VirtualBox

Ignore:
Timestamp:
Mar 24, 2011 11:20:37 AM (14 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
70745
Message:

r0drv/solaris/solevent*: Must re-check the wait condition before going to sleep.

Location:
trunk/src/VBox/Runtime/r0drv/solaris
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/r0drv/solaris/semevent-r0drv-solaris.c

    r36282 r36392  
    6565    /** The thread. */
    6666    kthread_t          *pThread;
    67     /** Flag set when waking up the thread by signal or destroy. */
    68     bool volatile       fWokenUp;
     67    /** Set to @c true when waking up the thread by signal or destroy. */
     68    uint32_t volatile  fWokenUp;
    6969} RTSEMEVENTSOLENTRY;
    7070/** Pointer to waiter entry. */
     
    300300                    {
    301301                        /* Do the wait and then recheck the conditions. */
    302                         rtR0SemSolWaitDoIt(&Wait, &pThis->Cnd, &pThis->Mtx);
     302                        rtR0SemSolWaitDoIt(&Wait, &pThis->Cnd, &pThis->Mtx, &Waiter.fWokenUp, false);
    303303                        continue;
    304304                    }
  • trunk/src/VBox/Runtime/r0drv/solaris/semeventmulti-r0drv-solaris.c

    r36286 r36392  
    305305                    {
    306306                        /* Do the wait and then recheck the conditions. */
    307                         rtR0SemSolWaitDoIt(&Wait, &pThis->Cnd, &pThis->Mtx);
     307                        rtR0SemSolWaitDoIt(&Wait, &pThis->Cnd, &pThis->Mtx, &pThis->fStateAndGen, fOrgStateAndGen);
    308308                        continue;
    309309                    }
  • trunk/src/VBox/Runtime/r0drv/solaris/semeventwait-r0drv-solaris.h

    r36287 r36392  
    55
    66/*
    7  * Copyright (C) 2006-2010 Oracle Corporation
     7 * Copyright (C) 2006-2011 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    3939#define RTR0SEMSOLWAIT_RESOLUTION   50000
    4040
     41/** Disables the cyclic fallback code for old S10 installs - see @bugref{5342}.
     42 * @todo Fixed by @bugref{5595}, can be reenabled after checking out
     43 *       CY_HIGH_LEVEL. */
     44#define RTR0SEMSOLWAIT_NO_OLD_S10_FALLBACK
    4145
    4246/**
     
    6064    /** Set if it's an indefinite wait. */
    6165    bool            fIndefinite;
     66    /** Set if the waiting thread is ready to be woken up.
     67     * Avoids false setrun() calls due to temporary mutex exits. */
     68    bool volatile   fWantWakeup;
    6269    /** Set if we've already timed out.
    6370     * Set by rtR0SemSolWaitDoIt or rtR0SemSolWaitHighResTimeout, read by
     
    7077    /** The thread to wake up. */
    7178    kthread_t      *pThread;
    72 #if 0 /* @bugref{5342} */
     79#ifndef RTR0SEMSOLWAIT_NO_OLD_S10_FALLBACK
    7380    /** Cylic timer ID (used by the timeout callback). */
    7481    cyclic_id_t     idCy;
     
    137144        if (  (   (fFlags & (RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_ABSOLUTE))
    138145               || pWait->cNsRelTimeout < UINT32_C(1000000000) / 100 /*Hz*/ * 4)
    139             && g_pfnrtR0Sol_timeout_generic != NULL /* See @bugref{5342} */)
     146#ifdef RTR0SEMSOLWAIT_NO_OLD_S10_FALLBACK
     147            && g_pfnrtR0Sol_timeout_generic != NULL
     148#endif
     149           )
    140150            pWait->fHighRes     = true;
    141151        else
     
    161171    }
    162172
     173    pWait->fWantWakeup      = false;
    163174    pWait->fTimedOut        = false;
    164175    pWait->fInterrupted     = false;
     
    166177    pWait->pThread          = curthread;
    167178    pWait->pvMtx            = NULL;
    168 #if 0 /* @bugref{5342} */
     179#ifndef RTR0SEMSOLWAIT_NO_OLD_S10_FALLBACK
    169180    pWait->idCy             = CYCLIC_NONE;
    170181#endif
     
    174185
    175186
    176 #if 0 /* @bugref{5342} */
     187#ifndef RTR0SEMSOLWAIT_NO_OLD_S10_FALLBACK
    177188/**
    178189 * Cyclic timeout callback that sets the timeout indicator and wakes up the
     
    191202           before we wake it up.
    192203           Note: Trying to take the cpu_lock here doesn't work. */
    193         /** @todo LOCK ORDER INVERSION (pMtx & cpu_lock when arming the timer, here it's inverted).
    194          *  Possible fix: Use the thread lock for sleep/wakeup race prevention
    195          *  instead of the mutex associated with the cv/event. */
    196204        mutex_enter(pMtx);
    197205        if (mutex_owner(&cpu_lock) == curthread)
     
    200208            pWait->idCy = CYCLIC_NONE;
    201209        }
     210        bool const fWantWakeup = pWait->fWantWakeup;
    202211        ASMAtomicWriteBool(&pWait->fTimedOut, true);
    203212        mutex_exit(pMtx);
    204         setrun(pThread);
     213
     214        if (fWantWakeup)
     215            setrun(pThread);
    205216    }
    206217}
     
    224235           before we wake it up. */
    225236        mutex_enter(pMtx);
     237        bool const fWantWakeup = pWait->fWantWakeup;
    226238        ASMAtomicWriteBool(&pWait->fTimedOut, true);
    227239        mutex_exit(pMtx);
    228         setrun(pThread);
     240
     241        if (fWantWakeup)
     242            setrun(pThread);
    229243    }
    230244}
     
    238252 * @param   pMtx                The mutex related to the condition variable.
    239253 *                              The caller has entered this.
     254 * @param   pfState             The state variable to check if have changed
     255 *                              after leaving the mutex (spinlock).
     256 * @param   fCurState           The current value of @a pfState.  We'll return
     257 *                              without sleeping if @a pfState doesn't hold
     258 *                              this value after reacquiring the mutex.
    240259 *
    241260 * @remarks This must be call with the object mutex (spinlock) held.
    242261 */
    243 DECLINLINE(void) rtR0SemSolWaitDoIt(PRTR0SEMSOLWAIT pWait, kcondvar_t *pCnd, kmutex_t *pMtx)
     262DECLINLINE(void) rtR0SemSolWaitDoIt(PRTR0SEMSOLWAIT pWait, kcondvar_t *pCnd, kmutex_t *pMtx,
     263                                    uint32_t volatile *pfState, uint32_t const fCurState)
    244264{
    245265    union
     
    251271    /*
    252272     * Arm the timeout callback.
     273     *
     274     * We will have to leave the mutex (spinlock) when doing this because S10
     275     * (didn't check S11) will not correctly preserve PIL across calls to
     276     * timeout_generic() - @bugref{5595}.  We do it for all timeout methods to
     277     * be on the safe side, the nice sideeffect of which is that it solves the
     278     * lock inversion problem found in @bugref{5342}.
    253279     */
    254     bool const fHasTimeout = !pWait->fIndefinite;
     280    bool const  fHasTimeout = !pWait->fIndefinite;
     281    bool        fGoToSleep  = !fHasTimeout;
    255282    if (fHasTimeout)
    256283    {
     284        pWait->fWantWakeup = false;             /* only want fTimedOut */
    257285        ASMAtomicWritePtr(&pWait->pvMtx, pMtx); /* atomic is paranoia */
     286        mutex_exit(pMtx);
    258287
    259288        if (pWait->fHighRes)
    260289        {
    261 #if 0 /* @bugref{5342} */
     290#ifndef RTR0SEMSOLWAIT_NO_OLD_S10_FALLBACK
    262291            if (g_pfnrtR0Sol_timeout_generic != NULL)
    263292#endif
     
    266295                 * High resolution timeout - arm a high resolution timeout callback
    267296                 * for waking up the thread at the desired time.
    268                  *
    269                  * Release and reacquire the mutex across calls to timeout_generic(), @bugref{5595}.
    270297                 */
    271                 mutex_exit(pMtx);
    272298                u.idCo = g_pfnrtR0Sol_timeout_generic(CALLOUT_REALTIME, rtR0SemSolWaitTimeout, pWait,
    273299                                                      pWait->uNsAbsTimeout, RTR0SEMSOLWAIT_RESOLUTION,
    274300                                                      CALLOUT_FLAG_ABSOLUTE);
    275                 mutex_enter(pMtx);
    276             }
    277 #if 0 /* @bugref{5342} */
     301            }
     302#ifndef RTR0SEMSOLWAIT_NO_OLD_S10_FALLBACK
    278303            else
    279304            {
     
    303328             * We're better off with our own callback like on the timeout man page,
    304329             * than calling cv_timedwait[_sig]().
    305              *
    306              * Release and reacquire the mutex across calls to realtime_timeout(), @bugref{5595}.
    307330             */
    308             mutex_exit(pMtx);
    309331            u.idTom = realtime_timeout(rtR0SemSolWaitTimeout, pWait, pWait->u.lTimeout);
    310             mutex_enter(pMtx);
    311         }
     332        }
     333
     334        /*
     335         * Reacquire the mutex and check if the sleep condition still holds and
     336         * that we didn't already time out.
     337         */
     338        mutex_enter(pMtx);
     339        pWait->fWantWakeup = true;
     340        fGoToSleep = !ASMAtomicUoReadBool(&pWait->fTimedOut)
     341                  && ASMAtomicReadU32(pfState) == fCurState;
    312342    }
    313343
    314344    /*
    315      * Check if the timeout has already fired in the time when the mutex was released.
    316      * Required since we release/reacquire the mutex, @bugref{5595}.
     345     * Do the waiting if that's still desirable.
     346     * (rc > 0 - normal wake-up; rc == 0 - interruption; rc == -1 - timeout)
    317347     */
    318     if (ASMAtomicReadBool(&pWait->fTimedOut) == false)
    319     {
    320         /*
    321          * Do the waiting.
    322          * (rc > 0 - normal wake-up; rc == 0 - interruption; rc == -1 - timeout)
    323          */
     348    if (fGoToSleep)
     349    {
    324350        if (pWait->fInterruptible)
    325351        {
     
    339365    /*
    340366     * Remove the timeout callback.  Drop the lock while we're doing that
    341      * to reduce lock contention / deadlocks.  (Too bad we are stuck with the
    342      * cv_* API here, it's doing a little bit too much.)
     367     * to reduce lock contention / deadlocks.  Before dropping the lock,
     368     * indicate that the callback shouldn't do anything.
     369     *
     370     * (Too bad we are stuck with the cv_* API here, it's doing a little
     371     * bit too much.)
    343372     */
    344373    if (fHasTimeout)
    345374    {
    346         /*
    347          * Invalidate the mutex pointer here so that if the timer fires just after we
    348          * exit the mutex or has already fired and the callback is waiting on the mutex,
    349          * we can simply ignore it in the callback as we've completed waiting.
    350          */
     375        pWait->fWantWakeup = false;
    351376        ASMAtomicWritePtr(&pWait->pvMtx, NULL);
    352377        mutex_exit(pMtx);
     
    354379        if (pWait->fHighRes)
    355380        {
    356 #if 0 /* @bugref{5342} */
     381#ifndef RTR0SEMSOLWAIT_NO_OLD_S10_FALLBACK
    357382            if (g_pfnrtR0Sol_timeout_generic != NULL)
    358383#endif
    359384                g_pfnrtR0Sol_untimeout_generic(u.idCo, 0 /*nowait*/);
    360 #if 0 /* @bugref{5342} */
     385#ifndef RTR0SEMSOLWAIT_NO_OLD_S10_FALLBACK
    361386            else
    362387            {
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