/**
 * 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;
}
Beispiel #2
0
/**
 * 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;
}
Beispiel #4
0
/**
 * 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;
}