VirtualBox

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

Last change on this file since 68033 was 61751, checked in by vboxsync, 9 years ago

fixed small memory leaks on certain hosts (Solaris) when using pthread_*attr functions

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