VirtualBox

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

Last change on this file since 403 was 403, checked in by vboxsync, 18 years ago

Need RTThreadWait in ring-0 too when using the generic timers, so thread.cpp was ported to ring-0. Fixed a bug in RTTimerStart() (the generic code). (hope this doesn't break the other platforms...)

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