VirtualBox

Changeset 22582 in vbox


Ignore:
Timestamp:
Aug 30, 2009 8:47:57 PM (15 years ago)
Author:
vboxsync
Message:

Runtime/semevent{multi}-r0drv-freebsd:

Replace spin/default mutexes with sleep queues and
our spinlock implementation and unify the code
of both variants.
Spin mutexes can't be interrupted because they
disable interrupts and default mutexes.
Fixes panics if the kernel is compiled with WITNESS and INVARIANTS.

Location:
trunk/src/VBox/Runtime/r0drv/freebsd
Files:
2 edited

Legend:

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

    r20448 r22582  
    3939#include <iprt/assert.h>
    4040#include <iprt/err.h>
     41#include <iprt/spinlock.h>
    4142
    4243#include "internal/magics.h"
     
    5960    /** The number of threads in the process of waking up. */
    6061    uint32_t volatile   cWaking;
    61     /** The FreeBSD spinlock protecting this structure. */
    62     struct mtx          Mtx;
     62    /** Spinlock protecting this structure. */
     63    RTSPINLOCK          hSpinLock;
    6364} RTSEMEVENTINTERNAL, *PRTSEMEVENTINTERNAL;
    6465
     
    7677        pEventInt->cWaking = 0;
    7778        pEventInt->fSignaled = 0;
    78         mtx_init(&pEventInt->Mtx, "IPRT Event Semaphore", NULL, 0);
    79         *pEventSem = pEventInt;
    80         return VINF_SUCCESS;
     79        int rc = RTSpinlockCreate(&pEventInt->hSpinLock);
     80        if (RT_SUCCESS(rc))
     81        {
     82            *pEventSem = pEventInt;
     83            return VINF_SUCCESS;
     84        }
     85
     86        RTMemFree(pEventInt);
     87        return rc;
    8188    }
    8289    return VERR_NO_MEMORY;
     
    8895    if (EventSem == NIL_RTSEMEVENT)     /* don't bitch */
    8996        return VERR_INVALID_HANDLE;
     97    PRTSEMEVENTINTERNAL pEventInt = (PRTSEMEVENTINTERNAL)EventSem;
     98    RTSPINLOCKTMP Tmp;
     99
     100    AssertPtrReturn(pEventInt, VERR_INVALID_HANDLE);
     101    AssertMsgReturn(pEventInt->u32Magic == RTSEMEVENT_MAGIC,
     102                    ("pEventInt=%p u32Magic=%#x\n", pEventInt, pEventInt->u32Magic),
     103                    VERR_INVALID_HANDLE);
     104
     105    RTSpinlockAcquire(pEventInt->hSpinLock, &Tmp);
     106
     107    ASMAtomicIncU32(&pEventInt->u32Magic); /* make the handle invalid */
     108    if (pEventInt->cWaiters > 0)
     109    {
     110        /* abort waiting thread, last man cleans up. */
     111        ASMAtomicXchgU32(&pEventInt->cWaking, pEventInt->cWaking + pEventInt->cWaiters);
     112        sleepq_lock(pEventInt);
     113        sleepq_broadcast(pEventInt, SLEEPQ_CONDVAR, 0, 0);
     114        sleepq_release(pEventInt);
     115        RTSpinlockRelease(pEventInt->hSpinLock, &Tmp);
     116    }
     117    else if (pEventInt->cWaking)
     118        /* the last waking thread is gonna do the cleanup */
     119        RTSpinlockRelease(pEventInt->hSpinLock, &Tmp);
     120    else
     121    {
     122        RTSpinlockRelease(pEventInt->hSpinLock, &Tmp);
     123        RTSpinlockDestroy(pEventInt->hSpinLock);
     124        RTMemFree(pEventInt);
     125    }
     126
     127    return VINF_SUCCESS;
     128}
     129
     130
     131RTDECL(int)  RTSemEventSignal(RTSEMEVENT EventSem)
     132{
     133    RTSPINLOCKTMP       Tmp;
    90134    PRTSEMEVENTINTERNAL pEventInt = (PRTSEMEVENTINTERNAL)EventSem;
    91135    AssertPtrReturn(pEventInt, VERR_INVALID_HANDLE);
     
    94138                    VERR_INVALID_HANDLE);
    95139
    96     mtx_lock(&pEventInt->Mtx);
    97     ASMAtomicIncU32(&pEventInt->u32Magic); /* make the handle invalid */
     140    RTSpinlockAcquire(pEventInt->hSpinLock, &Tmp);
     141
    98142    if (pEventInt->cWaiters > 0)
    99143    {
    100         /* abort waiting thread, last man cleans up. */
    101         ASMAtomicXchgU32(&pEventInt->cWaking, pEventInt->cWaking + pEventInt->cWaiters);
    102         wakeup(pEventInt);
    103         mtx_unlock(&pEventInt->Mtx);
    104     }
    105     else if (pEventInt->cWaking)
    106         /* the last waking thread is gonna do the cleanup */
    107         mtx_unlock(&pEventInt->Mtx);
     144        ASMAtomicDecU32(&pEventInt->cWaiters);
     145        ASMAtomicIncU32(&pEventInt->cWaking);
     146        sleepq_lock(pEventInt);
     147        int fWakeupSwapProc = sleepq_signal(pEventInt, SLEEPQ_CONDVAR, 0, 0);
     148        sleepq_release(pEventInt);
     149        if (fWakeupSwapProc)
     150            kick_proc0();
     151    }
    108152    else
    109     {
    110         mtx_unlock(&pEventInt->Mtx);
    111         mtx_destroy(&pEventInt->Mtx);
    112         RTMemFree(pEventInt);
    113     }
    114 
     153        ASMAtomicXchgU8(&pEventInt->fSignaled, true);
     154
     155    RTSpinlockRelease(pEventInt->hSpinLock, &Tmp);
    115156    return VINF_SUCCESS;
    116157}
    117158
    118159
    119 RTDECL(int)  RTSemEventSignal(RTSEMEVENT EventSem)
    120 {
     160static int rtSemEventWait(RTSEMEVENT EventSem, unsigned cMillies, bool fInterruptible)
     161{
     162    int rc;
     163    RTSPINLOCKTMP       Tmp;
    121164    PRTSEMEVENTINTERNAL pEventInt = (PRTSEMEVENTINTERNAL)EventSem;
    122165    AssertPtrReturn(pEventInt, VERR_INVALID_HANDLE);
     
    125168                    VERR_INVALID_HANDLE);
    126169
    127     mtx_lock(&pEventInt->Mtx);
    128 
    129     if (pEventInt->cWaiters > 0)
    130     {
    131         ASMAtomicDecU32(&pEventInt->cWaiters);
    132         ASMAtomicIncU32(&pEventInt->cWaking);
    133         wakeup_one(pEventInt);
    134     }
    135     else
    136         ASMAtomicXchgU8(&pEventInt->fSignaled, true);
    137 
    138     mtx_unlock(&pEventInt->Mtx);
    139     return VINF_SUCCESS;
    140 }
    141 
    142 
    143 static int rtSemEventWait(RTSEMEVENT EventSem, unsigned cMillies, bool fInterruptible)
    144 {
    145     int rc;
    146     PRTSEMEVENTINTERNAL pEventInt = (PRTSEMEVENTINTERNAL)EventSem;
    147     AssertPtrReturn(pEventInt, VERR_INVALID_HANDLE);
    148     AssertMsgReturn(pEventInt->u32Magic == RTSEMEVENT_MAGIC,
    149                     ("pEventInt=%p u32Magic=%#x\n", pEventInt, pEventInt->u32Magic),
    150                     VERR_INVALID_HANDLE);
    151 
    152     mtx_lock(&pEventInt->Mtx);
     170    RTSpinlockAcquire(pEventInt->hSpinLock, &Tmp);
    153171
    154172    if (pEventInt->fSignaled)
     
    160178    else
    161179    {
    162         /*
    163          * Translate milliseconds into ticks and go to sleep.
    164          */
    165         struct timeval tv;
    166 
    167         if (cMillies != RT_INDEFINITE_WAIT)
     180        if (cMillies == 0)
     181            rc = VERR_TIMEOUT;
     182        else
    168183        {
    169             tv.tv_sec = cMillies / 1000;
    170             tv.tv_usec = (cMillies % 1000) * 1000;
    171         }
    172 
    173         ASMAtomicIncU32(&pEventInt->cWaiters);
    174 
    175         /** @todo r=bird: This doesn't handle cMillies == 0 correctly, it will assert
    176          *        and or sleep for ever according to r47861. (That's probably an old bug
    177          *        of my making.)
    178          */
    179         rc = mtx_sleep(pEventInt,          /* block id */
    180                        &pEventInt->Mtx,    /* mtx */
    181                        fInterruptible ? PZERO | PCATCH : PZERO,
    182                        "iprtev",           /* max 6 chars */
    183                        cMillies == RT_INDEFINITE_WAIT
    184                        ? 0
    185                        : tvtohz(&tv));
    186 
    187         switch (rc)
    188         {
    189             case 0:
    190                 if (pEventInt->u32Magic == RTSEMEVENT_MAGIC)
    191                 {
    192                     ASMAtomicDecU32(&pEventInt->cWaking);
    193                     rc = VINF_SUCCESS;
    194                 }
     184            ASMAtomicIncU32(&pEventInt->cWaiters);
     185
     186            int fFlags = SLEEPQ_CONDVAR;
     187
     188            if (fInterruptible)
     189                fFlags |= SLEEPQ_INTERRUPTIBLE;
     190
     191            sleepq_lock(pEventInt);
     192            sleepq_add(pEventInt, NULL, "IPRT Event Semaphore", fFlags, 0);
     193
     194            if (cMillies != RT_INDEFINITE_WAIT)
     195            {
     196                /*
     197                 * Translate milliseconds into ticks and go to sleep.
     198                 */
     199                struct timeval tv;
     200
     201                tv.tv_sec = cMillies / 1000;
     202                tv.tv_usec = (cMillies % 1000) * 1000;
     203
     204                sleepq_set_timeout(pEventInt, tvtohz(&tv));
     205
     206                RTSpinlockRelease(pEventInt->hSpinLock, &Tmp);
     207
     208                if (fInterruptible)
     209                    rc = sleepq_timedwait_sig(pEventInt, 0);
     210                else
     211                    rc = sleepq_timedwait(pEventInt, 0);
     212            }
     213            else
     214            {
     215                RTSpinlockRelease(pEventInt->hSpinLock, &Tmp);
     216
     217                if (fInterruptible)
     218                    rc = sleepq_wait_sig(pEventInt, 0);
    195219                else
    196220                {
    197                     rc = VERR_SEM_DESTROYED; /** @todo this isn't necessarily correct, we've
    198                                               * could've woken up just before destruction... */
    199                     if (!ASMAtomicDecU32(&pEventInt->cWaking))
     221                    rc = 0;
     222                    sleepq_wait(pEventInt, 0);
     223                }
     224            }
     225
     226            RTSpinlockAcquire(pEventInt->hSpinLock, &Tmp);
     227
     228            switch (rc)
     229            {
     230                case 0:
     231                    if (pEventInt->u32Magic == RTSEMEVENT_MAGIC)
    200232                    {
    201                         /* The event was destroyed, as the last thread do the cleanup.
    202                            we don't actually know whether */
    203                         mtx_unlock(&pEventInt->Mtx);
    204                         mtx_destroy(&pEventInt->Mtx);
    205                         RTMemFree(pEventInt);
    206                         return rc;
     233                        ASMAtomicDecU32(&pEventInt->cWaking);
     234                        rc = VINF_SUCCESS;
    207235                    }
    208                 }
    209                 break;
    210 
    211             case EWOULDBLOCK:
    212                 Assert(cMillies != RT_INDEFINITE_WAIT);
    213                 if (pEventInt->cWaiters > 0)
    214                     ASMAtomicDecU32(&pEventInt->cWaiters);
    215                 rc = VERR_TIMEOUT;
    216                 break;
    217 
    218             case EINTR:
    219             case ERESTART:
    220                 Assert(fInterruptible);
    221                 if (pEventInt->cWaiters > 0)
    222                     ASMAtomicDecU32(&pEventInt->cWaiters);
    223                 rc = VERR_INTERRUPTED;
    224                 break;
    225 
    226             default:
    227                 AssertMsgFailed(("tsleep -> %d\n", rc));
    228                 rc = VERR_GENERAL_FAILURE;
    229                 break;
     236                    else
     237                    {
     238                        rc = VERR_SEM_DESTROYED; /** @todo this isn't necessarily correct, we've
     239                                                  * could've woken up just before destruction... */
     240                        if (!ASMAtomicDecU32(&pEventInt->cWaking))
     241                        {
     242                            /* The event was destroyed, as the last thread do the cleanup.
     243                               we don't actually know whether */
     244                            RTSpinlockRelease(pEventInt->hSpinLock, &Tmp);
     245                            RTSpinlockDestroy(pEventInt->hSpinLock);
     246                            RTMemFree(pEventInt);
     247                            return rc;
     248                        }
     249                    }
     250                    break;
     251
     252                case EWOULDBLOCK:
     253                    Assert(cMillies != RT_INDEFINITE_WAIT);
     254                    if (pEventInt->cWaiters > 0)
     255                        ASMAtomicDecU32(&pEventInt->cWaiters);
     256                    rc = VERR_TIMEOUT;
     257                    break;
     258
     259                case EINTR:
     260                case ERESTART:
     261                    Assert(fInterruptible);
     262                    if (pEventInt->cWaiters > 0)
     263                        ASMAtomicDecU32(&pEventInt->cWaiters);
     264                    rc = VERR_INTERRUPTED;
     265                    break;
     266
     267                default:
     268                    AssertMsgFailed(("sleepq_* -> %d\n", rc));
     269                    rc = VERR_GENERAL_FAILURE;
     270                    break;
     271            }
    230272        }
    231273    }
    232274
    233     mtx_unlock(&pEventInt->Mtx);
     275    RTSpinlockRelease(pEventInt->hSpinLock, &Tmp);
     276
    234277    return rc;
    235278}
  • trunk/src/VBox/Runtime/r0drv/freebsd/semeventmulti-r0drv-freebsd.c

    r19565 r22582  
    3939#include <iprt/assert.h>
    4040#include <iprt/err.h>
     41#include <iprt/spinlock.h>
    4142
    4243#include "internal/magics.h"
     
    5960    /** The number of threads in the process of waking up. */
    6061    uint32_t volatile   cWaking;
    61     /** The FreeBSD spinlock protecting this structure. */
    62     struct mtx          Mtx;
     62    /** Spinlock protecting this structure. */
     63    RTSPINLOCK          hSpinLock;
    6364} RTSEMEVENTMULTIINTERNAL, *PRTSEMEVENTMULTIINTERNAL;
    6465
     
    7677        pEventMultiInt->cWaking = 0;
    7778        pEventMultiInt->fSignaled = 0;
    78         mtx_init(&pEventMultiInt->Mtx, "IPRT Multiple Release Event Semaphore", NULL, MTX_SPIN);
    79         *pEventMultiSem = pEventMultiInt;
    80         return VINF_SUCCESS;
     79        int rc = RTSpinlockCreate(&pEventMultiInt->hSpinLock);
     80        if (RT_SUCCESS(rc))
     81        {
     82            *pEventMultiSem = pEventMultiInt;
     83            return VINF_SUCCESS;
     84        }
     85
     86        RTMemFree(pEventMultiInt);
     87        return rc;
    8188    }
    8289    return VERR_NO_MEMORY;
     
    8895    if (EventMultiSem == NIL_RTSEMEVENTMULTI)     /* don't bitch */
    8996        return VERR_INVALID_HANDLE;
     97    PRTSEMEVENTMULTIINTERNAL pEventMultiInt = (PRTSEMEVENTMULTIINTERNAL)EventMultiSem;
     98    RTSPINLOCKTMP            Tmp;
     99
     100    AssertPtrReturn(pEventMultiInt, VERR_INVALID_HANDLE);
     101    AssertMsgReturn(pEventMultiInt->u32Magic == RTSEMEVENTMULTI_MAGIC,
     102                    ("pEventMultiInt=%p u32Magic=%#x\n", pEventMultiInt, pEventMultiInt->u32Magic),
     103                    VERR_INVALID_HANDLE);
     104
     105    RTSpinlockAcquire(pEventMultiInt->hSpinLock, &Tmp);
     106    ASMAtomicIncU32(&pEventMultiInt->u32Magic); /* make the handle invalid */
     107    if (pEventMultiInt->cWaiters > 0)
     108    {
     109        /* abort waiting thread, last man cleans up. */
     110        ASMAtomicXchgU32(&pEventMultiInt->cWaking, pEventMultiInt->cWaking + pEventMultiInt->cWaiters);
     111        sleepq_lock(pEventMultiInt);
     112        sleepq_broadcast(pEventMultiInt, SLEEPQ_CONDVAR, 0, 0);
     113        sleepq_release(pEventMultiInt);
     114        RTSpinlockRelease(pEventMultiInt->hSpinLock, &Tmp);
     115    }
     116    else if (pEventMultiInt->cWaking)
     117        /* the last waking thread is gonna do the cleanup */
     118        RTSpinlockRelease(pEventMultiInt->hSpinLock, &Tmp);
     119    else
     120    {
     121        RTSpinlockRelease(pEventMultiInt->hSpinLock, &Tmp);
     122        RTSpinlockDestroy(pEventMultiInt->hSpinLock);
     123        RTMemFree(pEventMultiInt);
     124    }
     125
     126    return VINF_SUCCESS;
     127}
     128
     129
     130RTDECL(int)  RTSemEventMultiSignal(RTSEMEVENTMULTI EventMultiSem)
     131{
     132    RTSPINLOCKTMP            Tmp;
    90133    PRTSEMEVENTMULTIINTERNAL pEventMultiInt = (PRTSEMEVENTMULTIINTERNAL)EventMultiSem;
    91134    AssertPtrReturn(pEventMultiInt, VERR_INVALID_HANDLE);
     
    94137                    VERR_INVALID_HANDLE);
    95138
    96     mtx_lock_spin(&pEventMultiInt->Mtx);
    97     ASMAtomicIncU32(&pEventMultiInt->u32Magic); /* make the handle invalid */
     139    RTSpinlockAcquire(pEventMultiInt->hSpinLock, &Tmp);
     140
     141    ASMAtomicXchgU8(&pEventMultiInt->fSignaled, true);
    98142    if (pEventMultiInt->cWaiters > 0)
    99143    {
    100         /* abort waiting thread, last man cleans up. */
    101144        ASMAtomicXchgU32(&pEventMultiInt->cWaking, pEventMultiInt->cWaking + pEventMultiInt->cWaiters);
    102         wakeup(pEventMultiInt);
    103         mtx_unlock_spin(&pEventMultiInt->Mtx);
    104     }
    105     else if (pEventMultiInt->cWaking)
    106         /* the last waking thread is gonna do the cleanup */
    107         mtx_unlock_spin(&pEventMultiInt->Mtx);
    108     else
    109     {
    110         mtx_unlock_spin(&pEventMultiInt->Mtx);
    111         mtx_destroy(&pEventMultiInt->Mtx);
    112         RTMemFree(pEventMultiInt);
    113     }
    114 
     145        ASMAtomicXchgU32(&pEventMultiInt->cWaiters, 0);
     146        sleepq_lock(pEventMultiInt);
     147        int fWakeupSwapProc = sleepq_signal(pEventMultiInt, SLEEPQ_CONDVAR, 0, 0);
     148        sleepq_release(pEventMultiInt);
     149        if (fWakeupSwapProc)
     150            kick_proc0();
     151    }
     152
     153    RTSpinlockRelease(pEventMultiInt->hSpinLock, &Tmp);
    115154    return VINF_SUCCESS;
    116155}
    117156
    118157
    119 RTDECL(int)  RTSemEventMultiSignal(RTSEMEVENTMULTI EventMultiSem)
    120 {
     158RTDECL(int)  RTSemEventMultiReset(RTSEMEVENTMULTI EventMultiSem)
     159{
     160    RTSPINLOCKTMP            Tmp;
    121161    PRTSEMEVENTMULTIINTERNAL pEventMultiInt = (PRTSEMEVENTMULTIINTERNAL)EventMultiSem;
    122162    AssertPtrReturn(pEventMultiInt, VERR_INVALID_HANDLE);
     
    125165                    VERR_INVALID_HANDLE);
    126166
    127     mtx_lock_spin(&pEventMultiInt->Mtx);
    128 
    129     ASMAtomicXchgU8(&pEventMultiInt->fSignaled, true);
    130     if (pEventMultiInt->cWaiters > 0)
    131     {
    132         ASMAtomicXchgU32(&pEventMultiInt->cWaking, pEventMultiInt->cWaking + pEventMultiInt->cWaiters);
    133         ASMAtomicXchgU32(&pEventMultiInt->cWaiters, 0);
    134         wakeup(pEventMultiInt);
    135     }
    136 
    137     mtx_unlock_spin(&pEventMultiInt->Mtx);
     167    RTSpinlockAcquire(pEventMultiInt->hSpinLock, &Tmp);
     168    ASMAtomicXchgU8(&pEventMultiInt->fSignaled, false);
     169    RTSpinlockRelease(pEventMultiInt->hSpinLock, &Tmp);
    138170    return VINF_SUCCESS;
    139171}
    140172
    141173
    142 RTDECL(int)  RTSemEventMultiReset(RTSEMEVENTMULTI EventMultiSem)
    143 {
     174static int rtSemEventMultiWait(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies, bool fInterruptible)
     175{
     176    int rc;
     177    RTSPINLOCKTMP            Tmp;
    144178    PRTSEMEVENTMULTIINTERNAL pEventMultiInt = (PRTSEMEVENTMULTIINTERNAL)EventMultiSem;
    145179    AssertPtrReturn(pEventMultiInt, VERR_INVALID_HANDLE);
     
    148182                    VERR_INVALID_HANDLE);
    149183
    150     mtx_lock_spin(&pEventMultiInt->Mtx);
    151     ASMAtomicXchgU8(&pEventMultiInt->fSignaled, false);
    152     mtx_unlock_spin(&pEventMultiInt->Mtx);
    153     return VINF_SUCCESS;
    154 }
    155 
    156 
    157 static int rtSemEventMultiWait(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies, bool fInterruptible)
    158 {
    159     int rc;
    160     PRTSEMEVENTMULTIINTERNAL pEventMultiInt = (PRTSEMEVENTMULTIINTERNAL)EventMultiSem;
    161     AssertPtrReturn(pEventMultiInt, VERR_INVALID_HANDLE);
    162     AssertMsgReturn(pEventMultiInt->u32Magic == RTSEMEVENTMULTI_MAGIC,
    163                     ("pEventMultiInt=%p u32Magic=%#x\n", pEventMultiInt, pEventMultiInt->u32Magic),
    164                     VERR_INVALID_HANDLE);
    165 
    166     mtx_lock_spin(&pEventMultiInt->Mtx);
     184    RTSpinlockAcquire(pEventMultiInt->hSpinLock, &Tmp);
    167185
    168186    if (pEventMultiInt->fSignaled)
     
    170188    else
    171189    {
    172         /*
    173          * Translate milliseconds into ticks and go to sleep.
    174          */
    175         int cTicks;
    176         if (cMillies != RT_INDEFINITE_WAIT)
     190        if (cMillies == 0)
     191            rc = VERR_TIMEOUT;
     192        else
    177193        {
    178             if (hz == 1000)
    179                 cTicks = cMillies;
    180             else if (hz == 100)
    181                 cTicks = cMillies / 10;
     194            ASMAtomicIncU32(&pEventMultiInt->cWaiters);
     195
     196            int fFlags = SLEEPQ_CONDVAR;
     197
     198            if (fInterruptible)
     199                fFlags |= SLEEPQ_INTERRUPTIBLE;
     200
     201            sleepq_lock(pEventMultiInt);
     202            sleepq_add(pEventMultiInt, NULL, "IPRT Event Semaphore", fFlags, 0);
     203
     204            if (cMillies != RT_INDEFINITE_WAIT)
     205            {
     206                /*
     207                 * Translate milliseconds into ticks and go to sleep.
     208                 */
     209                struct timeval tv;
     210
     211                tv.tv_sec = cMillies / 1000;
     212                tv.tv_usec = (cMillies % 1000) * 1000;
     213
     214                sleepq_set_timeout(pEventMultiInt, tvtohz(&tv));
     215
     216                RTSpinlockRelease(pEventMultiInt->hSpinLock, &Tmp);
     217
     218                if (fInterruptible)
     219                    rc = sleepq_timedwait_sig(pEventMultiInt, 0);
     220                else
     221                    rc = sleepq_timedwait(pEventMultiInt, 0);
     222            }
    182223            else
    183224            {
    184                 int64_t cTicks64 = ((uint64_t)cMillies * hz) / 1000;
    185                 cTicks = (int)cTicks64;
    186                 if (cTicks != cTicks64)
    187                     cTicks = INT_MAX;
     225                RTSpinlockRelease(pEventMultiInt->hSpinLock, &Tmp);
     226
     227                if (fInterruptible)
     228                    rc = sleepq_wait_sig(pEventMultiInt, 0);
     229                else
     230                {
     231                    rc = 0;
     232                    sleepq_wait(pEventMultiInt, 0);
     233                }
     234            }
     235
     236            RTSpinlockAcquire(pEventMultiInt->hSpinLock, &Tmp);
     237
     238            switch (rc)
     239            {
     240                case 0:
     241                    if (pEventMultiInt->u32Magic == RTSEMEVENTMULTI_MAGIC)
     242                    {
     243                        ASMAtomicDecU32(&pEventMultiInt->cWaking);
     244                        rc = VINF_SUCCESS;
     245                    }
     246                    else
     247                    {
     248                        rc = VERR_SEM_DESTROYED; /** @todo this isn't necessarily correct, we've
     249                                                  * could've woken up just before destruction... */
     250                        if (!ASMAtomicDecU32(&pEventMultiInt->cWaking))
     251                        {
     252                            /* The event was destroyed, as the last thread do the cleanup.
     253                               we don't actually know whether */
     254                            RTSpinlockRelease(pEventMultiInt->hSpinLock, &Tmp);
     255                            RTSpinlockDestroy(pEventMultiInt->hSpinLock);
     256                            RTMemFree(pEventMultiInt);
     257                            return rc;
     258                        }
     259                    }
     260                    break;
     261
     262                case EWOULDBLOCK:
     263                    Assert(cMillies != RT_INDEFINITE_WAIT);
     264                    if (pEventMultiInt->cWaiters > 0)
     265                        ASMAtomicDecU32(&pEventMultiInt->cWaiters);
     266                    rc = VERR_TIMEOUT;
     267                    break;
     268
     269                case EINTR:
     270                case ERESTART:
     271                    Assert(fInterruptible);
     272                    if (pEventMultiInt->cWaiters > 0)
     273                        ASMAtomicDecU32(&pEventMultiInt->cWaiters);
     274                    rc = VERR_INTERRUPTED;
     275                    break;
     276
     277                default:
     278                    AssertMsgFailed(("sleepq_* -> %d\n", rc));
     279                    rc = VERR_GENERAL_FAILURE;
     280                    break;
    188281            }
    189282        }
    190         else
    191             cTicks = 0;
    192 
    193         ASMAtomicIncU32(&pEventMultiInt->cWaiters);
    194 
    195         rc = msleep_spin(pEventMultiInt,     /* block id */
    196                          &pEventMultiInt->Mtx,
    197                          //fInterruptible ? PZERO | PCATCH : PZERO,
    198                          "iprte",           /* max 6 chars */
    199                          cTicks);
    200         switch (rc)
    201         {
    202             case 0:
    203                 if (pEventMultiInt->u32Magic == RTSEMEVENTMULTI_MAGIC)
    204                 {
    205                     ASMAtomicDecU32(&pEventMultiInt->cWaking);
    206                     rc = VINF_SUCCESS;
    207                 }
    208                 else
    209                 {
    210                     rc = VERR_SEM_DESTROYED; /** @todo this isn't necessarily correct, we've
    211                                               * could've woken up just before destruction... */
    212                     if (!ASMAtomicDecU32(&pEventMultiInt->cWaking))
    213                     {
    214                         /* The event was destroyed, as the last thread do the cleanup.
    215                            we don't actually know whether */
    216                         mtx_unlock_spin(&pEventMultiInt->Mtx);
    217                         mtx_destroy(&pEventMultiInt->Mtx);
    218                         RTMemFree(pEventMultiInt);
    219                         return rc;
    220                     }
    221                 }
    222                 break;
    223 
    224             case EWOULDBLOCK:
    225                 Assert(cMillies != RT_INDEFINITE_WAIT);
    226                 if (pEventMultiInt->cWaiters > 0)
    227                     ASMAtomicDecU32(&pEventMultiInt->cWaiters);
    228                 rc = VERR_TIMEOUT;
    229                 break;
    230 
    231             case EINTR:
    232             case ERESTART:
    233                 Assert(fInterruptible);
    234                 if (pEventMultiInt->cWaiters > 0)
    235                     ASMAtomicDecU32(&pEventMultiInt->cWaiters);
    236                 rc = VERR_INTERRUPTED;
    237                 break;
    238 
    239             default:
    240                 AssertMsgFailed(("msleep -> %d\n", rc));
    241                 rc = VERR_GENERAL_FAILURE;
    242                 break;
    243         }
    244     }
    245 
    246     mtx_unlock_spin(&pEventMultiInt->Mtx);
     283    }
     284
     285    RTSpinlockRelease(pEventMultiInt->hSpinLock, &Tmp);
    247286    return rc;
    248287}
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