VirtualBox

Changeset 33376 in vbox for trunk/src


Ignore:
Timestamp:
Oct 24, 2010 12:55:23 PM (14 years ago)
Author:
vboxsync
Message:

FreeBSD: Implement RTSemEvent{|Multi}WaitEx

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

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/common/VBoxGuest/freebsd/Makefile

    r31518 r33376  
    113113        RTRandAdvCreateSystemFaster-generic.c \
    114114        RTRandAdvCreateSystemTruer-generic.c \
     115    RTSemEventWait-2-ex-generic.c \
     116    RTSemEventWaitNoResume-2-ex-generic.c \
     117    RTSemEventMultiWait-2-ex-generic.c \
     118    RTSemEventMultiWaitNoResume-2-ex-generic.c \
    115119        RTTimerCreate-generic.c \
    116120        timer-generic.c \
  • trunk/src/VBox/Additions/common/VBoxGuest/freebsd/files_vboxguest

    r33111 r33376  
    147147    ${PATH_ROOT}/src/VBox/Runtime/generic/RTRandAdvCreateSystemTruer-generic.cpp=>generic/RTRandAdvCreateSystemTruer-generic.c \
    148148    ${PATH_ROOT}/src/VBox/Runtime/generic/uuid-generic.cpp=>generic/uuid-generic.c \
     149    ${PATH_ROOT}/src/VBox/Runtime/generic/RTSemEventWait-2-ex-generic.cpp=>generic/RTSemEventWait-2-ex-generic.c \
     150    ${PATH_ROOT}/src/VBox/Runtime/generic/RTSemEventWaitNoResume-2-ex-generic.cpp=>generic/RTSemEventWaitNoResume-2-ex-generic.c \
     151    ${PATH_ROOT}/src/VBox/Runtime/generic/RTSemEventMultiWait-2-ex-generic.cpp=>generic/RTSemEventMultiWait-2-ex-generic.c \
     152    ${PATH_ROOT}/src/VBox/Runtime/generic/RTSemEventMultiWaitNoResume-2-ex-generic.cpp=>generic/RTSemEventMultiWaitNoResume-2-ex-generic.c \
    149153    ${PATH_ROOT}/src/VBox/Runtime/generic/RTTimerCreate-generic.cpp=>generic/RTTimerCreate-generic.c \
    150154    ${PATH_ROOT}/src/VBox/Runtime/generic/timer-generic.cpp=>generic/timer-generic.c \
     
    171175    ${PATH_ROOT}/src/VBox/Runtime/r0drv/freebsd/thread2-r0drv-freebsd.c=>r0drv/freebsd/thread2-r0drv-freebsd.c \
    172176    ${PATH_ROOT}/src/VBox/Runtime/r0drv/freebsd/time-r0drv-freebsd.c=>r0drv/freebsd/time-r0drv-freebsd.c \
     177    ${PATH_ROOT}/src/VBox/Runtime/r0drv/freebsd/sleepqueue-r0drv-freebsd.h=>r0drv/freebsd/sleepqueue-r0drv-freebsd.h \
    173178    ${PATH_ROOT}/src/VBox/Runtime/r0drv/generic/semspinmutex-r0drv-generic.c=>r0drv/generic/semspinmutex-r0drv-generic.c \
    174179    ${PATH_ROOT}/src/VBox/Runtime/r0drv/generic/mpnotification-r0drv-generic.cpp=>r0drv/generic/mpnotification-r0drv-generic.c \
  • trunk/src/VBox/HostDrivers/Support/freebsd/Makefile

    r32572 r33376  
    128128        RTRandAdvCreateSystemFaster-generic.c \
    129129        RTRandAdvCreateSystemTruer-generic.c \
     130    RTSemEventWait-2-ex-generic.c \
     131    RTSemEventWaitNoResume-2-ex-generic.c \
     132    RTSemEventMultiWait-2-ex-generic.c \
     133    RTSemEventMultiWaitNoResume-2-ex-generic.c \
    130134        RTTimerCreate-generic.c \
    131135        timer-generic.c \
  • trunk/src/VBox/HostDrivers/Support/freebsd/files_vboxdrv

    r33111 r33376  
    150150    ${PATH_ROOT}/src/VBox/Runtime/generic/RTRandAdvCreateSystemTruer-generic.cpp=>generic/RTRandAdvCreateSystemTruer-generic.c \
    151151    ${PATH_ROOT}/src/VBox/Runtime/generic/uuid-generic.cpp=>generic/uuid-generic.c \
     152    ${PATH_ROOT}/src/VBox/Runtime/generic/RTSemEventWait-2-ex-generic.cpp=>generic/RTSemEventWait-2-ex-generic.c \
     153    ${PATH_ROOT}/src/VBox/Runtime/generic/RTSemEventWaitNoResume-2-ex-generic.cpp=>generic/RTSemEventWaitNoResume-2-ex-generic.c \
     154    ${PATH_ROOT}/src/VBox/Runtime/generic/RTSemEventMultiWait-2-ex-generic.cpp=>generic/RTSemEventMultiWait-2-ex-generic.c \
     155    ${PATH_ROOT}/src/VBox/Runtime/generic/RTSemEventMultiWaitNoResume-2-ex-generic.cpp=>generic/RTSemEventMultiWaitNoResume-2-ex-generic.c \
    152156    ${PATH_ROOT}/src/VBox/Runtime/generic/RTTimerCreate-generic.cpp=>generic/RTTimerCreate-generic.c \
    153157    ${PATH_ROOT}/src/VBox/Runtime/generic/RTMpGetArraySize-generic.cpp=>generic/RTMpGetArraySize-generic.c \
     
    176180    ${PATH_ROOT}/src/VBox/Runtime/r0drv/freebsd/thread2-r0drv-freebsd.c=>r0drv/freebsd/thread2-r0drv-freebsd.c \
    177181    ${PATH_ROOT}/src/VBox/Runtime/r0drv/freebsd/time-r0drv-freebsd.c=>r0drv/freebsd/time-r0drv-freebsd.c \
     182    ${PATH_ROOT}/src/VBox/Runtime/r0drv/freebsd/sleepqueue-r0drv-freebsd.h=>r0drv/freebsd/sleepqueue-r0drv-freebsd.h \
    178183    ${PATH_ROOT}/src/VBox/Runtime/r0drv/generic/semspinmutex-r0drv-generic.c=>r0drv/generic/semspinmutex-r0drv-generic.c \
    179184    ${PATH_ROOT}/src/VBox/Runtime/r0drv/generic/mpnotification-r0drv-generic.cpp=>r0drv/generic/mpnotification-r0drv-generic.c \
  • trunk/src/VBox/Runtime/r0drv/freebsd/semevent-r0drv-freebsd.c

    r33269 r33376  
    3333*******************************************************************************/
    3434#include "the-freebsd-kernel.h"
    35 
     35#include "internal/iprt.h"
    3636#include <iprt/semaphore.h>
    37 #include <iprt/alloc.h>
     37
    3838#include <iprt/asm.h>
    3939#include <iprt/assert.h>
    4040#include <iprt/err.h>
    41 #include <iprt/spinlock.h>
    42 
     41#include <iprt/lockvalidator.h>
     42#include <iprt/mem.h>
     43
     44#include "sleepqueue-r0drv-freebsd.h"
    4345#include "internal/magics.h"
    4446
     
    5456    /** Magic value (RTSEMEVENT_MAGIC). */
    5557    uint32_t volatile   u32Magic;
    56     /** The number of waiting threads. */
    57     uint32_t volatile   cWaiters;
    58     /** Set if the event object is signaled. */
    59     uint8_t volatile    fSignaled;
    60     /** The number of threads in the process of waking up. */
    61     uint32_t volatile   cWaking;
    62     /** Spinlock protecting this structure. */
    63     RTSPINLOCK          hSpinLock;
     58    /** The object status - !0 when signaled and 0 when reset. */
     59    uint32_t volatile   fState;
     60    /** Reference counter. */
     61    uint32_t volatile   cRefs;
    6462} RTSEMEVENTINTERNAL, *PRTSEMEVENTINTERNAL;
    6563
     
    8381
    8482    pThis->u32Magic  = RTSEMEVENT_MAGIC;
    85     pThis->cWaiters  = 0;
    86     pThis->cWaking   = 0;
    87     pThis->fSignaled = 0;
    88     int rc = RTSpinlockCreate(&pThis->hSpinLock);
    89     if (RT_SUCCESS(rc))
    90     {
    91         *phEventSem = pThis;
    92         return VINF_SUCCESS;
    93     }
    94 
    95     RTMemFree(pThis);
    96     return rc;
     83    pThis->cRefs     = 1;
     84    pThis->fState    = 0;
     85
     86    *phEventSem = pThis;
     87    return VINF_SUCCESS;
     88}
     89
     90
     91/**
     92 * Retains a reference to the event semaphore.
     93 *
     94 * @param   pThis       The event semaphore.
     95 */
     96DECLINLINE(void) rtR0SemEventBsdRetain(PRTSEMEVENTINTERNAL pThis)
     97{
     98    uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
     99    Assert(cRefs < 100000); NOREF(cRefs);
     100}
     101
     102
     103/**
     104 * Releases a reference to the event semaphore.
     105 *
     106 * @param   pThis       The event semaphore.
     107 */
     108DECLINLINE(void) rtR0SemEventBsdRelease(PRTSEMEVENTINTERNAL pThis)
     109{
     110    if (RT_UNLIKELY(ASMAtomicDecU32(&pThis->cRefs) == 0))
     111        RTMemFree(pThis);
    97112}
    98113
     
    100115RTDECL(int)  RTSemEventDestroy(RTSEMEVENT hEventSem)
    101116{
     117    /*
     118     * Validate input.
     119     */
    102120    PRTSEMEVENTINTERNAL pThis = hEventSem;
    103     RTSPINLOCKTMP       Tmp   = RTSPINLOCKTMP_INITIALIZER;
    104 
    105121    if (pThis == NIL_RTSEMEVENT)
    106122        return VINF_SUCCESS;
     123    AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);
     124    Assert(pThis->cRefs > 0);
     125
     126    /*
     127     * Invalidate it and signal the object just in case.
     128     */
     129    ASMAtomicWriteU32(&pThis->u32Magic, ~RTSEMEVENT_MAGIC);
     130    ASMAtomicWriteU32(&pThis->fState, 0);
     131    rtR0SemBsdBroadcast(pThis);
     132    rtR0SemEventBsdRelease(pThis);
     133    return VINF_SUCCESS;
     134}
     135
     136
     137RTDECL(int)  RTSemEventSignal(RTSEMEVENT hEventSem)
     138{
     139    /*
     140     * Validate input.
     141     */
     142    PRTSEMEVENTINTERNAL pThis = (PRTSEMEVENTINTERNAL)hEventSem;
    107143    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
    108     AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
    109 
    110     RTSpinlockAcquire(pThis->hSpinLock, &Tmp);
    111 
    112     ASMAtomicIncU32(&pThis->u32Magic); /* make the handle invalid */
    113     if (pThis->cWaiters > 0)
    114     {
    115         /* abort waiting thread, last man cleans up. */
    116         ASMAtomicXchgU32(&pThis->cWaking, pThis->cWaking + pThis->cWaiters);
    117         sleepq_lock(pThis);
    118         sleepq_broadcast(pThis, SLEEPQ_CONDVAR, 0, 0);
    119         sleepq_release(pThis);
    120         RTSpinlockRelease(pThis->hSpinLock, &Tmp);
    121     }
    122     else if (pThis->cWaking)
    123         /* the last waking thread is gonna do the cleanup */
    124         RTSpinlockRelease(pThis->hSpinLock, &Tmp);
     144    AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);
     145    rtR0SemEventBsdRetain(pThis);
     146
     147    /*
     148     * Signal the event object.
     149     */
     150    ASMAtomicWriteU32(&pThis->fState, 1);
     151    rtR0SemBsdSignal(pThis);
     152    rtR0SemEventBsdRelease(pThis);
     153    return VINF_SUCCESS;
     154}
     155
     156/**
     157 * Worker for RTSemEventWaitEx and RTSemEventWaitExDebug.
     158 *
     159 * @returns VBox status code.
     160 * @param   pThis           The event semaphore.
     161 * @param   fFlags          See RTSemEventWaitEx.
     162 * @param   uTimeout        See RTSemEventWaitEx.
     163 * @param   pSrcPos         The source code position of the wait.
     164 */
     165static int rtR0SemEventWait(PRTSEMEVENTINTERNAL pThis, uint32_t fFlags, uint64_t uTimeout,
     166                            PCRTLOCKVALSRCPOS pSrcPos)
     167{
     168    int rc;
     169
     170    /*
     171     * Validate the input.
     172     */
     173    AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
     174    AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
     175    AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER);
     176    rtR0SemEventBsdRetain(pThis);
     177
     178    /*
     179     * Try grab the event without setting up the wait.
     180     */
     181    if (ASMAtomicCmpXchgU32(&pThis->fState, 0, 1))
     182        rc = VINF_SUCCESS;
    125183    else
    126184    {
    127         RTSpinlockRelease(pThis->hSpinLock, &Tmp);
    128         RTSpinlockDestroy(pThis->hSpinLock);
    129         RTMemFree(pThis);
    130     }
    131 
    132     return VINF_SUCCESS;
    133 }
    134 
    135 
    136 RTDECL(int)  RTSemEventSignal(RTSEMEVENT hEventSem)
    137 {
    138     RTSPINLOCKTMP       Tmp = RTSPINLOCKTMP_INITIALIZER;
    139     PRTSEMEVENTINTERNAL pThis = (PRTSEMEVENTINTERNAL)hEventSem;
    140     AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
    141     AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC,
    142                     ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
    143                     VERR_INVALID_HANDLE);
    144 
    145     RTSpinlockAcquire(pThis->hSpinLock, &Tmp);
    146 
    147     if (pThis->cWaiters > 0)
    148     {
    149         ASMAtomicDecU32(&pThis->cWaiters);
    150         ASMAtomicIncU32(&pThis->cWaking);
    151         sleepq_lock(pThis);
    152         int fWakeupSwapProc = sleepq_signal(pThis, SLEEPQ_CONDVAR, 0, 0);
    153         sleepq_release(pThis);
    154         if (fWakeupSwapProc)
    155             kick_proc0();
    156     }
    157     else
    158         ASMAtomicXchgU8(&pThis->fSignaled, true);
    159 
    160     RTSpinlockRelease(pThis->hSpinLock, &Tmp);
    161     return VINF_SUCCESS;
    162 }
    163 
    164 
    165 static int rtSemEventWait(RTSEMEVENT hEventSem, RTMSINTERVAL cMillies, bool fInterruptible)
    166 {
    167     int rc;
    168     RTSPINLOCKTMP       Tmp = RTSPINLOCKTMP_INITIALIZER;
    169     PRTSEMEVENTINTERNAL pThis = (PRTSEMEVENTINTERNAL)hEventSem;
    170     AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
    171     AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC,
    172                     ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
    173                     VERR_INVALID_HANDLE);
    174 
    175     RTSpinlockAcquire(pThis->hSpinLock, &Tmp);
    176 
    177     if (pThis->fSignaled)
    178     {
    179         Assert(!pThis->cWaiters);
    180         ASMAtomicXchgU8(&pThis->fSignaled, false);
    181         rc = VINF_SUCCESS;
    182     }
    183     else
    184     {
    185         if (cMillies == 0)
    186             rc = VERR_TIMEOUT;
    187         else
     185        /*
     186         * We have to wait.
     187         */
     188        RTR0SEMBSDSLEEP Wait;
     189        rc = rtR0SemBsdWaitInit(&Wait, fFlags, uTimeout, pThis);
     190        if (RT_SUCCESS(rc))
    188191        {
    189             ASMAtomicIncU32(&pThis->cWaiters);
    190 
    191             int fFlags = SLEEPQ_CONDVAR;
    192 
    193             if (fInterruptible)
    194                 fFlags |= SLEEPQ_INTERRUPTIBLE;
    195 
    196             sleepq_lock(pThis);
    197             sleepq_add(pThis, NULL, "IPRT Event Semaphore", fFlags, 0);
    198 
    199             if (cMillies != RT_INDEFINITE_WAIT)
     192            for (;;)
    200193            {
    201                 /*
    202                  * Translate milliseconds into ticks and go to sleep.
    203                  */
    204                 struct timeval tv;
    205 
    206                 tv.tv_sec = cMillies / 1000;
    207                 tv.tv_usec = (cMillies % 1000) * 1000;
    208 
    209                 sleepq_set_timeout(pThis, tvtohz(&tv));
    210 
    211                 RTSpinlockRelease(pThis->hSpinLock, &Tmp);
    212 
    213                 if (fInterruptible)
    214                     rc = SLEEPQ_TIMEDWAIT_SIG(pThis);
    215                 else
    216                     rc = SLEEPQ_TIMEDWAIT(pThis);
    217             }
    218             else
    219             {
    220                 RTSpinlockRelease(pThis->hSpinLock, &Tmp);
    221 
    222                 if (fInterruptible)
    223                     rc = SLEEPQ_WAIT_SIG(pThis);
     194                /* The destruction test. */
     195                if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENT_MAGIC))
     196                    rc = VERR_SEM_DESTROYED;
    224197                else
    225198                {
    226                     rc = 0;
    227                     SLEEPQ_WAIT(pThis);
    228                 }
    229             }
    230 
    231             RTSpinlockAcquire(pThis->hSpinLock, &Tmp);
    232 
    233             switch (rc)
    234             {
    235                 case 0:
    236                     if (pThis->u32Magic == RTSEMEVENT_MAGIC)
    237                     {
    238                         ASMAtomicDecU32(&pThis->cWaking);
     199                    rtR0SemBsdWaitPrepare(&Wait);
     200
     201                    /* Check the exit conditions. */
     202                    if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENT_MAGIC))
     203                        rc = VERR_SEM_DESTROYED;
     204                    else if (ASMAtomicCmpXchgU32(&pThis->fState, 0, 1))
    239205                        rc = VINF_SUCCESS;
    240                     }
     206                    else if (rtR0SemBsdWaitHasTimedOut(&Wait))
     207                        rc = VERR_TIMEOUT;
     208                    else if (rtR0SemBsdWaitWasInterrupted(&Wait))
     209                        rc = VERR_INTERRUPTED;
    241210                    else
    242211                    {
    243                         rc = VERR_SEM_DESTROYED; /** @todo this isn't necessarily correct, we've
    244                                                   * could've woken up just before destruction... */
    245                         if (!ASMAtomicDecU32(&pThis->cWaking))
    246                         {
    247                             /* The event was destroyed, as the last thread do the cleanup.
    248                                we don't actually know whether */
    249                             RTSpinlockRelease(pThis->hSpinLock, &Tmp);
    250                             RTSpinlockDestroy(pThis->hSpinLock);
    251                             RTMemFree(pThis);
    252                             return rc;
    253                         }
     212                        /* Do the wait and then recheck the conditions. */
     213                        rtR0SemBsdWaitDoIt(&Wait);
     214                        continue;
    254215                    }
    255                     break;
    256 
    257                 case EWOULDBLOCK:
    258                     Assert(cMillies != RT_INDEFINITE_WAIT);
    259                     if (pThis->cWaiters > 0)
    260                         ASMAtomicDecU32(&pThis->cWaiters);
    261                     rc = VERR_TIMEOUT;
    262                     break;
    263 
    264                 case EINTR:
    265                 case ERESTART:
    266                     Assert(fInterruptible);
    267                     if (pThis->cWaiters > 0)
    268                         ASMAtomicDecU32(&pThis->cWaiters);
    269                     rc = VERR_INTERRUPTED;
    270                     break;
    271 
    272                 default:
    273                     AssertMsgFailed(("sleepq_* -> %d\n", rc));
    274                     rc = VERR_GENERAL_FAILURE;
    275                     break;
     216                }
     217                break;
    276218            }
     219
     220            rtR0SemBsdWaitDelete(&Wait);
    277221        }
    278222    }
    279223
    280     RTSpinlockRelease(pThis->hSpinLock, &Tmp);
    281 
     224    rtR0SemEventBsdRelease(pThis);
    282225    return rc;
    283226}
    284227
    285228
    286 RTDECL(int)  RTSemEventWait(RTSEMEVENT hEventSem, RTMSINTERVAL cMillies)
    287 {
    288     return rtSemEventWait(hEventSem, cMillies, false /* not interruptible */);
    289 }
    290 
    291 
    292 RTDECL(int)  RTSemEventWaitNoResume(RTSEMEVENT hEventSem, RTMSINTERVAL cMillies)
    293 {
    294     return rtSemEventWait(hEventSem, cMillies, true /* interruptible */);
    295 }
     229#undef RTSemEventWaitEx
     230RTDECL(int)  RTSemEventWaitEx(RTSEMEVENT hEventSem, uint32_t fFlags, uint64_t uTimeout)
     231{
     232#ifndef RTSEMEVENT_STRICT
     233    return rtR0SemEventWait(hEventSem, fFlags, uTimeout, NULL);
     234#else
     235    RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
     236    return rtR0SemEventWait(hEventSem, fFlags, uTimeout, &SrcPos);
     237#endif
     238}
     239RT_EXPORT_SYMBOL(RTSemEventWaitEx);
     240
     241
     242RTDECL(int)  RTSemEventWaitExDebug(RTSEMEVENT hEventSem, uint32_t fFlags, uint64_t uTimeout,
     243                                   RTHCUINTPTR uId, RT_SRC_POS_DECL)
     244{
     245    RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
     246    return rtR0SemEventWait(hEventSem, fFlags, uTimeout, &SrcPos);
     247}
     248RT_EXPORT_SYMBOL(RTSemEventWaitExDebug);
    296249
    297250
  • trunk/src/VBox/Runtime/r0drv/freebsd/semeventmulti-r0drv-freebsd.c

    r33155 r33376  
    3333*******************************************************************************/
    3434#include "the-freebsd-kernel.h"
    35 
     35#include "internal/iprt.h"
    3636#include <iprt/semaphore.h>
    37 #include <iprt/alloc.h>
     37
     38#include <iprt/assert.h>
    3839#include <iprt/asm.h>
    39 #include <iprt/assert.h>
    4040#include <iprt/err.h>
    41 #include <iprt/spinlock.h>
    42 
     41#include <iprt/mem.h>
     42#include <iprt/lockvalidator.h>
     43
     44#include "sleepqueue-r0drv-freebsd.h"
    4345#include "internal/magics.h"
     46
     47
     48/*******************************************************************************
     49*   Defined Constants And Macros                                               *
     50*******************************************************************************/
     51/** @name fStateAndGen values
     52 * @{ */
     53/** The state bit number. */
     54#define RTSEMEVENTMULTIBSD_STATE_BIT        0
     55/** The state mask. */
     56#define RTSEMEVENTMULTIBSD_STATE_MASK       RT_BIT_32(RTSEMEVENTMULTIBSD_STATE_BIT)
     57/** The generation mask. */
     58#define RTSEMEVENTMULTIBSD_GEN_MASK         ~RTSEMEVENTMULTIBSD_STATE_MASK
     59/** The generation shift. */
     60#define RTSEMEVENTMULTIBSD_GEN_SHIFT        1
     61/** The initial variable value. */
     62#define RTSEMEVENTMULTIBSD_STATE_GEN_INIT   UINT32_C(0xfffffffc)
     63/** @}  */
    4464
    4565/*******************************************************************************
     
    5373    /** Magic value (RTSEMEVENTMULTI_MAGIC). */
    5474    uint32_t volatile   u32Magic;
    55     /** The number of waiting threads. */
    56     uint32_t volatile   cWaiters;
    57     /** Set if the event object is signaled. */
    58     uint8_t volatile    fSignaled;
    59     /** The number of threads in the process of waking up. */
    60     uint32_t volatile   cWaking;
    61     /** Spinlock protecting this structure. */
    62     RTSPINLOCK          hSpinLock;
     75    /** The object state bit and generation counter.
     76     * The generation counter is incremented every time the object is
     77     * signalled. */
     78    uint32_t volatile   fStateAndGen;
     79    /** Reference counter. */
     80    uint32_t volatile   cRefs;
    6381} RTSEMEVENTMULTIINTERNAL, *PRTSEMEVENTMULTIINTERNAL;
    6482
     
    7391                                     const char *pszNameFmt, ...)
    7492{
    75     AssertCompile(sizeof(RTSEMEVENTMULTIINTERNAL) > sizeof(void *));
     93    PRTSEMEVENTMULTIINTERNAL pThis;
     94
    7695    AssertReturn(!(fFlags & ~RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER);
    77     AssertPtrReturn(phEventMultiSem, VERR_INVALID_POINTER);
    78 
    79     PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)RTMemAllocZ(sizeof(*pThis));
     96    pThis = (PRTSEMEVENTMULTIINTERNAL)RTMemAlloc(sizeof(*pThis));
    8097    if (pThis)
    8198    {
    82         pThis->u32Magic = RTSEMEVENTMULTI_MAGIC;
    83         pThis->cWaiters = 0;
    84         pThis->cWaking = 0;
    85         pThis->fSignaled = 0;
    86         int rc = RTSpinlockCreate(&pThis->hSpinLock);
    87         if (RT_SUCCESS(rc))
    88         {
    89             *phEventMultiSem = pThis;
    90             return VINF_SUCCESS;
    91         }
    92 
    93         RTMemFree(pThis);
    94         return rc;
     99        pThis->u32Magic     = RTSEMEVENTMULTI_MAGIC;
     100        pThis->fStateAndGen = RTSEMEVENTMULTIBSD_STATE_GEN_INIT;
     101        pThis->cRefs        = 1;
     102
     103        *phEventMultiSem = pThis;
     104        return VINF_SUCCESS;
    95105    }
    96106    return VERR_NO_MEMORY;
     
    98108
    99109
     110/**
     111 * Retain a reference to the semaphore.
     112 *
     113 * @param   pThis       The semaphore.
     114 */
     115DECLINLINE(void) rtR0SemEventMultiBsdRetain(PRTSEMEVENTMULTIINTERNAL pThis)
     116{
     117    uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
     118    Assert(cRefs && cRefs < 100000);
     119}
     120
     121
     122/**
     123 * Release a reference, destroy the thing if necessary.
     124 *
     125 * @param   pThis       The semaphore.
     126 */
     127DECLINLINE(void) rtR0SemEventMultiBsdRelease(PRTSEMEVENTMULTIINTERNAL pThis)
     128{
     129    if (RT_UNLIKELY(ASMAtomicDecU32(&pThis->cRefs) == 0))
     130    {
     131        Assert(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC);
     132        RTMemFree(pThis);
     133    }
     134}
     135
     136
    100137RTDECL(int)  RTSemEventMultiDestroy(RTSEMEVENTMULTI hEventMultiSem)
    101138{
     139    /*
     140     * Validate input.
     141     */
    102142    PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
    103     RTSPINLOCKTMP            Tmp = RTSPINLOCKTMP_INITIALIZER;
    104 
    105143    if (pThis == NIL_RTSEMEVENTMULTI)
    106144        return VINF_SUCCESS;
    107     AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
    108     AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
    109 
    110     RTSpinlockAcquire(pThis->hSpinLock, &Tmp);
    111     ASMAtomicIncU32(&pThis->u32Magic); /* make the handle invalid */
    112     if (pThis->cWaiters > 0)
     145    AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
     146    AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
     147    Assert(pThis->cRefs > 0);
     148
     149    /*
     150     * Invalidate it and signal the object just in case.
     151     */
     152    ASMAtomicWriteU32(&pThis->u32Magic, ~RTSEMEVENTMULTI_MAGIC);
     153    ASMAtomicAndU32(&pThis->fStateAndGen, RTSEMEVENTMULTIBSD_GEN_MASK);
     154    rtR0SemBsdBroadcast(pThis);
     155    rtR0SemEventMultiBsdRelease(pThis);
     156    return VINF_SUCCESS;
     157}
     158
     159
     160RTDECL(int)  RTSemEventMultiSignal(RTSEMEVENTMULTI hEventMultiSem)
     161{
     162    uint32_t fNew;
     163    uint32_t fOld;
     164
     165    /*
     166     * Validate input.
     167     */
     168    PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
     169    if (!pThis)
     170        return VERR_INVALID_PARAMETER;
     171    AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
     172    AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
     173    rtR0SemEventMultiBsdRetain(pThis);
     174
     175    /*
     176     * Signal the event object.  The cause of the parnoia here is racing to try
     177     * deal with racing RTSemEventMultiSignal calls (should probably be
     178     * forbidden, but it's relatively easy to handle).
     179     */
     180    do
    113181    {
    114         /* abort waiting thread, last man cleans up. */
    115         ASMAtomicXchgU32(&pThis->cWaking, pThis->cWaking + pThis->cWaiters);
    116         sleepq_lock(pThis);
    117         sleepq_broadcast(pThis, SLEEPQ_CONDVAR, 0, 0);
    118         sleepq_release(pThis);
    119         RTSpinlockRelease(pThis->hSpinLock, &Tmp);
     182        fNew = fOld = ASMAtomicUoReadU32(&pThis->fStateAndGen);
     183        fNew += 1 << RTSEMEVENTMULTIBSD_GEN_SHIFT;
     184        fNew |= RTSEMEVENTMULTIBSD_STATE_MASK;
    120185    }
    121     else if (pThis->cWaking)
    122         /* the last waking thread is gonna do the cleanup */
    123         RTSpinlockRelease(pThis->hSpinLock, &Tmp);
    124     else
    125     {
    126         RTSpinlockRelease(pThis->hSpinLock, &Tmp);
    127         RTSpinlockDestroy(pThis->hSpinLock);
    128         RTMemFree(pThis);
    129     }
    130 
     186    while (!ASMAtomicCmpXchgU32(&pThis->fStateAndGen, fNew, fOld));
     187
     188    rtR0SemBsdBroadcast(pThis);
     189    rtR0SemEventMultiBsdRelease(pThis);
    131190    return VINF_SUCCESS;
    132191}
    133192
    134193
    135 RTDECL(int)  RTSemEventMultiSignal(RTSEMEVENTMULTI hEventMultiSem)
    136 {
    137     RTSPINLOCKTMP            Tmp = RTSPINLOCKTMP_INITIALIZER;
     194RTDECL(int)  RTSemEventMultiReset(RTSEMEVENTMULTI hEventMultiSem)
     195{
     196    /*
     197     * Validate input.
     198     */
    138199    PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
    139     AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
    140     AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC,
    141                     ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
    142                     VERR_INVALID_HANDLE);
    143 
    144     RTSpinlockAcquire(pThis->hSpinLock, &Tmp);
    145 
    146     ASMAtomicXchgU8(&pThis->fSignaled, true);
    147     if (pThis->cWaiters > 0)
    148     {
    149         ASMAtomicXchgU32(&pThis->cWaking, pThis->cWaking + pThis->cWaiters);
    150         ASMAtomicXchgU32(&pThis->cWaiters, 0);
    151         sleepq_lock(pThis);
    152         int fWakeupSwapProc = sleepq_signal(pThis, SLEEPQ_CONDVAR, 0, 0);
    153         sleepq_release(pThis);
    154         if (fWakeupSwapProc)
    155             kick_proc0();
    156     }
    157 
    158     RTSpinlockRelease(pThis->hSpinLock, &Tmp);
     200    if (!pThis)
     201        return VERR_INVALID_PARAMETER;
     202    AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
     203    AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
     204    rtR0SemEventMultiBsdRetain(pThis);
     205
     206    /*
     207     * Reset it.
     208     */
     209    ASMAtomicAndU32(&pThis->fStateAndGen, ~RTSEMEVENTMULTIBSD_STATE_MASK);
     210
     211    rtR0SemEventMultiBsdRelease(pThis);
    159212    return VINF_SUCCESS;
    160213}
    161214
    162215
    163 RTDECL(int)  RTSemEventMultiReset(RTSEMEVENTMULTI hEventMultiSem)
    164 {
    165     RTSPINLOCKTMP            Tmp = RTSPINLOCKTMP_INITIALIZER;
    166     PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
    167     AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
    168     AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC,
    169                     ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
    170                     VERR_INVALID_HANDLE);
    171 
    172     RTSpinlockAcquire(pThis->hSpinLock, &Tmp);
    173     ASMAtomicXchgU8(&pThis->fSignaled, false);
    174     RTSpinlockRelease(pThis->hSpinLock, &Tmp);
    175     return VINF_SUCCESS;
    176 }
    177 
    178 
    179 static int rtSemEventMultiWait(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies, bool fInterruptible)
    180 {
    181     int rc;
    182     RTSPINLOCKTMP            Tmp = RTSPINLOCKTMP_INITIALIZER;
    183     PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
    184     AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
    185     AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC,
    186                     ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
    187                     VERR_INVALID_HANDLE);
    188 
    189     RTSpinlockAcquire(pThis->hSpinLock, &Tmp);
    190 
    191     if (pThis->fSignaled)
     216/**
     217 * Worker for RTSemEventMultiWaitEx and RTSemEventMultiWaitExDebug.
     218 *
     219 * @returns VBox status code.
     220 * @param   pThis           The event semaphore.
     221 * @param   fFlags          See RTSemEventMultiWaitEx.
     222 * @param   uTimeout        See RTSemEventMultiWaitEx.
     223 * @param   pSrcPos         The source code position of the wait.
     224 */
     225static int rtR0SemEventMultiBsdWait(PRTSEMEVENTMULTIINTERNAL pThis, uint32_t fFlags, uint64_t uTimeout,
     226                                    PCRTLOCKVALSRCPOS pSrcPos)
     227{
     228    uint32_t    fOrgStateAndGen;
     229    int         rc;
     230
     231    /*
     232     * Validate the input.
     233     */
     234    AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
     235    AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
     236    AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER);
     237    rtR0SemEventMultiBsdRetain(pThis);
     238
     239    /*
     240     * Is the event already signalled or do we have to wait?
     241     */
     242    fOrgStateAndGen = ASMAtomicUoReadU32(&pThis->fStateAndGen);
     243    if (fOrgStateAndGen & RTSEMEVENTMULTIBSD_STATE_MASK)
    192244        rc = VINF_SUCCESS;
    193245    else
    194246    {
    195         if (cMillies == 0)
    196             rc = VERR_TIMEOUT;
    197         else
     247        /*
     248         * We have to wait.
     249         */
     250        RTR0SEMBSDSLEEP Wait;
     251        rc = rtR0SemBsdWaitInit(&Wait, fFlags, uTimeout, pThis);
     252        if (RT_SUCCESS(rc))
    198253        {
    199             ASMAtomicIncU32(&pThis->cWaiters);
    200 
    201             int fFlags = SLEEPQ_CONDVAR;
    202 
    203             if (fInterruptible)
    204                 fFlags |= SLEEPQ_INTERRUPTIBLE;
    205 
    206             sleepq_lock(pThis);
    207             sleepq_add(pThis, NULL, "IPRT Event Semaphore", fFlags, 0);
    208 
    209             if (cMillies != RT_INDEFINITE_WAIT)
     254            for (;;)
    210255            {
    211                 /*
    212                  * Translate milliseconds into ticks and go to sleep.
    213                  */
    214                 struct timeval tv;
    215 
    216                 tv.tv_sec = cMillies / 1000;
    217                 tv.tv_usec = (cMillies % 1000) * 1000;
    218 
    219                 sleepq_set_timeout(pThis, tvtohz(&tv));
    220 
    221                 RTSpinlockRelease(pThis->hSpinLock, &Tmp);
    222 
    223                 if (fInterruptible)
    224                     rc = SLEEPQ_TIMEDWAIT_SIG(pThis);
    225                 else
    226                     rc = SLEEPQ_TIMEDWAIT(pThis);
    227             }
    228             else
    229             {
    230                 RTSpinlockRelease(pThis->hSpinLock, &Tmp);
    231 
    232                 if (fInterruptible)
    233                     rc = SLEEPQ_WAIT_SIG(pThis);
     256                /* The destruction test. */
     257                if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC))
     258                    rc = VERR_SEM_DESTROYED;
    234259                else
    235260                {
    236                     rc = 0;
    237                     SLEEPQ_WAIT(pThis);
    238                 }
    239             }
    240 
    241             RTSpinlockAcquire(pThis->hSpinLock, &Tmp);
    242 
    243             switch (rc)
    244             {
    245                 case 0:
    246                     if (pThis->u32Magic == RTSEMEVENTMULTI_MAGIC)
    247                     {
    248                         ASMAtomicDecU32(&pThis->cWaking);
     261                    rtR0SemBsdWaitPrepare(&Wait);
     262
     263                    /* Check the exit conditions. */
     264                    if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC))
     265                        rc = VERR_SEM_DESTROYED;
     266                    else if (ASMAtomicUoReadU32(&pThis->fStateAndGen) != fOrgStateAndGen)
    249267                        rc = VINF_SUCCESS;
    250                     }
     268                    else if (rtR0SemBsdWaitHasTimedOut(&Wait))
     269                        rc = VERR_TIMEOUT;
     270                    else if (rtR0SemBsdWaitWasInterrupted(&Wait))
     271                        rc = VERR_INTERRUPTED;
    251272                    else
    252273                    {
    253                         rc = VERR_SEM_DESTROYED; /** @todo this isn't necessarily correct, we've
    254                                                   * could've woken up just before destruction... */
    255                         if (!ASMAtomicDecU32(&pThis->cWaking))
    256                         {
    257                             /* The event was destroyed, as the last thread do the cleanup.
    258                                we don't actually know whether */
    259                             RTSpinlockRelease(pThis->hSpinLock, &Tmp);
    260                             RTSpinlockDestroy(pThis->hSpinLock);
    261                             RTMemFree(pThis);
    262                             return rc;
    263                         }
     274                        /* Do the wait and then recheck the conditions. */
     275                        rtR0SemBsdWaitDoIt(&Wait);
     276                        continue;
    264277                    }
    265                     break;
    266 
    267                 case EWOULDBLOCK:
    268                     Assert(cMillies != RT_INDEFINITE_WAIT);
    269                     if (pThis->cWaiters > 0)
    270                         ASMAtomicDecU32(&pThis->cWaiters);
    271                     rc = VERR_TIMEOUT;
    272                     break;
    273 
    274                 case EINTR:
    275                 case ERESTART:
    276                     Assert(fInterruptible);
    277                     if (pThis->cWaiters > 0)
    278                         ASMAtomicDecU32(&pThis->cWaiters);
    279                     rc = VERR_INTERRUPTED;
    280                     break;
    281 
    282                 default:
    283                     AssertMsgFailed(("sleepq_* -> %d\n", rc));
    284                     rc = VERR_GENERAL_FAILURE;
    285                     break;
     278                }
     279                break;
    286280            }
     281
     282            rtR0SemBsdWaitDelete(&Wait);
    287283        }
    288284    }
    289285
    290     RTSpinlockRelease(pThis->hSpinLock, &Tmp);
     286    rtR0SemEventMultiBsdRelease(pThis);
    291287    return rc;
    292288}
    293289
    294290
    295 RTDECL(int)  RTSemEventMultiWait(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies)
    296 {
    297     return rtSemEventMultiWait(hEventMultiSem, cMillies, false /* not interruptible */);
    298 }
    299 
    300 
    301 RTDECL(int)  RTSemEventMultiWaitNoResume(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies)
    302 {
    303     return rtSemEventMultiWait(hEventMultiSem, cMillies, true /* interruptible */);
    304 }
     291#undef RTSemEventMultiWaitEx
     292RTDECL(int)  RTSemEventMultiWaitEx(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout)
     293{
     294#ifndef RTSEMEVENT_STRICT
     295    return rtR0SemEventMultiBsdWait(hEventMultiSem, fFlags, uTimeout, NULL);
     296#else
     297    RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
     298    return rtR0SemEventMultiBsdWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
     299#endif
     300}
     301RT_EXPORT_SYMBOL(RTSemEventMultiWaitEx);
     302
     303
     304RTDECL(int)  RTSemEventMultiWaitExDebug(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout,
     305                                        RTHCUINTPTR uId, RT_SRC_POS_DECL)
     306{
     307    RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
     308    return rtR0SemEventMultiBsdWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
     309}
     310RT_EXPORT_SYMBOL(RTSemEventMultiWaitExDebug);
    305311
    306312
    307313RTDECL(uint32_t) RTSemEventMultiGetResolution(void)
    308314{
    309     return 1000000000 / hz;
    310 }
    311 
     315    return rtR0SemBsdWaitGetResolution();
     316}
     317RT_EXPORT_SYMBOL(RTSemEventMultiGetResolution);
     318
Note: See TracChangeset for help on using the changeset viewer.

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