VirtualBox

Changeset 33144 in vbox


Ignore:
Timestamp:
Oct 14, 2010 10:11:36 PM (14 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
66676
Message:

IPRT: Reimplemented ring-0 event semaphores for solaris.

Location:
trunk/src/VBox
Files:
1 added
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/HostDrivers/Support/solaris/mod.sh

    r28800 r33144  
    6767$SUDO cp $DIR/vboxdrv $VBOXDRV_DIR/vboxdrv
    6868$SUDO cp $script_dir/src/VBox/HostDrivers/Support/solaris/vboxdrv.conf $VBOXDRV_CONF_DIR/vboxdrv.conf
    69 old_id=`/usr/sbin/modinfo | /usr/xpg4/bin/grep vbox | cut -f 1 -d ' ' | sort -n -r `
     69old_id=`/usr/sbin/modinfo | /usr/xpg4/bin/grep vbox | grep -v vboxguest | grep -v vboxfs | cut -f 1 -d ' ' | sort -n -r `
    7070if test -n "$old_id"; then
    7171    echo "* unloading $old_id..."
  • trunk/src/VBox/Runtime/Makefile.kmk

    r33092 r33144  
    16401640        generic/RTAssertShouldPanic-generic.cpp \
    16411641        generic/RTLogWriteStdOut-stub-generic.cpp \
     1642        generic/RTSemEventWait-2-ex-generic.cpp \
     1643        generic/RTSemEventWaitNoResume-2-ex-generic.cpp \
    16421644        generic/RTSemEventMultiWait-2-ex-generic.cpp \
    16431645        generic/RTSemEventMultiWaitNoResume-2-ex-generic.cpp \
  • trunk/src/VBox/Runtime/r0drv/solaris/semevent-r0drv-solaris.c

    r30935 r33144  
    3939#endif
    4040#include <iprt/err.h>
     41#include <iprt/list.h>
     42#include <iprt/lockvalidator.h>
    4143#include <iprt/mem.h>
    4244#include <iprt/mp.h>
    4345#include <iprt/thread.h>
    4446#include "internal/magics.h"
     47#include "semeventwait-r0drv-solaris.h"
    4548
    4649
     
    4851*   Structures and Typedefs                                                    *
    4952*******************************************************************************/
     53/**
     54 * Waiter entry.  Lives on the stack.
     55 *
     56 * @remarks Unfortunately, we cannot easily use cv_signal because we cannot
     57 *          distinguish between it and the spurious wakeups we get after fork.
     58 *          So, we keep an unprioritized FIFO with the sleeping threads.
     59 */
     60typedef struct RTSEMEVENTSOLENTRY
     61{
     62    /** The list node. */
     63    RTLISTNODE      Node;
     64    /** The thread. */
     65    kthread_t      *pThread;
     66    /** Flag set when waking up the thread by signal or destroy. */
     67    bool volatile   fWokenUp;
     68} RTSEMEVENTSOLENTRY;
     69/** Pointer to waiter entry. */
     70typedef RTSEMEVENTSOLENTRY *PRTSEMEVENTSOLENTRY;
     71
     72
    5073/**
    5174 * Solaris event semaphore.
     
    5982    /** Set if the object is signalled when there are no waiters. */
    6083    bool                fSignaled;
    61     /** Object generation.
    62      * This is incremented every time the object is signalled and used to
    63      * check for spurious wake-ups. */
    64     uint32_t            uSignalGen;
    65     /** The number of waiting threads. */
    66     uint32_t            cWaiters;
    67     /** The number of signalled threads. */
    68     uint32_t            cWakeUp;
     84    /** List of waiting and woken up threads. */
     85    RTLISTNODE          WaitList;
    6986    /** The Solaris mutex protecting this structure and pairing up the with the cv. */
    7087    kmutex_t            Mtx;
     
    95112    pThis->cRefs          = 1;
    96113    pThis->fSignaled      = false;
    97     pThis->uSignalGen     = 0;
    98     pThis->cWaiters       = 0;
    99     pThis->cWakeUp        = 0;
     114    RTListInit(&pThis->WaitList);
    100115    mutex_init(&pThis->Mtx, "IPRT Event Semaphore", MUTEX_DRIVER, (void *)ipltospl(DISP_LEVEL));
    101116    cv_init(&pThis->Cnd, "IPRT CV", CV_DRIVER, NULL);
     
    106121
    107122
     123/**
     124 * Retain a reference to the semaphore.
     125 *
     126 * @param   pThis       The semaphore.
     127 */
     128DECLINLINE(void) rtR0SemEventSolRetain(PRTSEMEVENTINTERNAL pThis)
     129{
     130    uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
     131    Assert(cRefs && cRefs < 100000);
     132}
     133
     134
     135/**
     136 * The destruct.
     137 *
     138 * @param   pThis       The semaphore.
     139 */
     140static void rtR0SemEventSolDtor(PRTSEMEVENTINTERNAL pThis)
     141{
     142    Assert(pThis->u32Magic != RTSEMEVENT_MAGIC);
     143    cv_destroy(&pThis->Cnd);
     144    mutex_destroy(&pThis->Mtx);
     145    RTMemFree(pThis);
     146}
     147
     148
     149/**
     150 * Release a reference, destroy the thing if necessary.
     151 *
     152 * @param   pThis       The semaphore.
     153 */
     154DECLINLINE(void) rtR0SemEventSolRelease(PRTSEMEVENTINTERNAL pThis)
     155{
     156    if (RT_UNLIKELY(ASMAtomicDecU32(&pThis->cRefs) == 0))
     157        rtR0SemEventSolDtor(pThis);
     158}
     159
     160
    108161RTDECL(int)  RTSemEventDestroy(RTSEMEVENT hEventSem)
    109162{
     163    /*
     164     * Validate input.
     165     */
    110166    PRTSEMEVENTINTERNAL pThis = hEventSem;
    111167    if (pThis == NIL_RTSEMEVENT)
     
    113169    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
    114170    AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);
     171    Assert(pThis->cRefs > 0);
    115172    RT_ASSERT_INTS_ON();
    116173
    117174    mutex_enter(&pThis->Mtx);
    118175
    119     ASMAtomicDecU32(&pThis->cRefs);
    120 
    121     pThis->u32Magic = ~RTSEMEVENT_MAGIC; /* make the handle invalid */
    122     if (pThis->cWaiters > 0)
     176    /*
     177     * Invalidate the semaphore.
     178     */
     179    ASMAtomicWriteU32(&pThis->u32Magic, ~RTSEMEVENT_MAGIC);
     180    ASMAtomicWriteBool(&pThis->fSignaled, false);
     181
     182    /*
     183     * Abort and wake up all threads.
     184     */
     185    PRTSEMEVENTSOLENTRY pWaiter;
     186    RTListForEach(&pThis->WaitList, pWaiter, RTSEMEVENTSOLENTRY, Node)
    123187    {
    124         /*
    125          * Signal all threads to destroy.
    126          */
    127         cv_broadcast(&pThis->Cnd);
    128         mutex_exit(&pThis->Mtx);
     188        pWaiter->fWokenUp = true;
    129189    }
    130     else if (pThis->cRefs == 0)
    131     {
    132         /*
    133          * We're the last thread referencing this object, destroy it.
    134          */
    135         mutex_exit(&pThis->Mtx);
    136         cv_destroy(&pThis->Cnd);
    137         mutex_destroy(&pThis->Mtx);
    138         RTMemFree(pThis);
    139     }
    140     else
    141     {
    142         /*
    143          * There are other threads still referencing this object, last one cleans up.
    144          */
    145         mutex_exit(&pThis->Mtx);
    146     }
     190    cv_broadcast(&pThis->Cnd);
     191
     192    /*
     193     * Release the reference from RTSemEventCreateEx.
     194     */
     195    mutex_exit(&pThis->Mtx);
     196    rtR0SemEventSolRelease(pThis);
    147197
    148198    return VINF_SUCCESS;
     
    150200
    151201
    152 RTDECL(int)  RTSemEventSignal(RTSEMEVENT hEventSem)
     202RTDECL(int) RTSemEventSignal(RTSEMEVENT hEventSem)
    153203{
    154204    PRTSEMEVENTINTERNAL pThis = (PRTSEMEVENTINTERNAL)hEventSem;
     
    158208    RT_ASSERT_INTS_ON();
    159209
    160     /*
    161      * If we're in interrupt context we need to unpin the underlying current
    162      * thread as this could lead to a deadlock (see #4259 for the full explanation)
    163      *
    164      * Note! This assumes nobody is using the RTThreadPreemptDisable in an
    165      *       interrupt context and expects it to work right.  The swtch will
    166      *       result in a voluntary preemption.  To fix this, we would have to
    167      *       do our own counting in RTThreadPreemptDisable/Restore like we do
    168      *       on systems which doesn't do preemption (OS/2, linux, ...) and
    169      *       check whether preemption was disabled via RTThreadPreemptDisable
    170      *       or not and only call swtch if RTThreadPreemptDisable wasn't called.
    171      */
    172     int fAcquired = mutex_tryenter(&pThis->Mtx);
    173     if (!fAcquired)
     210    rtR0SemEventSolRetain(pThis);
     211    rtR0SemSolWaitEnterMutexWithUnpinningHack(&pThis->Mtx);
     212
     213    /*
     214     * Wake up one thread.
     215     */
     216    ASMAtomicWriteBool(&pThis->fSignaled, true);
     217
     218    PRTSEMEVENTSOLENTRY pWaiter;
     219    RTListForEach(&pThis->WaitList, pWaiter, RTSEMEVENTSOLENTRY, Node)
    174220    {
    175         if (curthread->t_intr && getpil() < DISP_LEVEL)
     221        if (!pWaiter->fWokenUp)
    176222        {
    177             RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER;
    178             RTThreadPreemptDisable(&PreemptState);
    179             preempt();
    180             RTThreadPreemptRestore(&PreemptState);
     223            pWaiter->fWokenUp = true;
     224            setrun(pWaiter->pThread);
     225            ASMAtomicWriteBool(&pThis->fSignaled, false);
     226            break;
    181227        }
    182         mutex_enter(&pThis->Mtx);
    183228    }
    184229
    185     /*
    186      * If there are more waiting threads, wake them up. Otherwise leave the
    187      * semaphore in the signalled state.
    188      */
    189     pThis->cWakeUp++;
    190     if (pThis->cWakeUp <= pThis->cWaiters) /** @todo r=bird: see cWakeup = 0 below. */
    191     {
    192         cv_signal(&pThis->Cnd);
    193         pThis->uSignalGen++;
    194     }
    195     else
    196         pThis->fSignaled = true;
    197 
    198230    mutex_exit(&pThis->Mtx);
     231    rtR0SemEventSolRelease(pThis);
    199232
    200233    RT_ASSERT_PREEMPT_CPUID();
     
    203236
    204237
    205 static int rtSemEventWaitWorker(PRTSEMEVENTINTERNAL pThis, RTMSINTERVAL cMillies, bool fInterruptible)
    206 {
    207     /*
    208      * Translate milliseconds into ticks and go to sleep.
    209      */
    210     int rc = 0;
    211     if (cMillies != RT_INDEFINITE_WAIT)
    212     {
    213         clock_t cTicks = drv_usectohz((clock_t)(cMillies * 1000L));
    214         clock_t cTimeout = ddi_get_lbolt();
    215         cTimeout += cTicks;
    216         if (fInterruptible)
    217             rc = cv_timedwait_sig(&pThis->Cnd, &pThis->Mtx, cTimeout);
    218         else
    219             rc = cv_timedwait(&pThis->Cnd, &pThis->Mtx, cTimeout);
    220     }
     238/**
     239 * Worker for RTSemEventWaitEx and RTSemEventWaitExDebug.
     240 *
     241 * @returns VBox status code.
     242 * @param   pThis           The event semaphore.
     243 * @param   fFlags          See RTSemEventWaitEx.
     244 * @param   uTimeout        See RTSemEventWaitEx.
     245 * @param   pSrcPos         The source code position of the wait.
     246 */
     247static int rtR0SemEventSolWait(PRTSEMEVENTINTERNAL pThis, uint32_t fFlags, uint64_t uTimeout,
     248                               PCRTLOCKVALSRCPOS pSrcPos)
     249{
     250    /*
     251     * Validate the input.
     252     */
     253    AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
     254    AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
     255    AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER);
     256
     257    rtR0SemEventSolRetain(pThis);
     258    mutex_enter(&pThis->Mtx);
     259
     260    /*
     261     * In the signaled state?
     262     */
     263    int rc;
     264    if (ASMAtomicCmpXchgBool(&pThis->fSignaled, false, true))
     265        rc = VINF_SUCCESS;
    221266    else
    222267    {
    223         if (fInterruptible)
    224             rc = cv_wait_sig(&pThis->Cnd, &pThis->Mtx);
    225         else
     268        /*
     269         * We have to wait.
     270         */
     271        RTR0SEMSOLWAIT Wait;
     272        rc = rtR0SemSolWaitInit(&Wait, fFlags, uTimeout);
     273        if (RT_SUCCESS(rc))
    226274        {
    227             cv_wait(&pThis->Cnd, &pThis->Mtx);
    228             rc = 1;
     275            RTSEMEVENTSOLENTRY Waiter;
     276            Waiter.pThread  = curthread;
     277            Waiter.fWokenUp = false;
     278            RTListAppend(&pThis->WaitList, &Waiter.Node);
     279
     280            for (;;)
     281            {
     282                /* The destruction test. */
     283                if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENT_MAGIC))
     284                    rc = VERR_SEM_DESTROYED;
     285                else
     286                {
     287                    /* Check the exit conditions. */
     288                    if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENT_MAGIC))
     289                        rc = VERR_SEM_DESTROYED;
     290                    else if (Waiter.fWokenUp)
     291                        rc = VINF_SUCCESS;
     292                    else if (rtR0SemSolWaitHasTimedOut(&Wait))
     293                        rc = VERR_TIMEOUT;
     294                    else if (rtR0SemSolWaitWasInterrupted(&Wait))
     295                        rc = VERR_INTERRUPTED;
     296                    else
     297                    {
     298                        /* Do the wait and then recheck the conditions. */
     299                        rtR0SemSolWaitDoIt(&Wait, &pThis->Cnd, &pThis->Mtx);
     300                        continue;
     301                    }
     302                }
     303                break;
     304            }
     305
     306            rtR0SemSolWaitDelete(&Wait);
     307            RTListNodeRemove(&Waiter.Node);
    229308        }
    230309    }
    231310
     311    mutex_exit(&pThis->Mtx);
     312    rtR0SemEventSolRelease(pThis);
    232313    return rc;
    233314}
    234315
    235316
    236 static int rtSemEventWait(RTSEMEVENT hEventSem, RTMSINTERVAL cMillies, bool fInterruptible)
    237 {
    238     int rc;
    239     PRTSEMEVENTINTERNAL pThis = (PRTSEMEVENTINTERNAL)hEventSem;
    240     AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
    241     AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);
    242     if (cMillies)
    243         RT_ASSERT_PREEMPTIBLE();
    244 
    245     mutex_enter(&pThis->Mtx);
    246 
    247     ASMAtomicIncU32(&pThis->cRefs);
    248 
    249     if (pThis->fSignaled)
    250     {
    251         /*
    252          * The last signal occurred without any waiters and now we're the first thread
    253          * waiting for the event signal. So no real need to wait for one.
    254          */
    255         Assert(!pThis->cWaiters);
    256         pThis->fSignaled = false;
    257         /** @todo r=bird: This will get out of whack if someone is in the
    258          *        process of waking up (waiting to be scheduled). Further
    259          *        more, a race between a cv_signal and a
    260          *        timeout/interruption may cause wakeups to go unconsumed.
    261          *        Not sure how we could easily deal with this rigth now... */
    262         pThis->cWakeUp   = 0;
    263         rc = VINF_SUCCESS;
    264     }
    265     else if (!cMillies)
    266         rc = VERR_TIMEOUT;
    267     else
    268     {
    269         pThis->cWaiters++;
    270         /* This loop is only for continuing after a spurious wake-up. */
    271         for (;;)
    272         {
    273             uint32_t const uSignalGenBeforeWait = pThis->uSignalGen;
    274             rc = rtSemEventWaitWorker(pThis, cMillies, fInterruptible);
    275             if (rc > 0)
    276             {
    277                 if (pThis->u32Magic == RTSEMEVENT_MAGIC)
    278                 {
    279                     if (pThis->uSignalGen != uSignalGenBeforeWait)
    280                     {
    281                         /* We've been signaled by cv_signal(), consume the wake up. */
    282                         --pThis->cWakeUp; /** @todo r=bird: May cause underflow, see above. */
    283                         rc = VINF_SUCCESS;
    284                     }
    285                     else
    286                         /* Spurious wakeup due to some signal, go back to waiting. */
    287                         continue;
    288                 }
    289                 else
    290                     /* We're being destroyed. */
    291                     rc = VERR_SEM_DESTROYED;
    292             }
    293             else if (rc == -1)
    294                 /* Timeout reached. */
    295                 rc = VERR_TIMEOUT;
    296             else
    297                 /* Returned due to pending signal */
    298                 rc = VERR_INTERRUPTED;
    299 
    300             break;
    301         }
    302         --pThis->cWaiters;
    303     }
    304 
    305     if (!ASMAtomicDecU32(&pThis->cRefs))
    306     {
    307         Assert(RT_FAILURE_NP(rc));
    308         mutex_exit(&pThis->Mtx);
    309         cv_destroy(&pThis->Cnd);
    310         mutex_destroy(&pThis->Mtx);
    311         RTMemFree(pThis);
    312         return rc;
    313     }
    314 
    315     mutex_exit(&pThis->Mtx);
    316     return rc;
    317 }
    318 
    319 
    320 RTDECL(int)  RTSemEventWait(RTSEMEVENT hEventSem, RTMSINTERVAL cMillies)
    321 {
    322     return rtSemEventWait(hEventSem, cMillies, false /* not interruptible */);
    323 }
    324 
    325 
    326 RTDECL(int)  RTSemEventWaitNoResume(RTSEMEVENT hEventSem, RTMSINTERVAL cMillies)
    327 {
    328     return rtSemEventWait(hEventSem, cMillies, true /* interruptible */);
    329 }
    330 
     317#undef RTSemEventWaitEx
     318RTDECL(int)  RTSemEventWaitEx(RTSEMEVENT hEventSem, uint32_t fFlags, uint64_t uTimeout)
     319{
     320#ifndef RTSEMEVENT_STRICT
     321    return rtR0SemEventSolWait(hEventSem, fFlags, uTimeout, NULL);
     322#else
     323    RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
     324    return rtR0SemEventSolWait(hEventSem, fFlags, uTimeout, &SrcPos);
     325#endif
     326}
     327
     328
     329RTDECL(int)  RTSemEventWaitExDebug(RTSEMEVENT hEventSem, uint32_t fFlags, uint64_t uTimeout,
     330                                   RTHCUINTPTR uId, RT_SRC_POS_DECL)
     331{
     332    RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
     333    return rtR0SemEventSolWait(hEventSem, fFlags, uTimeout, &SrcPos);
     334}
     335
  • trunk/src/VBox/Runtime/r0drv/solaris/semeventmulti-r0drv-solaris.c

    r33092 r33144  
    4545#include <iprt/time.h>
    4646#include "internal/magics.h"
     47#include "semeventwait-r0drv-solaris.h"
    4748
    4849
     
    195196    RT_ASSERT_INTS_ON();
    196197    rtR0SemEventMultiSolRetain(pThis);
    197 
    198     /*
    199      * If we're in interrupt context we need to unpin the underlying current
    200      * thread as this could lead to a deadlock (see #4259 for the full explanation)
    201      *
    202      * Note! See remarks about preemption in RTSemEventSignal.
    203      */
    204     int fAcquired = mutex_tryenter(&pThis->Mtx);
    205     if (!fAcquired)
    206     {
    207         if (curthread->t_intr && getpil() < DISP_LEVEL)
    208         {
    209             RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER;
    210             RTThreadPreemptDisable(&PreemptState);
    211             preempt();
    212             RTThreadPreemptRestore(&PreemptState);
    213         }
    214         mutex_enter(&pThis->Mtx);
    215     }
     198    rtR0SemSolWaitEnterMutexWithUnpinningHack(&pThis->Mtx);
    216199    Assert(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC);
    217200
     
    244227                    VERR_INVALID_HANDLE);
    245228    RT_ASSERT_INTS_ON();
     229
    246230    rtR0SemEventMultiSolRetain(pThis);
    247 
    248     /*
    249      * If we're in interrupt context we need to unpin the underlying current
    250      * thread as this could lead to a deadlock (see #4259 for the full explanation)
    251      *
    252      * Note! See remarks about preemption in RTSemEventSignal.
    253      */
    254     int fAcquired = mutex_tryenter(&pThis->Mtx);
    255     if (!fAcquired)
    256     {
    257         if (curthread->t_intr && getpil() < DISP_LEVEL)
    258         {
    259             RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER;
    260             RTThreadPreemptDisable(&PreemptState);
    261             preempt();
    262             RTThreadPreemptRestore(&PreemptState);
    263         }
    264         mutex_enter(&pThis->Mtx);
    265     }
     231    rtR0SemSolWaitEnterMutexWithUnpinningHack(&pThis->Mtx);
    266232    Assert(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC);
    267233
     
    272238
    273239    mutex_exit(&pThis->Mtx);
    274 
    275240    rtR0SemEventMultiSolRelease(pThis);
     241
    276242    RT_ASSERT_PREEMPT_CPUID();
    277243    return VINF_SUCCESS;
    278244}
    279 
    280 /* -------- Move to header ---------- */
    281 
    282 typedef struct RTR0SEMSOLWAIT
    283 {
    284     /** The absolute timeout given as nano seconds since the start of the
    285      *  monotonic clock. */
    286     uint64_t        uNsAbsTimeout;
    287     /** The timeout in nano seconds relative to the start of the wait. */
    288     uint64_t        cNsRelTimeout;
    289     /** The native timeout value. */
    290     union
    291     {
    292         /** The timeout (abs lbolt) when fHighRes is false.  */
    293         clock_t     lTimeout;
    294     } u;
    295     /** Set if we use high resolution timeouts. */
    296     bool            fHighRes;
    297     /** Set if it's an indefinite wait. */
    298     bool            fIndefinite;
    299     /** Set if we've already timed out.
    300      * Set by rtR0SemSolWaitDoIt or rtR0SemSolWaitHighResTimeout, read by
    301      * rtR0SemSolWaitHasTimedOut. */
    302     bool volatile   fTimedOut;
    303     /** Whether the wait was interrupted. */
    304     bool            fInterrupted;
    305     /** Interruptible or uninterruptible wait. */
    306     bool            fInterruptible;
    307     /** The thread to wake up. */
    308     kthread_t      *pThread;
    309     /** Cylic timer ID (used by the timeout callback). */
    310     cyclic_id_t     idCy;
    311 } RTR0SEMSOLWAIT;
    312 /** Pointer to a solaris semaphore wait structure.  */
    313 typedef RTR0SEMSOLWAIT *PRTR0SEMSOLWAIT;
    314 
    315 
    316 /**
    317  * Initializes a wait.
    318  *
    319  * The caller MUST check the wait condition BEFORE calling this function or the
    320  * timeout logic will be flawed.
    321  *
    322  * @returns VINF_SUCCESS or VERR_TIMEOUT.
    323  * @param   pWait               The wait structure.
    324  * @param   fFlags              The wait flags.
    325  * @param   uTimeout            The timeout.
    326  * @param   pWaitQueue          The wait queue head.
    327  */
    328 DECLINLINE(int) rtR0SemSolWaitInit(PRTR0SEMSOLWAIT pWait, uint32_t fFlags, uint64_t uTimeout)
    329 {
    330     /*
    331      * Process the flags and timeout.
    332      */
    333     if (!(fFlags & RTSEMWAIT_FLAGS_INDEFINITE))
    334     {
    335         if (fFlags & RTSEMWAIT_FLAGS_MILLISECS)
    336             uTimeout = uTimeout < UINT64_MAX / UINT32_C(1000000) * UINT32_C(1000000)
    337                      ? uTimeout * UINT32_C(1000000)
    338                      : UINT64_MAX;
    339         if (uTimeout == UINT64_MAX)
    340             fFlags |= RTSEMWAIT_FLAGS_INDEFINITE;
    341         else
    342         {
    343             uint64_t u64Now;
    344             if (fFlags & RTSEMWAIT_FLAGS_RELATIVE)
    345             {
    346                 if (uTimeout == 0)
    347                     return VERR_TIMEOUT;
    348 
    349                 u64Now = RTTimeSystemNanoTS();
    350                 pWait->cNsRelTimeout = uTimeout;
    351                 pWait->uNsAbsTimeout = u64Now + uTimeout;
    352                 if (pWait->uNsAbsTimeout < u64Now) /* overflow */
    353                     fFlags |= RTSEMWAIT_FLAGS_INDEFINITE;
    354             }
    355             else
    356             {
    357                 u64Now = RTTimeSystemNanoTS();
    358                 if (u64Now >= uTimeout)
    359                     return VERR_TIMEOUT;
    360 
    361                 pWait->cNsRelTimeout = uTimeout - u64Now;
    362                 pWait->uNsAbsTimeout = uTimeout;
    363             }
    364         }
    365     }
    366 
    367     if (!(fFlags & RTSEMWAIT_FLAGS_INDEFINITE))
    368     {
    369         pWait->fIndefinite      = false;
    370         if (   (fFlags & (RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_ABSOLUTE))
    371             || pWait->cNsRelTimeout < UINT32_C(1000000000) / 100 /*Hz*/ * 4)
    372             pWait->fHighRes     = true;
    373         else
    374         {
    375 #if 1
    376             uint64_t cTicks     = NSEC_TO_TICK_ROUNDUP(uTimeout);
    377 #else
    378             uint64_t cTicks     = drv_usectohz((clock_t)(uTimeout / 1000));
    379 #endif
    380             if (cTicks >= LONG_MAX)
    381                 fFlags |= RTSEMWAIT_FLAGS_INDEFINITE;
    382             else
    383             {
    384                 pWait->u.lTimeout = ddi_get_lbolt() + cTicks;
    385                 pWait->fHighRes = false;
    386             }
    387         }
    388     }
    389 
    390     if (fFlags & RTSEMWAIT_FLAGS_INDEFINITE)
    391     {
    392         pWait->fIndefinite      = true;
    393         pWait->fHighRes         = false;
    394         pWait->uNsAbsTimeout    = UINT64_MAX;
    395         pWait->cNsRelTimeout    = UINT64_MAX;
    396         pWait->u.lTimeout       = LONG_MAX;
    397     }
    398 
    399     pWait->fTimedOut        = false;
    400     pWait->fInterrupted     = false;
    401     pWait->fInterruptible   = !!(fFlags & RTSEMWAIT_FLAGS_INTERRUPTIBLE);
    402     pWait->pThread          = curthread;
    403     pWait->idCy             = CYCLIC_NONE;
    404 
    405     return VINF_SUCCESS;
    406 }
    407 
    408 
    409 /**
    410  * Cyclic timeout callback that sets the timeout indicator and wakes up the
    411  * waiting thread.
    412  *
    413  * @param   pvUser              The wait structure.
    414  */
    415 static void rtR0SemSolWaitHighResTimeout(void *pvUser)
    416 {
    417     PRTR0SEMSOLWAIT pWait   = (PRTR0SEMSOLWAIT)pvUser;
    418     kthread_t      *pThread = pWait->pThread;
    419     if (VALID_PTR(pThread)) /* paranoia */
    420     {
    421         /* Note: Trying to take the cpu_lock here doesn't work. */
    422         if (mutex_owner(&cpu_lock) == curthread)
    423         {
    424             cyclic_remove(pWait->idCy);
    425             pWait->idCy = CYCLIC_NONE;
    426         }
    427         ASMAtomicWriteBool(&pWait->fTimedOut, true);
    428         setrun(pThread);
    429     }
    430 }
    431 
    432 
    433 /**
    434  * Do the actual wait.
    435  *
    436  * @param   pWait               The wait structure.
    437  * @param   pCnd                The condition variable to wait on.
    438  * @param   pMtx                The mutex related to the condition variable.
    439  *                              The caller has entered this.
    440  */
    441 DECLINLINE(void) rtR0SemSolWaitDoIt(PRTR0SEMSOLWAIT pWait, kcondvar_t *pCnd, kmutex_t *pMtx)
    442 {
    443     int rc = 1;
    444     if (pWait->fIndefinite)
    445     {
    446         /*
    447          * No timeout - easy.
    448          */
    449         if (pWait->fInterruptible)
    450             rc = cv_wait_sig(pCnd, pMtx);
    451         else
    452             cv_wait(pCnd, pMtx);
    453     }
    454     else if (pWait->fHighRes)
    455     {
    456         /*
    457          * High resolution timeout - arm a one-shot cyclic for waking up
    458          * the thread at the desired time.
    459          */
    460         cyc_handler_t   Cyh;
    461         Cyh.cyh_arg      = pWait;
    462         Cyh.cyh_func     = rtR0SemSolWaitHighResTimeout;
    463         Cyh.cyh_level    = CY_LOW_LEVEL; /// @todo try CY_LOCK_LEVEL and CY_HIGH_LEVEL?
    464 
    465         cyc_time_t      Cyt;
    466         Cyt.cyt_when     = pWait->uNsAbsTimeout;
    467         Cyt.cyt_interval = UINT64_C(1000000000) * 60;
    468 
    469         mutex_enter(&cpu_lock);
    470         pWait->idCy = cyclic_add(&Cyh, &Cyt);
    471         mutex_exit(&cpu_lock);
    472 
    473         if (pWait->fInterruptible)
    474             rc = cv_wait_sig(pCnd, pMtx);
    475         else
    476             cv_wait(pCnd, pMtx);
    477 
    478         mutex_enter(&cpu_lock);
    479         if (pWait->idCy != CYCLIC_NONE)
    480         {
    481             cyclic_remove(pWait->idCy);
    482             pWait->idCy = CYCLIC_NONE;
    483         }
    484         mutex_exit(&cpu_lock);
    485     }
    486     else
    487     {
    488         /*
    489          * Normal timeout.
    490          */
    491         if (pWait->fInterruptible)
    492             rc = cv_timedwait_sig(pCnd, pMtx, pWait->u.lTimeout);
    493         else
    494             rc = cv_timedwait(pCnd, pMtx, pWait->u.lTimeout);
    495     }
    496 
    497     /* Above zero means normal wake-up. */
    498     if (rc > 0)
    499         return;
    500 
    501     /* Timeout is signalled by -1. */
    502     if (rc == -1)
    503         pWait->fTimedOut = true;
    504     /* Interruption is signalled by 0. */
    505     else
    506     {
    507         AssertMsg(rc == 0, ("rc=%d\n", rc));
    508         pWait->fInterrupted = true;
    509     }
    510 }
    511 
    512 
    513 /**
    514  * Checks if a solaris wait was interrupted.
    515  *
    516  * @returns true / false
    517  * @param   pWait               The wait structure.
    518  * @remarks This shall be called before the first rtR0SemSolWaitDoIt().
    519  */
    520 DECLINLINE(bool) rtR0SemSolWaitWasInterrupted(PRTR0SEMSOLWAIT pWait)
    521 {
    522     return pWait->fInterrupted;
    523 }
    524 
    525 
    526 /**
    527  * Checks if a solaris wait has timed out.
    528  *
    529  * @returns true / false
    530  * @param   pWait               The wait structure.
    531  */
    532 DECLINLINE(bool) rtR0SemSolWaitHasTimedOut(PRTR0SEMSOLWAIT pWait)
    533 {
    534     return pWait->fTimedOut;
    535 }
    536 
    537 
    538 /**
    539  * Deletes a solaris wait.
    540  *
    541  * @param   pWait               The wait structure.
    542  */
    543 DECLINLINE(void) rtR0SemSolWaitDelete(PRTR0SEMSOLWAIT pWait)
    544 {
    545     pWait->pThread = NULL;
    546 }
    547 
    548 /* -------- End ---------- */
    549245
    550246
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