/** * The prober thread. * We don't want to mess with the priority of the calling thread. * * @remark This is pretty presumptive stuff, but if it works on Linux and * FreeBSD it does what I want. */ static void *rtSchedNativeProberThread(void *pvUser) { NOREF(pvUser); SAVEDPRIORITY SavedPriority; rtSchedNativeSave(&SavedPriority); /* * Check if we can get higher priority (typically only root can do this). * (Won't work right if our priority is -19 to start with, but what the heck.) * * We assume that the priority range is -19 to 19. Should probably find the right * define for this. */ int iStart = getpriority(PRIO_PROCESS, 0); int i = iStart; while (i-- > -20) if (setpriority(PRIO_PROCESS, 0, i)) break; g_iMaxPriority = getpriority(PRIO_PROCESS, 0); g_fCanRaisePriority = g_iMaxPriority < iStart; g_fCanRestorePriority = setpriority(PRIO_PROCESS, 0, iStart) == 0; /* * Check if we temporarily lower the thread priority. * Again, we assume we're not at the extreme end of the priority scale. */ iStart = getpriority(PRIO_PROCESS, 0); i = iStart; while (i++ < 19) if (setpriority(PRIO_PROCESS, 0, i)) break; g_iMinPriority = getpriority(PRIO_PROCESS, 0); if ( setpriority(PRIO_PROCESS, 0, iStart) || getpriority(PRIO_PROCESS, 0) != iStart) g_fCanRestorePriority = false; if (g_iMinPriority == g_iMaxPriority) g_fCanRestorePriority = g_fCanRaisePriority = false; /* * Check what happens to child threads when the parent lowers the * priority when it's being created. */ iStart = getpriority(PRIO_PROCESS, 0); g_fScrewedUpMaxPriorityLimitInheritance = true; if ( g_fCanRestorePriority && !setpriority(PRIO_PROCESS, 0, g_iMinPriority) && iStart != g_iMinPriority) { if (rtSchedRunThread(rtSchedNativeSubProberThread, (void *)(intptr_t)iStart) == 0) g_fScrewedUpMaxPriorityLimitInheritance = false; } /* done */ rtSchedNativeRestore(&SavedPriority); return (void *)VINF_SUCCESS; }
/** * Calculate the scheduling properties for all the threads in the default * process priority, assuming the current thread have the type enmType. * * @returns iprt status code. * @param enmType The thread type to be assumed for the current thread. */ DECLHIDDEN(int) rtSchedNativeCalcDefaultPriority(RTTHREADTYPE enmType) { Assert(enmType > RTTHREADTYPE_INVALID && enmType < RTTHREADTYPE_END); /* * First figure out what's we're allowed to do in this process. */ if (!g_fInitialized) { int iPriority = getpriority(PRIO_PROCESS, 0); #ifdef RLIMIT_RTPRIO /** @todo */ #endif int rc = rtSchedRunThread(rtSchedNativeProberThread, NULL); if (RT_FAILURE(rc)) return rc; Assert(getpriority(PRIO_PROCESS, 0) == iPriority); NOREF(iPriority); g_fInitialized = true; } /* * Select the right priority type table and update the default * process priority structure. */ if (g_fCanRaisePriority && g_fCanRestorePriority && !g_fScrewedUpMaxPriorityLimitInheritance) g_aDefaultPriority.paTypes = &g_aTypesLinuxFree[0]; else if (!g_fCanRaisePriority && g_fCanRestorePriority && !g_fScrewedUpMaxPriorityLimitInheritance) g_aDefaultPriority.paTypes = &g_aTypesLinuxRestricted[0]; else g_aDefaultPriority.paTypes = &g_aTypesLinuxFlat[0]; Assert(enmType == g_aDefaultPriority.paTypes[enmType].enmType); int iPriority = getpriority(PRIO_PROCESS, 0 /* current process */); g_aDefaultPriority.iNice = iPriority - g_aDefaultPriority.paTypes[enmType].iPriority; g_aDefaultPriority.iDelta = g_aDefaultPriority.iNice; rtSchedDumpPriority(); return VINF_SUCCESS; }
/** * Validates the ability to apply suggested priority scheme. * * The function checks that we're able to apply all the thread types in the * suggested priority scheme. * * @returns iprt status code. * @param pCfg The priority scheme to validate. * @param fHavePriorityProxy Set if we've got a priority proxy thread, * otherwise clear. */ static int rtSchedNativeCheckThreadTypes(const PROCPRIORITY *pCfg, bool fHavePriorityProxy) { int i = RTTHREADTYPE_END; while (--i > RTTHREADTYPE_INVALID) { VALIDATORPRIORITYPAIR PrioPair; PrioPair.iCurrent = g_pProcessPriority->paTypes[i].iPriority + g_pProcessPriority->iDelta; PrioPair.iNew = pCfg->paTypes[i].iPriority + pCfg->iDelta; if (g_acRTThreadTypeStats[i] == 0) PrioPair.iCurrent = INT_MAX; #ifdef RT_STRICT int const iPriority = getpriority(PRIO_PROCESS, 0); #endif int rc = rtSchedRunThread(rtSchedNativeValidatorThread, &PrioPair, fHavePriorityProxy /*fUsePriorityProxy*/); Assert(getpriority(PRIO_PROCESS, 0) == iPriority); if (RT_FAILURE(rc)) return rc; } return VINF_SUCCESS; }
/** * Validates and sets the process priority. * * This will check that all rtThreadNativeSetPriority() will success for all the * thread types when applied to the current thread. * * @returns iprt status code. * @param enmPriority The priority to validate and set. */ DECLHIDDEN(int) rtProcNativeSetPriority(RTPROCPRIORITY enmPriority) { Assert(enmPriority > RTPROCPRIORITY_INVALID && enmPriority < RTPROCPRIORITY_LAST); int rc = VINF_SUCCESS; if (enmPriority == RTPROCPRIORITY_DEFAULT) g_pProcessPriority = &g_aDefaultPriority; else { /* * Find a configuration which matches and can be applied. */ rc = VERR_FILE_NOT_FOUND; for (unsigned i = 0; i < RT_ELEMENTS(g_aUnixConfigs); i++) { if (g_aUnixConfigs[i].enmPriority == enmPriority) { int iPriority = getpriority(PRIO_PROCESS, 0); int rc3 = rtSchedRunThread(rtSchedNativeValidatorThread, (void *)&g_aUnixConfigs[i]); Assert(getpriority(PRIO_PROCESS, 0) == iPriority); NOREF(iPriority); if (RT_SUCCESS(rc3)) { g_pProcessPriority = &g_aUnixConfigs[i]; rc = VINF_SUCCESS; break; } if (rc == VERR_FILE_NOT_FOUND) rc = rc3; } } } #ifdef THREAD_LOGGING LogFlow(("rtProcNativeSetPriority: returns %Rrc enmPriority=%d\n", rc, enmPriority)); rtSchedDumpPriority(); #endif return rc; }