VirtualBox

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

Last change on this file since 31820 was 28800, checked in by vboxsync, 15 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

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