VirtualBox

Changeset 77910 in vbox for trunk/src/VBox/Runtime/r3


Ignore:
Timestamp:
Mar 27, 2019 11:33:01 AM (6 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
129623
Message:

Main: bugref:7929: Added ability to change the priority of the VM process

Location:
trunk/src/VBox/Runtime/r3
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/r3/darwin/sched-darwin.cpp

    r76553 r77910  
    9999{
    100100    {
     101        RTPROCPRIORITY_DEFAULT, "Default",
     102        {
     103            { RTTHREADTYPE_INVALID,                 INT_MIN, INT_MIN },
     104            { RTTHREADTYPE_INFREQUENT_POLLER,       29, 29 },
     105            { RTTHREADTYPE_MAIN_HEAVY_WORKER,       30, 30 },
     106            { RTTHREADTYPE_EMULATION,               31, 31 }, /* the default priority */
     107            { RTTHREADTYPE_DEFAULT,                 32, 32 },
     108            { RTTHREADTYPE_GUI,                     32, 32 },
     109            { RTTHREADTYPE_MAIN_WORKER,             32, 32 },
     110            { RTTHREADTYPE_VRDP_IO,                 39, 39 },
     111            { RTTHREADTYPE_DEBUGGER,                42, 42 },
     112            { RTTHREADTYPE_MSG_PUMP,                47, 47 },
     113            { RTTHREADTYPE_IO,                      52, 52 },
     114            { RTTHREADTYPE_TIMER,                   55, 55 }
     115        }
     116    },
     117    {
    101118        RTPROCPRIORITY_LOW, "Low",
    102119        {
     
    207224 *
    208225 * @returns The base priority
    209  */
    210 static int rtSchedDarwinGetBasePriority(void)
     226 * @param   pThread     The thread to get it for.  NULL for current.
     227 */
     228static int rtSchedDarwinGetBasePriority(PRTTHREADINT pThread)
    211229{
    212230    /* the base_priority. */
    213     mach_msg_type_number_t              Count = POLICY_TIMESHARE_INFO_COUNT;
    214     struct policy_timeshare_info        TSInfo = {0,0,0,0,0};
    215     kern_return_t                       krc;
    216     krc = thread_info(mach_thread_self(), THREAD_SCHED_TIMESHARE_INFO, (thread_info_t)&TSInfo, &Count);
     231    mach_msg_type_number_t       Count = POLICY_TIMESHARE_INFO_COUNT;
     232    struct policy_timeshare_info TSInfo = {0,0,0,0,0};
     233    kern_return_t krc = thread_info(!pThread ? mach_thread_self() : pthread_mach_thread_np((pthread_t)pThread->Core.Key),
     234                                    THREAD_SCHED_TIMESHARE_INFO, (thread_info_t)&TSInfo, &Count);
    217235    Assert(krc == KERN_SUCCESS);
    218236
     
    228246     * Get the current priority.
    229247     */
    230     int iBasePriority = rtSchedDarwinGetBasePriority();
     248    int iBasePriority = rtSchedDarwinGetBasePriority(NULL);
    231249    Assert(iBasePriority >= 0 && iBasePriority <= 63);
    232250
     
    277295DECLHIDDEN(int) rtThreadNativeSetPriority(PRTTHREADINT pThread, RTTHREADTYPE enmType)
    278296{
    279     Assert(pThread->Core.Key == pthread_self());
    280297    Assert(enmType > RTTHREADTYPE_INVALID && enmType < RTTHREADTYPE_END);
    281298    AssertMsg(g_pProcessPriority && g_pProcessPriority->aTypes[enmType].enmType == enmType,
     
    305322        {
    306323            int i = 0;
    307             int iBasePriority = rtSchedDarwinGetBasePriority();
    308 
    309             while (!err && iBasePriority < iDesiredBasePriority && i++ < 256)
     324            int iBasePriority = rtSchedDarwinGetBasePriority(pThread);
     325
     326            while (   !err
     327                   && iBasePriority < iDesiredBasePriority
     328                   && i++ < 256)
    310329            {
    311330                SchedParam.sched_priority = ++iPriority;
    312331                err = pthread_setschedparam((pthread_t)pThread->Core.Key, iSchedPolicy, &SchedParam);
    313                 iBasePriority = rtSchedDarwinGetBasePriority();
     332                iBasePriority = rtSchedDarwinGetBasePriority(pThread);
    314333            }
    315334
    316             while (!err && iBasePriority > iDesiredBasePriority && i++ < 256)
     335            while (   !err
     336                   && iPriority > 0
     337                   && iBasePriority > iDesiredBasePriority
     338                   && i++ < 256)
    317339            {
    318340                SchedParam.sched_priority = --iPriority;
    319341                err = pthread_setschedparam((pthread_t)pThread->Core.Key, iSchedPolicy, &SchedParam);
    320                 iBasePriority = rtSchedDarwinGetBasePriority();
     342                iBasePriority = rtSchedDarwinGetBasePriority(pThread);
    321343            }
     344
     345            return VINF_SUCCESS;
    322346        }
    323347    }
  • trunk/src/VBox/Runtime/r3/linux/sched-linux.cpp

    r76553 r77910  
    120120    int                 iPthreadPolicy;
    121121} SAVEDPRIORITY, *PSAVEDPRIORITY;
     122
     123
     124/**
     125 * Priorities for checking by separate thread
     126 * @internal
     127 */
     128typedef struct
     129{
     130    /** The current thread priority to assume first. */
     131    int                 iCurrent;
     132    /** The thread priority to try set afterwards. */
     133    int                 iNew;
     134} VALIDATORPRIORITYPAIR, *PVALIDATORPRIORITYPAIR;
    122135
    123136
     
    306319
    307320/**
     321 * Called on the priority proxy thread if requested running, otherwise
     322 * rtSchedRunThread() calls it directly.
     323 */
     324static DECLCALLBACK(int) rtSchedRunThreadCallback(pthread_t *pThread, void *(*pfnThread)(void *pvArg), void *pvArg)
     325{
     326    int rc = pthread_create(pThread, NULL, pfnThread, pvArg);
     327    if (!rc)
     328        return VINF_SUCCESS;
     329    return RTErrConvertFromErrno(rc);
     330}
     331
     332
     333/**
    308334 * Starts a worker thread and wait for it to complete.
     335 *
    309336 * We cannot use RTThreadCreate since we're already owner of the RW lock.
    310337 */
    311 static int rtSchedRunThread(void *(*pfnThread)(void *pvArg), void *pvArg)
     338static int rtSchedRunThread(void *(*pfnThread)(void *pvArg), void *pvArg, bool fUsePriorityProxy)
    312339{
    313340    /*
     
    315342     */
    316343    pthread_t Thread;
    317     int rc = pthread_create(&Thread, NULL, pfnThread, pvArg);
    318     if (!rc)
     344    int rc;
     345#ifndef RTTHREAD_POSIX_WITH_CREATE_PRIORITY_PROXY
     346    RT_NOREF(fUsePriorityProxy);
     347#else
     348    if (   fUsePriorityProxy
     349        && rtThreadPosixPriorityProxyStart())
     350        rc = rtThreadPosixPriorityProxyCall(NULL, (PFNRT)rtSchedRunThreadCallback, 3, &Thread, pfnThread, pvArg);
     351    else
     352#endif
     353        rc = rtSchedRunThreadCallback(&Thread, pfnThread, pvArg);
     354    if (RT_SUCCESS(rc))
    319355    {
    320356        /*
     
    330366        return (int)(uintptr_t)pvRet;
    331367    }
    332     return RTErrConvertFromErrno(rc);
     368    return rc;
    333369}
    334370
     
    435471        &&  iStart != g_iMinPriority)
    436472    {
    437         if (rtSchedRunThread(rtSchedNativeSubProberThread, (void *)(intptr_t)iStart) == 0)
     473        if (rtSchedRunThread(rtSchedNativeSubProberThread, (void *)(intptr_t)iStart, false /*fUsePriorityProxy*/) == 0)
    438474            g_fScrewedUpMaxPriorityLimitInheritance = false;
    439475    }
     
    465501        /** @todo */
    466502#endif
    467         int rc = rtSchedRunThread(rtSchedNativeProberThread, NULL);
     503        int rc = rtSchedRunThread(rtSchedNativeProberThread, NULL, false /*fUsePriorityProxy*/);
    468504        if (RT_FAILURE(rc))
    469505            return rc;
     
    499535static void *rtSchedNativeValidatorThread(void *pvUser)
    500536{
    501     const PROCPRIORITY *pCfg = (const PROCPRIORITY *)pvUser;
     537    PVALIDATORPRIORITYPAIR pPrioPair = (PVALIDATORPRIORITYPAIR)pvUser;
    502538    SAVEDPRIORITY SavedPriority;
    503539    rtSchedNativeSave(&SavedPriority);
    504540
    505     /*
    506      * Try out the priorities from the top and down.
    507      */
    508541    int rc = VINF_SUCCESS;
     542
     543    /*
     544     * Set the priority to the current value for specified thread type
     545     */
     546    if (setpriority(PRIO_PROCESS, 0, pPrioPair->iCurrent))
     547        rc = RTErrConvertFromErrno(errno);
     548
     549    /*
     550     * Try set the new priority.
     551     */
     552    if (RT_SUCCESS(rc) && setpriority(PRIO_PROCESS, 0, pPrioPair->iNew))
     553        rc = RTErrConvertFromErrno(errno);
     554
     555    /* done */
     556    rtSchedNativeRestore(&SavedPriority);
     557    return (void *)(intptr_t)rc;
     558}
     559
     560
     561/**
     562 * Validates the ability to apply suggested priority scheme.
     563 *
     564 * The function checks that we're able to apply all the thread types in the
     565 * suggested priority scheme.
     566 *
     567 * @returns iprt status code.
     568 * @param   pCfg                The priority scheme to validate.
     569 * @param   fHavePriorityProxy  Set if we've got a priority proxy thread,
     570 *                              otherwise clear.
     571 */
     572static int rtSchedNativeCheckThreadTypes(const PROCPRIORITY *pCfg, bool fHavePriorityProxy)
     573{
     574    /** @todo Only check transitions of thread types that actually are in use.
     575     * For the others, just check we can create threads with the new priority
     576     * scheme (ignoring the old). Best done by having an array of
     577     * per-threadtype counters in common/misc/thread.cpp. */
    509578    int i = RTTHREADTYPE_END;
    510579    while (--i > RTTHREADTYPE_INVALID)
    511580    {
    512         int iPriority = pCfg->paTypes[i].iPriority + pCfg->iDelta;
    513         if (setpriority(PRIO_PROCESS, 0, iPriority))
    514         {
    515             rc = RTErrConvertFromErrno(errno);
    516             break;
    517         }
     581        VALIDATORPRIORITYPAIR PrioPair;
     582        PrioPair.iCurrent = g_pProcessPriority->paTypes[i].iPriority + g_pProcessPriority->iDelta;
     583        PrioPair.iNew     = pCfg->paTypes[i].iPriority               + pCfg->iDelta;
     584
     585#ifdef RT_STRICT
     586        int const iPriority = getpriority(PRIO_PROCESS, 0);
     587#endif
     588        int rc = rtSchedRunThread(rtSchedNativeValidatorThread, &PrioPair, fHavePriorityProxy /*fUsePriorityProxy*/);
     589        Assert(getpriority(PRIO_PROCESS, 0) == iPriority);
     590
     591        if (RT_FAILURE(rc))
     592            return rc;
    518593    }
    519 
    520     /* done */
    521     rtSchedNativeRestore(&SavedPriority);
    522     return (void *)(intptr_t)rc;
     594    return VINF_SUCCESS;
    523595}
    524596
     
    537609    Assert(enmPriority > RTPROCPRIORITY_INVALID && enmPriority < RTPROCPRIORITY_LAST);
    538610
    539     int rc = VINF_SUCCESS;
     611#ifdef RTTHREAD_POSIX_WITH_CREATE_PRIORITY_PROXY
     612    /*
     613     * Make sure the proxy creation thread is started so we don't 'lose' our
     614     * initial priority if it's lowered.
     615     */
     616    bool const fHavePriorityProxy = rtThreadPosixPriorityProxyStart();
     617#else
     618    bool const fHavePriorityProxy = false;
     619#endif
     620
     621    int rc;
    540622    if (enmPriority == RTPROCPRIORITY_DEFAULT)
    541         g_pProcessPriority = &g_aDefaultPriority;
     623    {
     624        /*
     625         * If we've lowered priority since the process started, it may be impossible
     626         * to raise it again for existing thread (new threads will work fine).
     627         */
     628        rc = SchedNativeCheckThreadTypes(&g_aDefaultPriority);
     629        if (RT_SUCCESS(rc))
     630            g_pProcessPriority = &g_aDefaultPriority;
     631    }
    542632    else
    543633    {
     
    545635         * Find a configuration which matches and can be applied.
    546636         */
    547         rc = VERR_FILE_NOT_FOUND;
     637        rc = VERR_NOT_FOUND;
    548638        for (unsigned i = 0; i < RT_ELEMENTS(g_aUnixConfigs); i++)
    549         {
    550639            if (g_aUnixConfigs[i].enmPriority == enmPriority)
    551640            {
    552                 int iPriority = getpriority(PRIO_PROCESS, 0);
    553                 int rc3 = rtSchedRunThread(rtSchedNativeValidatorThread, (void *)&g_aUnixConfigs[i]);
    554                 Assert(getpriority(PRIO_PROCESS, 0) == iPriority); NOREF(iPriority);
    555                 if (RT_SUCCESS(rc3))
     641                int rc2 = rtSchedNativeCheckThreadTypes(&g_aUnixConfigs[i], fHavePriorityProxy);
     642                if (RT_SUCCESS(rc2))
    556643                {
    557644                    g_pProcessPriority = &g_aUnixConfigs[i];
     
    559646                    break;
    560647                }
    561                 if (rc == VERR_FILE_NOT_FOUND)
    562                     rc = rc3;
     648                if (rc == VERR_NOT_FOUND || rc == VERR_ACCESS_DENIED)
     649                    rc = rc2;
    563650            }
    564         }
    565651    }
    566652
     
    574660
    575661/**
     662 * Called on the priority proxy thread if it's running, otherwise
     663 * rtThreadNativeSetPriority calls it directly.
     664 */
     665static DECLCALLBACK(int) rtThreadLinuxSetPriorityCallback(PRTTHREADINT pThread, int iPriority)
     666{
     667    if (!setpriority(PRIO_PROCESS, pThread->tid, iPriority))
     668    {
     669        AssertMsg(iPriority == getpriority(PRIO_PROCESS, pThread->tid),
     670                  ("iPriority=%d getpriority()=%d\n", iPriority, getpriority(PRIO_PROCESS, pThread->tid)));
     671#ifdef THREAD_LOGGING
     672        Log(("rtThreadNativeSetPriority: Thread=%p enmType=%d iPriority=%d pid=%d tid=%d\n",
     673             pThread->Core.Key, enmType, iPriority, getpid(), pThread->tid));
     674#endif
     675        return VINF_SUCCESS;
     676    }
     677    AssertMsgFailed(("setpriority(,, %d) -> errno=%d rc=%Rrc\n", iPriority, errno, RTErrConvertFromErrno(errno)));
     678    return VINF_SUCCESS; //non-fatal for now.
     679}
     680
     681
     682/**
    576683 * Sets the priority of the thread according to the thread type
    577684 * and current process priority.
     
    589696    Assert(enmType > RTTHREADTYPE_INVALID && enmType < RTTHREADTYPE_END);
    590697    Assert(enmType == g_pProcessPriority->paTypes[enmType].enmType);
    591     Assert((pthread_t)pThread->Core.Key == pthread_self()); RT_NOREF_PV(pThread);
    592 
    593     /*
    594      * Calculate the thread priority and apply it.
    595      */
    596     int rc = VINF_SUCCESS;
    597     int iPriority = g_pProcessPriority->paTypes[enmType].iPriority + g_pProcessPriority->iDelta;
    598     if (!setpriority(PRIO_PROCESS, 0, iPriority))
    599     {
    600         AssertMsg(iPriority == getpriority(PRIO_PROCESS, 0), ("iPriority=%d getpriority()=%d\n", iPriority, getpriority(PRIO_PROCESS, 0)));
    601 #ifdef THREAD_LOGGING
    602         Log(("rtThreadNativeSetPriority: Thread=%p enmType=%d iPriority=%d pid=%d\n", pThread->Core.Key, enmType, iPriority, getpid()));
    603 #endif
    604     }
    605     else
    606     {
    607         rc = RTErrConvertFromErrno(errno);
    608         AssertMsgFailed(("setpriority(,, %d) -> errno=%d rc=%Rrc\n", iPriority, errno, rc));
    609         rc = VINF_SUCCESS; //non-fatal for now.
    610     }
    611 
    612     return rc;
    613 }
    614 
     698
     699    /*
     700     * The thread ID is zero for alien threads, so skip these or we'd risk
     701     * modifying our own priority.
     702     */
     703    if (!pThread->tid)
     704        return VINF_SUCCESS;
     705
     706    /*
     707     * Calculate the thread priority and apply it, preferrably via the priority proxy thread.
     708     */
     709    int const iPriority = g_pProcessPriority->paTypes[enmType].iPriority + g_pProcessPriority->iDelta;
     710#ifdef RTTHREAD_POSIX_WITH_CREATE_PRIORITY_PROXY
     711    if (rtThreadPosixPriorityProxyStart())
     712        return rtThreadPosixPriorityProxyCall(pThread, (PFNRT)rtThreadLinuxSetPriorityCallback, 2, pThread, iPriority);
     713#endif
     714    return rtThreadLinuxSetPriorityCallback(pThread, iPriority);
     715}
     716
  • trunk/src/VBox/Runtime/r3/posix/sched-posix.cpp

    r76553 r77910  
    323323/** Set if we figure we have nice capability, meaning we can use setpriority
    324324 * to raise the priority. */
    325 bool g_fCanNice = false;
     325static bool g_fCanNice = false;
    326326
    327327
     
    500500    /* done */
    501501    rtSchedNativeRestore(&SavedPriority);
     502    RT_NOREF(pvUser);
    502503    return (void *)VINF_SUCCESS;
    503504}
     
    634635    /* done */
    635636    rtSchedNativeRestore(&SavedPriority);
    636     return (void *)rc;
     637    return (void *)(intptr_t)rc;
    637638}
    638639
     
    650651    Assert(enmPriority > RTPROCPRIORITY_INVALID && enmPriority < RTPROCPRIORITY_LAST);
    651652
     653#ifdef RTTHREAD_POSIX_WITH_CREATE_PRIORITY_PROXY
     654    /*
     655     * Make sure the proxy creation thread is started so we don't 'lose' our
     656     * initial priority if it's lowered.
     657     */
     658    rtThreadPosixPriorityProxyStart();
     659#endif
     660
     661    /*
     662     * Nothing to validate for the default priority (assuming no external renice).
     663     */
    652664    int rc = VINF_SUCCESS;
    653665    if (enmPriority == RTPROCPRIORITY_DEFAULT)
     
    732744
    733745/**
     746 * Worker for rtThreadNativeSetPriority/OSPRIOSUP_PROCESS_AND_THREAD_LEVEL
     747 * that's either called on the priority proxy thread or directly if no proxy.
     748 */
     749static DECLCALLBACK(int) rtThreadPosixSetPriorityOnProcAndThrdCallback(PRTTHREADINT pThread, RTTHREADTYPE enmType)
     750{
     751    struct sched_param  SchedParam = {-9999999};
     752    int                 iPolicy = -7777777;
     753    int rc = pthread_getschedparam((pthread_t)pThread->Core.Key, &iPolicy, &SchedParam);
     754    if (!rc)
     755    {
     756        SchedParam.sched_priority = g_pProcessPriority->paTypes[enmType].iPriority
     757            + g_pProcessPriority->iDelta
     758            + sched_get_priority_min(iPolicy);
     759
     760        rc = pthread_setschedparam((pthread_t)pThread->Core.Key, iPolicy, &SchedParam);
     761        if (!rc)
     762        {
     763#ifdef THREAD_LOGGING
     764            Log(("rtThreadNativeSetPriority: Thread=%p enmType=%d iPolicy=%d sched_priority=%d pid=%d\n",
     765                 pThread->Core.Key, enmType, iPolicy, SchedParam.sched_priority, getpid()));
     766#endif
     767            return VINF_SUCCESS;
     768        }
     769    }
     770
     771    int rcNative = rc;
     772    rc = RTErrConvertFromErrno(rc);
     773    AssertMsgFailed(("pthread_[gs]etschedparam(%p, %d, {%d}) -> rcNative=%d rc=%Rrc\n",
     774                     (void *)pThread->Core.Key, iPolicy, SchedParam.sched_priority, rcNative, rc)); NOREF(rcNative);
     775    return rc;
     776}
     777
     778
     779/**
    734780 * Sets the priority of the thread according to the thread type
    735781 * and current process priority.
     
    746792    Assert(enmType > RTTHREADTYPE_INVALID && enmType < RTTHREADTYPE_END);
    747793    Assert(enmType == g_pProcessPriority->paTypes[enmType].enmType);
    748     Assert((pthread_t)pThread->Core.Key == pthread_self());
    749794
    750795    int rc = VINF_SUCCESS;
     
    753798        case OSPRIOSUP_PROCESS_AND_THREAD_LEVEL:
    754799        {
    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()));
     800#ifdef RTTHREAD_POSIX_WITH_CREATE_PRIORITY_PROXY
     801            if (rtThreadPosixPriorityProxyStart())
     802                rc = rtThreadPosixPriorityProxyCall(pThread, (PFNRT)rtThreadPosixSetPriorityOnProcAndThrdCallback,
     803                                                    2, pThread, enmType);
     804            else
    770805#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);
     806                rc = rtThreadPosixSetPriorityOnProcAndThrdCallback(pThread, enmType);
    779807            break;
    780808        }
     
    782810        case OSPRIOSUP_THREAD_LEVEL:
    783811        {
     812            /* No cross platform way of getting the 'who' parameter value for
     813               arbitrary threads, so this is restricted to the calling thread only. */
     814            AssertReturn((pthread_t)pThread->Core.Key == pthread_self(), VERR_NOT_SUPPORTED);
     815
    784816            int iPriority = g_pProcessPriority->paTypes[enmType].iPriority + g_pProcessPriority->iDelta;
    785817            if (!setpriority(PRIO_PROCESS, 0, iPriority))
  • trunk/src/VBox/Runtime/r3/posix/thread-posix.cpp

    r76553 r77910  
    3333#include <pthread.h>
    3434#include <signal.h>
     35#include <stdlib.h>
    3536#if defined(RT_OS_LINUX)
    3637# include <unistd.h>
     
    6566#include <iprt/initterm.h>
    6667#include <iprt/string.h>
     68#include <iprt/semaphore.h>
     69#include <iprt/list.h>
     70#include <iprt/once.h>
     71#include <iprt/critsect.h>
     72#include <iprt/req.h>
    6773#include "internal/thread.h"
    6874
     
    111117static PFNPTHREADSETNAME g_pfnThreadSetName = NULL;
    112118#endif /* IPRT_MAY_HAVE_PTHREAD_SET_NAME_NP */
     119
     120#ifdef RTTHREAD_POSIX_WITH_CREATE_PRIORITY_PROXY
     121/** Atomic indicator of whether the priority proxy thread has been (attempted) started.
     122 *
     123 * The priority proxy thread is started under these circumstances:
     124 *      - RTThreadCreate
     125 *      - RTThreadSetType
     126 *      - RTProcSetPriority
     127 *
     128 * Which means that we'll be single threaded when this is modified.
     129 *
     130 * Speical values:
     131 *      - VERR_TRY_AGAIN:           Not yet started.
     132 *      - VERR_WRONG_ORDER:         Starting.
     133 *      - VINF_SUCCESS:             Started successfully.
     134 *      - VERR_PROCESS_NOT_FOUND:   Stopping or stopped
     135 *      - Other error status if failed to start.
     136 *
     137 * @note We could potentially optimize this by only start it when we lower the
     138 *       priority of ourselves, the process, or a newly created thread.  But
     139 *       that would means we would need to take multi-threading into account, so
     140 *       let's not do that for now.
     141 */
     142static int32_t volatile g_rcPriorityProxyThreadStart            = VERR_TRY_AGAIN;
     143/** The IPRT thread handle for the priority proxy. */
     144static RTTHREAD         g_hRTThreadPosixPriorityProxyThread     = NIL_RTTHREAD;
     145/** The priority proxy queue. */
     146static RTREQQUEUE       g_hRTThreadPosixPriorityProxyQueue      = NIL_RTREQQUEUE;
     147#endif /* RTTHREAD_POSIX_WITH_CREATE_PRIORITY_PROXY */
    113148
    114149
     
    332367}
    333368
    334 
    335 DECLHIDDEN(int) rtThreadNativeCreate(PRTTHREADINT pThread, PRTNATIVETHREAD pNativeThread)
     369#ifdef RTTHREAD_POSIX_WITH_CREATE_PRIORITY_PROXY
     370
     371/**
     372 * @callback_method_impl{FNRTTHREAD,
     373 *  Priority proxy thread that services g_hRTThreadPosixPriorityProxyQueue.}
     374 */
     375static DECLCALLBACK(int) rtThreadPosixPriorityProxyThread(PRTTHREADINT, void *)
     376{
     377    for (;;)
     378    {
     379        RTREQQUEUE hReqQueue = g_hRTThreadPosixPriorityProxyQueue;
     380        if (hReqQueue != NIL_RTREQQUEUE)
     381            RTReqQueueProcess(hReqQueue, RT_INDEFINITE_WAIT);
     382        else
     383            break;
     384
     385        int32_t rc = ASMAtomicUoReadS32(&g_rcPriorityProxyThreadStart);
     386        if (rc != VINF_SUCCESS && rc != VERR_WRONG_ORDER)
     387            break;
     388    }
     389
     390    return VINF_SUCCESS;
     391}
     392
     393
     394/**
     395 * Just returns a non-success status codes to force the thread to re-evaluate
     396 * the global shutdown variable.
     397 */
     398static DECLCALLBACK(int) rtThreadPosixPriorityProxyStopper(void)
     399{
     400    return VERR_CANCELLED;
     401}
     402
     403
     404/**
     405 * An atexit() callback that stops the proxy creation/priority thread.
     406 */
     407static void rtThreadStopProxyThread(void)
     408{
     409    /*
     410     * Signal to the thread that it's time to shut down.
     411     */
     412    int32_t rc = ASMAtomicXchgS32(&g_rcPriorityProxyThreadStart, VERR_PROCESS_NOT_FOUND);
     413    if (RT_SUCCESS(rc))
     414    {
     415        /*
     416         * Grab the associated handles.
     417         */
     418        RTTHREAD   hThread = g_hRTThreadPosixPriorityProxyThread;
     419        RTREQQUEUE hQueue  = g_hRTThreadPosixPriorityProxyQueue;
     420        g_hRTThreadPosixPriorityProxyQueue  = NIL_RTREQQUEUE;
     421        g_hRTThreadPosixPriorityProxyThread = NIL_RTTHREAD;
     422        ASMCompilerBarrier(); /* paranoia */
     423
     424        AssertReturnVoid(hThread != NIL_RTTHREAD);
     425        AssertReturnVoid(hQueue != NIL_RTREQQUEUE);
     426
     427        /*
     428         * Kick the thread so it gets out of any pending RTReqQueueProcess call ASAP.
     429         */
     430        rc = RTReqQueueCallEx(hQueue, NULL, 0 /*cMillies*/, RTREQFLAGS_IPRT_STATUS | RTREQFLAGS_NO_WAIT,
     431                              (PFNRT)rtThreadPosixPriorityProxyStopper, 0);
     432
     433        /*
     434         * Wait for the thread to complete.
     435         */
     436        rc = RTThreadWait(hThread, RT_SUCCESS(rc) ? RT_MS_1SEC * 5 : 32, NULL);
     437        if (RT_SUCCESS(rc))
     438            RTReqQueueDestroy(hQueue);
     439        /* else: just leak the stuff, we're exitting, so nobody cares... */
     440    }
     441}
     442
     443
     444/**
     445 * Ensure that the proxy priority proxy thread has been started.
     446 *
     447 * Since we will always start a proxy thread when asked to create a thread,
     448 * there is no need for serialization here.
     449 *
     450 * @retval  true if started
     451 * @retval  false if it failed to start (caller must handle this scenario).
     452 */
     453DECLHIDDEN(bool) rtThreadPosixPriorityProxyStart(void)
     454{
     455    /*
     456     * Read the result.
     457     */
     458    int rc = ASMAtomicUoReadS32(&g_rcPriorityProxyThreadStart);
     459    if (rc != VERR_TRY_AGAIN)
     460        return RT_SUCCESS(rc);
     461
     462    /* If this triggers then there is a very unexpected race somewhere.  It
     463       should be harmless though. */
     464    AssertReturn(ASMAtomicCmpXchgS32(&g_rcPriorityProxyThreadStart, VERR_WRONG_ORDER, VERR_TRY_AGAIN), false);
     465
     466    /*
     467     * Not yet started, so do that.
     468     */
     469    rc = RTReqQueueCreate(&g_hRTThreadPosixPriorityProxyQueue);
     470    if (RT_SUCCESS(rc))
     471    {
     472        rc = RTThreadCreate(&g_hRTThreadPosixPriorityProxyThread, rtThreadPosixPriorityProxyThread, NULL, 0 /*cbStack*/,
     473                            RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "RTThrdPP");
     474        if (RT_SUCCESS(rc))
     475        {
     476            ASMAtomicWriteS32(&g_rcPriorityProxyThreadStart, VINF_SUCCESS);
     477
     478            atexit(rtThreadStopProxyThread);
     479            return true;
     480        }
     481        RTReqQueueCreate(&g_hRTThreadPosixPriorityProxyQueue);
     482    }
     483    ASMAtomicWriteS32(&g_rcPriorityProxyThreadStart, rc != VERR_WRONG_ORDER ? rc : VERR_PROCESS_NOT_FOUND);
     484    return false;
     485}
     486
     487
     488/**
     489 * Calls @a pfnFunction from the priority proxy thread.
     490 *
     491 * Caller must have called rtThreadPosixStartProxy() to check that the priority
     492 * proxy thread is running.
     493 *
     494 * @returns
     495 * @param   pTargetThread   The target thread, NULL if not applicable.  This is
     496 *                          so we can skip calls pertaining to the priority
     497 *                          proxy thread itself.
     498 * @param   pfnFunction     The function to call.  Must return IPRT status code.
     499 * @param   cArgs           Number of arguments (see also RTReqQueueCall).
     500 * @param   ...             Arguments (see also RTReqQueueCall).
     501 */
     502DECLHIDDEN(int) rtThreadPosixPriorityProxyCall(PRTTHREADINT pTargetThread, PFNRT pfnFunction, int cArgs, ...)
     503{
     504    int rc;
     505    if (   !pTargetThread
     506        || pTargetThread->pfnThread != rtThreadPosixPriorityProxyThread)
     507    {
     508        va_list va;
     509        va_start(va, cArgs);
     510        PRTREQ pReq;
     511        rc = RTReqQueueCallV(g_hRTThreadPosixPriorityProxyQueue, &pReq, RT_INDEFINITE_WAIT, RTREQFLAGS_IPRT_STATUS,
     512                             pfnFunction, cArgs, va);
     513        va_end(va);
     514        RTReqRelease(pReq);
     515    }
     516    else
     517        rc = VINF_SUCCESS;
     518    return rc;
     519}
     520
     521#endif /* !RTTHREAD_POSIX_WITH_CREATE_PRIORITY_PROXY */
     522
     523/**
     524 * Worker for rtThreadNativeCreate that's either called on the priority proxy
     525 * thread or directly on the calling thread depending on the proxy state.
     526 */
     527static DECLCALLBACK(int) rtThreadNativeInternalCreate(PRTTHREADINT pThread, PRTNATIVETHREAD pNativeThread)
    336528{
    337529    /*
     
    377569
    378570
     571DECLHIDDEN(int) rtThreadNativeCreate(PRTTHREADINT pThread, PRTNATIVETHREAD pNativeThread)
     572{
     573#ifdef RTTHREAD_POSIX_WITH_CREATE_PRIORITY_PROXY
     574    /*
     575     * If we have a priority proxy thread, use it.  Make sure to ignore the
     576     * staring of the proxy thread itself.
     577     */
     578    if (   pThread->pfnThread != rtThreadPosixPriorityProxyThread
     579        && rtThreadPosixPriorityProxyStart())
     580    {
     581        PRTREQ pReq;
     582        int rc = RTReqQueueCall(g_hRTThreadPosixPriorityProxyQueue, &pReq, RT_INDEFINITE_WAIT,
     583                                (PFNRT)rtThreadNativeInternalCreate, 2, pThread, pNativeThread);
     584        RTReqRelease(pReq);
     585        return rc;
     586    }
     587
     588    /*
     589     * Fall back on creating it directly without regard to priority proxying.
     590     */
     591#endif
     592    return rtThreadNativeInternalCreate(pThread, pNativeThread);
     593}
     594
     595
    379596RTDECL(RTTHREAD) RTThreadSelf(void)
    380597{
  • trunk/src/VBox/Runtime/r3/win/sched-win.cpp

    r76634 r77910  
    328328
    329329#ifdef WIN32_SCHED_ENABLED
    330     if (SetThreadPriority(rtThreadNativeGetHandle(pThread), g_pProcessPriority->aTypes[enmType].iThreadPriority))
     330    HANDLE hThread = rtThreadNativeGetHandle(pThread);
     331    if (   hThread == NULL /* No handle for alien threads. */
     332        || SetThreadPriority(hThread, g_pProcessPriority->aTypes[enmType].iThreadPriority))
    331333        return VINF_SUCCESS;
    332334
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette