VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/posix/sched-posix.cpp@ 19167

Last change on this file since 19167 was 13837, checked in by vboxsync, 16 years ago

s/%Vr\([acfs]\)/%Rr\1/g - since I'm upsetting everyone anyway, better make the most of it...

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 30.2 KB
Line 
1/* $Id: sched-posix.cpp 13837 2008-11-05 02:54:02Z vboxsync $ */
2/** @file
3 * IPRT - Scheduling, POSIX.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 *
26 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31/*
32 * !WARNING!
33 *
34 * When talking about lowering and raising priority, we do *NOT* refer to
35 * the common direction priority values takes on unix systems (lower means
36 * higher). So, when we raise the priority of a linux thread the nice
37 * value will decrease, and when we lower the priority the nice value
38 * will increase. Confusing, right?
39 *
40 * !WARNING!
41 */
42
43
44
45/** @def THREAD_LOGGING
46 * Be very careful with enabling this, it may cause deadlocks when combined
47 * with the 'thread' logging prefix.
48 */
49#ifdef __DOXYGEN__
50#define THREAD_LOGGING
51#endif
52
53/*******************************************************************************
54* Header Files *
55*******************************************************************************/
56#define LOG_GROUP RTLOGGROUP_THREAD
57#include <errno.h>
58#include <pthread.h>
59#include <sched.h>
60#include <unistd.h>
61#include <sys/resource.h>
62
63#include <iprt/thread.h>
64#include <iprt/process.h>
65#include <iprt/semaphore.h>
66#include <iprt/string.h>
67#include <iprt/assert.h>
68#include <iprt/log.h>
69#include <iprt/err.h>
70#include "internal/sched.h"
71#include "internal/thread.h"
72
73
74/*******************************************************************************
75* Structures and Typedefs *
76*******************************************************************************/
77
78/** Array scheduler attributes corresponding to each of the thread types. */
79typedef struct PROCPRIORITYTYPE
80{
81 /** For sanity include the array index. */
82 RTTHREADTYPE enmType;
83 /** The thread priority or nice delta - depends on which priority type. */
84 int iPriority;
85} PROCPRIORITYTYPE;
86
87
88/**
89 * Configuration of one priority.
90 */
91typedef struct
92{
93 /** The priority. */
94 RTPROCPRIORITY enmPriority;
95 /** The name of this priority. */
96 const char *pszName;
97 /** The process nice value. */
98 int iNice;
99 /** The delta applied to the iPriority value. */
100 int iDelta;
101 /** Array scheduler attributes corresponding to each of the thread types. */
102 const PROCPRIORITYTYPE *paTypes;
103} PROCPRIORITY;
104
105
106/**
107 * Saved priority settings
108 */
109typedef struct
110{
111 /** Process priority. */
112 int iPriority;
113 /** Process level. */
114 struct sched_param SchedParam;
115 /** Process level. */
116 int iPolicy;
117 /** pthread level. */
118 struct sched_param PthreadSchedParam;
119 /** pthread level. */
120 int iPthreadPolicy;
121} SAVEDPRIORITY, *PSAVEDPRIORITY;
122
123
124/*******************************************************************************
125* Global Variables *
126*******************************************************************************/
127/**
128 * Thread level priorities based on a 0..31 priority range
129 * as specified as the minium for SCHED_RR/FIFO. FreeBSD
130 * seems to be using this (needs more research to be
131 * certain).
132 */
133static const PROCPRIORITYTYPE g_aTypesThread[RTTHREADTYPE_END] =
134{
135 { RTTHREADTYPE_INVALID, -999999999 },
136 { RTTHREADTYPE_INFREQUENT_POLLER, 5 },
137 { RTTHREADTYPE_MAIN_HEAVY_WORKER, 12 },
138 { RTTHREADTYPE_EMULATION, 14 },
139 { RTTHREADTYPE_DEFAULT, 15 },
140 { RTTHREADTYPE_GUI, 16 },
141 { RTTHREADTYPE_MAIN_WORKER, 18 },
142 { RTTHREADTYPE_VRDP_IO, 24 },
143 { RTTHREADTYPE_DEBUGGER, 28 },
144 { RTTHREADTYPE_MSG_PUMP, 29 },
145 { RTTHREADTYPE_IO, 30 },
146 { RTTHREADTYPE_TIMER, 31 }
147};
148
149static const PROCPRIORITYTYPE g_aTypesThreadFlat[RTTHREADTYPE_END] =
150{
151 { RTTHREADTYPE_INVALID, ~0 },
152 { RTTHREADTYPE_INFREQUENT_POLLER, 15 },
153 { RTTHREADTYPE_MAIN_HEAVY_WORKER, 15 },
154 { RTTHREADTYPE_EMULATION, 15 },
155 { RTTHREADTYPE_DEFAULT, 15 },
156 { RTTHREADTYPE_GUI, 15 },
157 { RTTHREADTYPE_MAIN_WORKER, 15 },
158 { RTTHREADTYPE_VRDP_IO, 15 },
159 { RTTHREADTYPE_DEBUGGER, 15 },
160 { RTTHREADTYPE_MSG_PUMP, 15 },
161 { RTTHREADTYPE_IO, 15 },
162 { RTTHREADTYPE_TIMER, 15 }
163};
164
165/**
166 * Process and thread level priority, full access at thread level.
167 */
168static const PROCPRIORITY g_aProcessAndThread[] =
169{
170 { RTPROCPRIORITY_FLAT, "Flat", 0, 0, g_aTypesThreadFlat },
171 { RTPROCPRIORITY_LOW, "Low", 9, 0, g_aTypesThread },
172 { RTPROCPRIORITY_LOW, "Low", 11, 0, g_aTypesThread },
173 { RTPROCPRIORITY_LOW, "Low", 15, 0, g_aTypesThread },
174 { RTPROCPRIORITY_LOW, "Low", 17, 0, g_aTypesThread },
175 { RTPROCPRIORITY_LOW, "Low", 19, 0, g_aTypesThread },
176 { RTPROCPRIORITY_LOW, "Low", 7, 0, g_aTypesThread },
177 { RTPROCPRIORITY_LOW, "Low", 5, 0, g_aTypesThread },
178 { RTPROCPRIORITY_LOW, "Low", 3, 0, g_aTypesThread },
179 { RTPROCPRIORITY_LOW, "Low", 1, 0, g_aTypesThread },
180 { RTPROCPRIORITY_NORMAL, "Normal", 0, 0, g_aTypesThread },
181 { RTPROCPRIORITY_NORMAL, "Normal", 0, 0, g_aTypesThreadFlat },
182 { RTPROCPRIORITY_HIGH, "High", -9, 0, g_aTypesThread },
183 { RTPROCPRIORITY_HIGH, "High", -7, 0, g_aTypesThread },
184 { RTPROCPRIORITY_HIGH, "High", -5, 0, g_aTypesThread },
185 { RTPROCPRIORITY_HIGH, "High", -3, 0, g_aTypesThread },
186 { RTPROCPRIORITY_HIGH, "High", -1, 0, g_aTypesThread },
187 { RTPROCPRIORITY_HIGH, "High", -9, 0, g_aTypesThreadFlat },
188 { RTPROCPRIORITY_HIGH, "High", -1, 0, g_aTypesThreadFlat }
189};
190
191/**
192 * Deltas for a process in which we are not restricted
193 * to only be lowering the priority.
194 */
195static const PROCPRIORITYTYPE g_aTypesUnixFree[RTTHREADTYPE_END] =
196{
197 { RTTHREADTYPE_INVALID, -999999999 },
198 { RTTHREADTYPE_INFREQUENT_POLLER, +3 },
199 { RTTHREADTYPE_MAIN_HEAVY_WORKER, +2 },
200 { RTTHREADTYPE_EMULATION, +1 },
201 { RTTHREADTYPE_DEFAULT, 0 },
202 { RTTHREADTYPE_GUI, 0 },
203 { RTTHREADTYPE_MAIN_WORKER, 0 },
204 { RTTHREADTYPE_VRDP_IO, -1 },
205 { RTTHREADTYPE_DEBUGGER, -1 },
206 { RTTHREADTYPE_MSG_PUMP, -2 },
207 { RTTHREADTYPE_IO, -3 },
208 { RTTHREADTYPE_TIMER, -4 }
209};
210
211/**
212 * Deltas for a process in which we are restricted
213 * to only be lowering the priority.
214 */
215static const PROCPRIORITYTYPE g_aTypesUnixRestricted[RTTHREADTYPE_END] =
216{
217 { RTTHREADTYPE_INVALID, -999999999 },
218 { RTTHREADTYPE_INFREQUENT_POLLER, +3 },
219 { RTTHREADTYPE_MAIN_HEAVY_WORKER, +2 },
220 { RTTHREADTYPE_EMULATION, +1 },
221 { RTTHREADTYPE_DEFAULT, 0 },
222 { RTTHREADTYPE_GUI, 0 },
223 { RTTHREADTYPE_MAIN_WORKER, 0 },
224 { RTTHREADTYPE_VRDP_IO, 0 },
225 { RTTHREADTYPE_DEBUGGER, 0 },
226 { RTTHREADTYPE_MSG_PUMP, 0 },
227 { RTTHREADTYPE_IO, 0 },
228 { RTTHREADTYPE_TIMER, 0 }
229};
230
231/**
232 * Deltas for a process in which we are restricted
233 * to only be lowering the priority.
234 */
235static const PROCPRIORITYTYPE g_aTypesUnixFlat[RTTHREADTYPE_END] =
236{
237 { RTTHREADTYPE_INVALID, -999999999 },
238 { RTTHREADTYPE_INFREQUENT_POLLER, 0 },
239 { RTTHREADTYPE_MAIN_HEAVY_WORKER, 0 },
240 { RTTHREADTYPE_EMULATION, 0 },
241 { RTTHREADTYPE_DEFAULT, 0 },
242 { RTTHREADTYPE_GUI, 0 },
243 { RTTHREADTYPE_MAIN_WORKER, 0 },
244 { RTTHREADTYPE_VRDP_IO, 0 },
245 { RTTHREADTYPE_DEBUGGER, 0 },
246 { RTTHREADTYPE_MSG_PUMP, 0 },
247 { RTTHREADTYPE_IO, 0 },
248 { RTTHREADTYPE_TIMER, 0 }
249};
250
251/**
252 * Process and thread level priority, full access at thread level.
253 */
254static const PROCPRIORITY g_aUnixConfigs[] =
255{
256 { RTPROCPRIORITY_FLAT, "Flat", 0, 0, g_aTypesUnixFlat },
257 { RTPROCPRIORITY_LOW, "Low", 9, 9, g_aTypesUnixFree },
258 { RTPROCPRIORITY_LOW, "Low", 9, 9, g_aTypesUnixFlat },
259 { RTPROCPRIORITY_LOW, "Low", 15, 15, g_aTypesUnixFree },
260 { RTPROCPRIORITY_LOW, "Low", 15, 15, g_aTypesUnixFlat },
261 { RTPROCPRIORITY_LOW, "Low", 17, 17, g_aTypesUnixFree },
262 { RTPROCPRIORITY_LOW, "Low", 17, 17, g_aTypesUnixFlat },
263 { RTPROCPRIORITY_LOW, "Low", 19, 19, g_aTypesUnixFlat },
264 { RTPROCPRIORITY_LOW, "Low", 9, 9, g_aTypesUnixRestricted },
265 { RTPROCPRIORITY_LOW, "Low", 15, 15, g_aTypesUnixRestricted },
266 { RTPROCPRIORITY_LOW, "Low", 17, 17, g_aTypesUnixRestricted },
267 { RTPROCPRIORITY_NORMAL, "Normal", 0, 0, g_aTypesUnixFree },
268 { RTPROCPRIORITY_NORMAL, "Normal", 0, 0, g_aTypesUnixRestricted },
269 { RTPROCPRIORITY_NORMAL, "Normal", 0, 0, g_aTypesUnixFlat },
270 { RTPROCPRIORITY_HIGH, "High", -9, -9, g_aTypesUnixFree },
271 { RTPROCPRIORITY_HIGH, "High", -7, -7, g_aTypesUnixFree },
272 { RTPROCPRIORITY_HIGH, "High", -5, -5, g_aTypesUnixFree },
273 { RTPROCPRIORITY_HIGH, "High", -3, -3, g_aTypesUnixFree },
274 { RTPROCPRIORITY_HIGH, "High", -1, -1, g_aTypesUnixFree },
275 { RTPROCPRIORITY_HIGH, "High", -9, -9, g_aTypesUnixRestricted },
276 { RTPROCPRIORITY_HIGH, "High", -7, -7, g_aTypesUnixRestricted },
277 { RTPROCPRIORITY_HIGH, "High", -5, -5, g_aTypesUnixRestricted },
278 { RTPROCPRIORITY_HIGH, "High", -3, -3, g_aTypesUnixRestricted },
279 { RTPROCPRIORITY_HIGH, "High", -1, -1, g_aTypesUnixRestricted },
280 { RTPROCPRIORITY_HIGH, "High", -9, -9, g_aTypesUnixFlat },
281 { RTPROCPRIORITY_HIGH, "High", -7, -7, g_aTypesUnixFlat },
282 { RTPROCPRIORITY_HIGH, "High", -5, -5, g_aTypesUnixFlat },
283 { RTPROCPRIORITY_HIGH, "High", -3, -3, g_aTypesUnixFlat },
284 { RTPROCPRIORITY_HIGH, "High", -1, -1, g_aTypesUnixFlat }
285};
286
287/**
288 * The dynamic default priority configuration.
289 *
290 * This will be recalulated at runtime depending on what the
291 * system allow us to do and what the current priority is.
292 */
293static PROCPRIORITY g_aDefaultPriority =
294{
295 RTPROCPRIORITY_LOW, "Default", 0, 0, g_aTypesUnixRestricted
296};
297
298/** Pointer to the current priority configuration. */
299static const PROCPRIORITY *g_pProcessPriority = &g_aDefaultPriority;
300
301
302/** Set to what kind of scheduling priority support the host
303 * OS seems to be offering. Determined at runtime.
304 */
305static enum
306{
307 OSPRIOSUP_UNDETERMINED = 0,
308 /** An excellent combination of process and thread level
309 * I.e. setpriority() works on process level, one have to be supervisor
310 * to raise priority as is the custom in unix. While pthread_setschedparam()
311 * works on thread level and we can raise the priority just like we want.
312 *
313 * I think this is what FreeBSD offers. (It is certainly analogous to what
314 * NT offers if you wondered.) Linux on the other hand doesn't provide this
315 * for processes with SCHED_OTHER policy, and I'm not sure if we want to
316 * play around with using the real-time SCHED_RR and SCHED_FIFO which would
317 * require special privilegdes anyway.
318 */
319 OSPRIOSUP_PROCESS_AND_THREAD_LEVEL,
320 /** A rough thread level priority only.
321 * setpriority() is the only real game in town, and it works on thread level.
322 */
323 OSPRIOSUP_THREAD_LEVEL
324} volatile g_enmOsPrioSup = OSPRIOSUP_UNDETERMINED;
325
326/** Set if we figure we have nice capability, meaning we can use setpriority
327 * to raise the priority. */
328bool g_fCanNice = false;
329
330
331/*******************************************************************************
332* Internal Functions *
333*******************************************************************************/
334
335
336/**
337 * Saves all the scheduling attributes we can think of.
338 */
339static void rtSchedNativeSave(PSAVEDPRIORITY pSave)
340{
341 memset(pSave, 0xff, sizeof(*pSave));
342
343 errno = 0;
344 pSave->iPriority = getpriority(PRIO_PROCESS, 0 /* current process */);
345 Assert(errno == 0);
346
347 errno = 0;
348 sched_getparam(0 /* current process */, &pSave->SchedParam);
349 Assert(errno == 0);
350
351 errno = 0;
352 pSave->iPolicy = sched_getscheduler(0 /* current process */);
353 Assert(errno == 0);
354
355 int rc = pthread_getschedparam(pthread_self(), &pSave->iPthreadPolicy, &pSave->PthreadSchedParam);
356 Assert(rc == 0); NOREF(rc);
357}
358
359
360/**
361 * Restores scheduling attributes.
362 * Most of this won't work right, but anyway...
363 */
364static void rtSchedNativeRestore(PSAVEDPRIORITY pSave)
365{
366 setpriority(PRIO_PROCESS, 0, pSave->iPriority);
367 sched_setscheduler(0, pSave->iPolicy, &pSave->SchedParam);
368 sched_setparam(0, &pSave->SchedParam);
369 pthread_setschedparam(pthread_self(), pSave->iPthreadPolicy, &pSave->PthreadSchedParam);
370}
371
372
373/**
374 * Starts a worker thread and wait for it to complete.
375 * We cannot use RTThreadCreate since we're already owner of the RW lock.
376 */
377static int rtSchedCreateThread(void *(*pfnThread)(void *pvArg), void *pvArg)
378{
379 /*
380 * Setup thread attributes.
381 */
382 pthread_attr_t ThreadAttr;
383 int rc = pthread_attr_init(&ThreadAttr);
384 if (!rc)
385 {
386 rc = pthread_attr_setdetachstate(&ThreadAttr, PTHREAD_CREATE_JOINABLE);
387 if (!rc)
388 {
389 rc = pthread_attr_setstacksize(&ThreadAttr, 128*1024);
390 if (!rc)
391 {
392 /*
393 * Create the thread.
394 */
395 pthread_t Thread;
396 rc = pthread_create(&Thread, &ThreadAttr, pfnThread, pvArg);
397 if (!rc)
398 {
399 /*
400 * Wait for the thread to finish.
401 */
402 void *pvRet = (void *)-1;
403 do
404 {
405 rc = pthread_join(Thread, &pvRet);
406 } while (errno == EINTR);
407 if (rc)
408 return RTErrConvertFromErrno(rc);
409 return (int)(uintptr_t)pvRet;
410 }
411 }
412 }
413 pthread_attr_destroy(&ThreadAttr);
414 }
415 return RTErrConvertFromErrno(rc);
416}
417
418
419static void rtSchedDumpPriority(void)
420{
421#ifdef THREAD_LOGGING
422 Log(("Priority: g_fCanNice=%d g_enmOsPrioSup=%d\n", g_fCanNice, g_enmOsPrioSup));
423 Log(("Priority: enmPriority=%d \"%s\" iNice=%d iDelta=%d\n",
424 g_pProcessPriority->enmPriority,
425 g_pProcessPriority->pszName,
426 g_pProcessPriority->iNice,
427 g_pProcessPriority->iDelta));
428 Log(("Priority: %2d INFREQUENT_POLLER = %d\n", RTTHREADTYPE_INFREQUENT_POLLER, g_pProcessPriority->paTypes[RTTHREADTYPE_INFREQUENT_POLLER].iPriority));
429 Log(("Priority: %2d MAIN_HEAVY_WORKER = %d\n", RTTHREADTYPE_MAIN_HEAVY_WORKER, g_pProcessPriority->paTypes[RTTHREADTYPE_MAIN_HEAVY_WORKER].iPriority));
430 Log(("Priority: %2d EMULATION = %d\n", RTTHREADTYPE_EMULATION , g_pProcessPriority->paTypes[RTTHREADTYPE_EMULATION ].iPriority));
431 Log(("Priority: %2d DEFAULT = %d\n", RTTHREADTYPE_DEFAULT , g_pProcessPriority->paTypes[RTTHREADTYPE_DEFAULT ].iPriority));
432 Log(("Priority: %2d GUI = %d\n", RTTHREADTYPE_GUI , g_pProcessPriority->paTypes[RTTHREADTYPE_GUI ].iPriority));
433 Log(("Priority: %2d MAIN_WORKER = %d\n", RTTHREADTYPE_MAIN_WORKER , g_pProcessPriority->paTypes[RTTHREADTYPE_MAIN_WORKER ].iPriority));
434 Log(("Priority: %2d VRDP_IO = %d\n", RTTHREADTYPE_VRDP_IO , g_pProcessPriority->paTypes[RTTHREADTYPE_VRDP_IO ].iPriority));
435 Log(("Priority: %2d DEBUGGER = %d\n", RTTHREADTYPE_DEBUGGER , g_pProcessPriority->paTypes[RTTHREADTYPE_DEBUGGER ].iPriority));
436 Log(("Priority: %2d MSG_PUMP = %d\n", RTTHREADTYPE_MSG_PUMP , g_pProcessPriority->paTypes[RTTHREADTYPE_MSG_PUMP ].iPriority));
437 Log(("Priority: %2d IO = %d\n", RTTHREADTYPE_IO , g_pProcessPriority->paTypes[RTTHREADTYPE_IO ].iPriority));
438 Log(("Priority: %2d TIMER = %d\n", RTTHREADTYPE_TIMER , g_pProcessPriority->paTypes[RTTHREADTYPE_TIMER ].iPriority));
439#endif
440}
441
442
443/**
444 * The prober thread.
445 * We don't want to mess with the priority of the calling thread.
446 *
447 * @remark This is pretty presumptive stuff, but if it works on Linux and
448 * FreeBSD it does what I want.
449 */
450static void *rtSchedNativeProberThread(void *pvUser)
451{
452 SAVEDPRIORITY SavedPriority;
453 rtSchedNativeSave(&SavedPriority);
454
455 /*
456 * Let's first try and see what we get on a thread level.
457 */
458 int iMax = sched_get_priority_max(SavedPriority.iPthreadPolicy);
459 int iMin = sched_get_priority_min(SavedPriority.iPthreadPolicy);
460 if (iMax - iMin >= 32)
461 {
462 pthread_t Self = pthread_self();
463 int i = iMin;
464 while (i <= iMax)
465 {
466 struct sched_param SchedParam = SavedPriority.PthreadSchedParam;
467 SchedParam.sched_priority = i;
468 if (pthread_setschedparam(Self, SavedPriority.iPthreadPolicy, &SchedParam))
469 break;
470 i++;
471 }
472 if (i == iMax)
473 g_enmOsPrioSup = OSPRIOSUP_PROCESS_AND_THREAD_LEVEL;
474 }
475
476 /*
477 * Ok, we didn't have the good stuff, so let's fall back on the unix stuff.
478 */
479 if (g_enmOsPrioSup == OSPRIOSUP_UNDETERMINED)
480 g_enmOsPrioSup = OSPRIOSUP_THREAD_LEVEL;
481
482 /*
483 * Check if we can get higher priority (typically only root can do this).
484 * (Won't work right if our priority is -19 to start with, but what the heck.)
485 *
486 * We assume that the unix priority is -19 to 19. I know there are defines
487 * for this, but I don't remember which and if I'm awake enough to make sense
488 * of them from any SuS spec.
489 */
490 int iStart = getpriority(PRIO_PROCESS, 0);
491 int i = iStart;
492 while (i-- > -19)
493 {
494 if (setpriority(PRIO_PROCESS, 0, i))
495 break;
496 }
497 if (getpriority(PRIO_PROCESS, 0) != iStart)
498 g_fCanNice = true;
499 else
500 g_fCanNice = false;
501
502 /* done */
503 rtSchedNativeRestore(&SavedPriority);
504 return (void *)VINF_SUCCESS;
505}
506
507
508/**
509 * Calculate the scheduling properties for all the threads in the default
510 * process priority, assuming the current thread have the type enmType.
511 *
512 * @returns iprt status code.
513 * @param enmType The thread type to be assumed for the current thread.
514 */
515int rtSchedNativeCalcDefaultPriority(RTTHREADTYPE enmType)
516{
517 Assert(enmType > RTTHREADTYPE_INVALID && enmType < RTTHREADTYPE_END);
518
519 /*
520 * First figure out what's supported by the OS.
521 */
522 if (g_enmOsPrioSup == OSPRIOSUP_UNDETERMINED)
523 {
524 int iPriority = getpriority(PRIO_PROCESS, 0);
525 int rc = rtSchedCreateThread(rtSchedNativeProberThread, NULL);
526 if (RT_FAILURE(rc))
527 return rc;
528 if (g_enmOsPrioSup == OSPRIOSUP_UNDETERMINED)
529 g_enmOsPrioSup = OSPRIOSUP_THREAD_LEVEL;
530 Assert(getpriority(PRIO_PROCESS, 0) == iPriority); NOREF(iPriority);
531 }
532
533 /*
534 * Now let's see what we can do...
535 */
536 int iPriority = getpriority(PRIO_PROCESS, 0);
537 switch (g_enmOsPrioSup)
538 {
539 case OSPRIOSUP_PROCESS_AND_THREAD_LEVEL:
540 {
541 g_aDefaultPriority.iNice = iPriority;
542 g_aDefaultPriority.iDelta = 0;
543 g_aDefaultPriority.paTypes = g_aTypesThread;
544 Assert(enmType == g_aDefaultPriority.paTypes[enmType].enmType);
545 break;
546 }
547
548 case OSPRIOSUP_THREAD_LEVEL:
549 {
550 if (g_fCanNice)
551 g_aDefaultPriority.paTypes = g_aTypesUnixFree;
552 else
553 g_aDefaultPriority.paTypes = g_aTypesUnixRestricted;
554 Assert(enmType == g_aDefaultPriority.paTypes[enmType].enmType);
555 g_aDefaultPriority.iNice = iPriority - g_aDefaultPriority.paTypes[enmType].iPriority;
556 g_aDefaultPriority.iDelta = g_aDefaultPriority.iNice;
557 break;
558 }
559
560 default:
561 AssertFailed();
562 break;
563 }
564 rtSchedDumpPriority();
565 return VINF_SUCCESS;
566}
567
568
569/**
570 * The validator thread.
571 * We don't want to mess with the priority of the calling thread.
572 *
573 * @remark This is pretty presumptive stuff, but if it works on Linux and
574 * FreeBSD it does what I want.
575 */
576static void *rtSchedNativeValidatorThread(void *pvUser)
577{
578 const PROCPRIORITY *pCfg = (const PROCPRIORITY *)pvUser;
579 SAVEDPRIORITY SavedPriority;
580 rtSchedNativeSave(&SavedPriority);
581
582 int rc = VINF_SUCCESS;
583 switch (g_enmOsPrioSup)
584 {
585 /*
586 * Try set the specified process priority and then try
587 * out all the thread priorities which are used.
588 */
589 case OSPRIOSUP_PROCESS_AND_THREAD_LEVEL:
590 {
591 if (!setpriority(PRIO_PROCESS, 0, pCfg->iNice))
592 {
593 int iMin = sched_get_priority_min(SavedPriority.iPolicy);
594 pthread_t Self = pthread_self();
595 for (int i = RTTHREADTYPE_INVALID + 1; i < RTTHREADTYPE_END; i++)
596 {
597 struct sched_param SchedParam = SavedPriority.PthreadSchedParam;
598 SchedParam.sched_priority = pCfg->paTypes[i].iPriority
599 + pCfg->iDelta + iMin;
600 rc = pthread_setschedparam(Self, SavedPriority.iPthreadPolicy, &SchedParam);
601 if (rc)
602 {
603 rc = RTErrConvertFromErrno(rc);
604 break;
605 }
606 }
607 }
608 else
609 rc = RTErrConvertFromErrno(errno);
610 break;
611 }
612
613 /*
614 * Try out the priorities from the top and down.
615 */
616 case OSPRIOSUP_THREAD_LEVEL:
617 {
618 int i = RTTHREADTYPE_END;
619 while (--i > RTTHREADTYPE_INVALID)
620 {
621 int iPriority = pCfg->paTypes[i].iPriority + pCfg->iDelta;
622 if (setpriority(PRIO_PROCESS, 0, iPriority))
623 {
624 rc = RTErrConvertFromErrno(errno);
625 break;
626 }
627 }
628 break;
629 }
630
631 default:
632 AssertFailed();
633 break;
634 }
635
636 /* done */
637 rtSchedNativeRestore(&SavedPriority);
638 return (void *)rc;
639}
640
641
642/**
643 * Validates and sets the process priority.
644 * This will check that all rtThreadNativeSetPriority() will success for all the
645 * thread types when applied to the current thread.
646 *
647 * @returns iprt status code.
648 * @param enmPriority The priority to validate and set.
649 */
650int rtProcNativeSetPriority(RTPROCPRIORITY enmPriority)
651{
652 Assert(enmPriority > RTPROCPRIORITY_INVALID && enmPriority < RTPROCPRIORITY_LAST);
653
654 int rc = VINF_SUCCESS;
655 if (enmPriority == RTPROCPRIORITY_DEFAULT)
656 g_pProcessPriority = &g_aDefaultPriority;
657 else
658 {
659 /*
660 * Select the array to search.
661 */
662 const PROCPRIORITY *pa;
663 unsigned c;
664 switch (g_enmOsPrioSup)
665 {
666 case OSPRIOSUP_PROCESS_AND_THREAD_LEVEL:
667 pa = g_aProcessAndThread;
668 c = RT_ELEMENTS(g_aProcessAndThread);
669 break;
670 case OSPRIOSUP_THREAD_LEVEL:
671 pa = g_aUnixConfigs;
672 c = RT_ELEMENTS(g_aUnixConfigs);
673 break;
674 default:
675 pa = NULL;
676 c = 0;
677 break;
678 }
679
680 /*
681 * Search the array.
682 */
683 rc = VERR_FILE_NOT_FOUND;
684 unsigned i;
685 for (i = 0; i < c; i++)
686 {
687 if (pa[i].enmPriority == enmPriority)
688 {
689 /*
690 * Validate it.
691 */
692 int iPriority = getpriority(PRIO_PROCESS, 0);
693 int rc3 = rtSchedCreateThread(rtSchedNativeValidatorThread, (void *)&pa[i]);
694 Assert(getpriority(PRIO_PROCESS, 0) == iPriority); NOREF(iPriority);
695 if (RT_SUCCESS(rc))
696 rc = rc3;
697 if (RT_SUCCESS(rc))
698 break;
699 }
700 }
701
702 /*
703 * Did we get lucky?
704 * If so update process priority and globals.
705 */
706 if (RT_SUCCESS(rc))
707 {
708 switch (g_enmOsPrioSup)
709 {
710 case OSPRIOSUP_PROCESS_AND_THREAD_LEVEL:
711 if (setpriority(PRIO_PROCESS, 0, pa[i].iNice))
712 {
713 rc = RTErrConvertFromErrno(errno);
714 AssertMsgFailed(("setpriority(,,%d) -> errno=%d rc=%Rrc\n", pa[i].iNice, errno, rc));
715 }
716 break;
717
718 default:
719 break;
720 }
721
722 if (RT_SUCCESS(rc))
723 g_pProcessPriority = &pa[i];
724 }
725 }
726
727#ifdef THREAD_LOGGING
728 LogFlow(("rtProcNativeSetPriority: returns %Rrc enmPriority=%d\n", rc, enmPriority));
729 rtSchedDumpPriority();
730#endif
731 return rc;
732}
733
734
735/**
736 * Sets the priority of the thread according to the thread type
737 * and current process priority.
738 *
739 * The RTTHREADINT::enmType member has not yet been updated and will be updated by
740 * the caller on a successful return.
741 *
742 * @returns iprt status code.
743 * @param Thread The thread in question.
744 * @param enmType The thread type.
745 */
746int rtThreadNativeSetPriority(PRTTHREADINT pThread, RTTHREADTYPE enmType)
747{
748 Assert(enmType > RTTHREADTYPE_INVALID && enmType < RTTHREADTYPE_END);
749 Assert(enmType == g_pProcessPriority->paTypes[enmType].enmType);
750 Assert((pthread_t)pThread->Core.Key == pthread_self());
751
752 int rc = VINF_SUCCESS;
753 switch (g_enmOsPrioSup)
754 {
755 case OSPRIOSUP_PROCESS_AND_THREAD_LEVEL:
756 {
757 struct sched_param SchedParam = {-9999999};
758 int iPolicy = -7777777;
759 pthread_t Self = pthread_self();
760 rc = pthread_getschedparam(Self, &iPolicy, &SchedParam);
761 if (!rc)
762 {
763 SchedParam.sched_priority = g_pProcessPriority->paTypes[enmType].iPriority
764 + g_pProcessPriority->iDelta
765 + sched_get_priority_min(iPolicy);
766 rc = pthread_setschedparam(Self, iPolicy, &SchedParam);
767 if (!rc)
768 {
769#ifdef THREAD_LOGGING
770 Log(("rtThreadNativeSetPriority: Thread=%p enmType=%d iPolicy=%d sched_priority=%d pid=%d\n",
771 pThread->Core.Key, enmType, iPolicy, SchedParam.sched_priority, getpid()));
772#endif
773 break;
774 }
775 }
776
777 int rcNative = rc;
778 rc = RTErrConvertFromErrno(rc);
779 AssertMsgFailed(("pthread_[gs]etschedparam(%p, %d, {%d}) -> rcNative=%d rc=%Rrc\n",
780 (void *)Self, iPolicy, SchedParam.sched_priority, rcNative, rc)); NOREF(rcNative);
781 break;
782 }
783
784 case OSPRIOSUP_THREAD_LEVEL:
785 {
786 int iPriority = g_pProcessPriority->paTypes[enmType].iPriority + g_pProcessPriority->iDelta;
787 if (!setpriority(PRIO_PROCESS, 0, iPriority))
788 {
789 AssertMsg(iPriority == getpriority(PRIO_PROCESS, 0), ("iPriority=%d getpriority()=%d\n", iPriority, getpriority(PRIO_PROCESS, 0)));
790#ifdef THREAD_LOGGING
791 Log(("rtThreadNativeSetPriority: Thread=%p enmType=%d iPriority=%d pid=%d\n", pThread->Core.Key, enmType, iPriority, getpid()));
792#endif
793 }
794 else
795 {
796#if 0
797 rc = RTErrConvertFromErrno(errno);
798 AssertMsgFailed(("setpriority(,, %d) -> errno=%d rc=%Rrc\n", iPriority, errno, rc));
799#else
800 /** @todo
801 * Just keep quiet about failures now - we'll fail here because we're not
802 * allowed to raise our own priority. This is a problem when starting the
803 * threads with higher priority from EMT (i.e. most threads it starts).
804 * This is apparently inherited from the parent in some cases and not
805 * in other cases. I guess this would come down to which kind of pthread
806 * implementation is actually in use, and how many sensible patches which
807 * are installed.
808 * I need to find a system where this problem shows up in order to come up
809 * with a proper fix. There's an pthread_create attribute for not inherting
810 * scheduler stuff I think...
811 */
812 rc = VINF_SUCCESS;
813#endif
814 }
815 break;
816 }
817
818 /*
819 * Any thread created before we determin the default config, remains unchanged!
820 * The prober thread above is one of those.
821 */
822 default:
823 break;
824 }
825
826 return rc;
827}
828
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette