VirtualBox

Changeset 33042 in vbox for trunk/src/VBox/Runtime


Ignore:
Timestamp:
Oct 11, 2010 3:55:26 PM (14 years ago)
Author:
vboxsync
Message:

IPRT: Implemented RTSemEventMultiWaitEx* for r0drv darwin.

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

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/Makefile.kmk

    r33038 r33042  
    15101510        darwin/RTErrConvertFromDarwinKern.cpp \
    15111511        generic/RTAssertShouldPanic-generic.cpp \
     1512        generic/RTSemEventMultiWait-2-ex-generic.cpp \
     1513        generic/RTSemEventMultiWaitNoResume-2-ex-generic.cpp \
    15121514        generic/RTTimerCreate-generic.cpp \
    15131515        generic/mppresent-generic.cpp \
  • trunk/src/VBox/Runtime/r0drv/darwin/semeventmulti-r0drv-darwin.cpp

    r29255 r33042  
    3939#endif
    4040#include <iprt/err.h>
     41#include <iprt/lockvalidator.h>
    4142#include <iprt/mem.h>
    4243#include <iprt/mp.h>
    4344#include <iprt/thread.h>
     45#include <iprt/time.h>
    4446
    4547#include "internal/magics.h"
     48
     49
     50/*******************************************************************************
     51*   Defined Constants And Macros                                               *
     52*******************************************************************************/
     53/** @name fStateAndGen values
     54 * @{ */
     55/** The state bit number. */
     56#define RTSEMEVENTMULTIDARWIN_STATE_BIT         0
     57/** The state mask. */
     58#define RTSEMEVENTMULTIDARWIN_STATE_MASK        RT_BIT_32(RTSEMEVENTMULTIDARWIN_STATE_BIT)
     59/** The generation mask. */
     60#define RTSEMEVENTMULTIDARWIN_GEN_MASK          ~RTSEMEVENTMULTIDARWIN_STATE_MASK
     61/** The generation shift. */
     62#define RTSEMEVENTMULTIDARWIN_GEN_SHIFT         1
     63/** The initial variable value. */
     64#define RTSEMEVENTMULTIDARWIN_STATE_GEN_INIT    UINT32_C(0xfffffffc)
     65/** @}  */
    4666
    4767
     
    5676    /** Magic value (RTSEMEVENTMULTI_MAGIC). */
    5777    uint32_t volatile   u32Magic;
    58     /** The number of waiting threads. */
    59     uint32_t volatile   cWaiters;
    60     /** Set if the event object is signaled. */
    61     uint8_t volatile    fSignaled;
    62     /** The number of threads in the process of waking up. */
    63     uint32_t volatile   cWaking;
     78    /** The object state bit and generation counter.
     79     * The generation counter is incremented every time the object is
     80     * signalled. */
     81    uint32_t volatile   fStateAndGen;
     82    /** Reference counter. */
     83    uint32_t volatile   cRefs;
     84    /** Set if there are blocked threads. */
     85    bool volatile       fHaveBlockedThreads;
    6486    /** The spinlock protecting us. */
    6587    lck_spin_t         *pSpinlock;
     
    85107    if (pThis)
    86108    {
    87         pThis->u32Magic = RTSEMEVENTMULTI_MAGIC;
    88         pThis->cWaiters = 0;
    89         pThis->cWaking = 0;
    90         pThis->fSignaled = 0;
     109        pThis->u32Magic             = RTSEMEVENTMULTI_MAGIC;
     110        pThis->fStateAndGen         = RTSEMEVENTMULTIDARWIN_STATE_GEN_INIT;
     111        pThis->cRefs                = 1;
     112        pThis->fHaveBlockedThreads  = false;
    91113        Assert(g_pDarwinLockGroup);
    92114        pThis->pSpinlock = lck_spin_alloc_init(g_pDarwinLockGroup, LCK_ATTR_NULL);
     
    104126
    105127
     128/**
     129 * Retain a reference to the semaphore.
     130 *
     131 * @param   pThis       The semaphore.
     132 */
     133DECLINLINE(void) rtR0SemEventMultiDarwinRetain(PRTSEMEVENTMULTIINTERNAL pThis)
     134{
     135    uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
     136    Assert(cRefs && cRefs < 100000);
     137}
     138
     139
     140/**
     141 * Release a reference, destroy the thing if necessary.
     142 *
     143 * @param   pThis       The semaphore.
     144 */
     145DECLINLINE(void) rtR0SemEventMultiDarwinRelease(PRTSEMEVENTMULTIINTERNAL pThis)
     146{
     147    if (RT_UNLIKELY(ASMAtomicDecU32(&pThis->cRefs) == 0))
     148    {
     149        Assert(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC);
     150        lck_spin_destroy(pThis->pSpinlock, g_pDarwinLockGroup);
     151        RTMemFree(pThis);
     152    }
     153}
     154
     155
    106156RTDECL(int)  RTSemEventMultiDestroy(RTSEMEVENTMULTI hEventMultiSem)
    107157{
     
    111161    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
    112162    AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
     163    Assert(pThis->cRefs > 0);
    113164    RT_ASSERT_INTS_ON();
    114165
    115166    lck_spin_lock(pThis->pSpinlock);
    116     ASMAtomicIncU32(&pThis->u32Magic); /* make the handle invalid */
    117     if (pThis->cWaiters > 0)
    118     {
    119         /* abort waiting thread, last man cleans up. */
    120         ASMAtomicXchgU32(&pThis->cWaking, pThis->cWaking + pThis->cWaiters);
     167
     168    ASMAtomicWriteU32(&pThis->u32Magic, ~RTSEMEVENTMULTI_MAGIC); /* make the handle invalid */
     169    ASMAtomicAndU32(&pThis->fStateAndGen, RTSEMEVENTMULTIDARWIN_GEN_MASK);
     170    if (pThis->fHaveBlockedThreads)
     171    {
     172        /* abort waiting threads. */
    121173        thread_wakeup_prim((event_t)pThis, FALSE /* all threads */, THREAD_RESTART);
    122         lck_spin_unlock(pThis->pSpinlock);
    123     }
    124     else if (pThis->cWaking)
    125         /* the last waking thread is gonna do the cleanup */
    126         lck_spin_unlock(pThis->pSpinlock);
    127     else
    128     {
    129         lck_spin_unlock(pThis->pSpinlock);
    130         lck_spin_destroy(pThis->pSpinlock, g_pDarwinLockGroup);
    131         RTMemFree(pThis);
    132     }
     174    }
     175
     176    lck_spin_unlock(pThis->pSpinlock);
     177    rtR0SemEventMultiDarwinRelease(pThis);
    133178
    134179    return VINF_SUCCESS;
     
    144189    RT_ASSERT_INTS_ON();
    145190
     191    rtR0SemEventMultiDarwinRetain(pThis);
    146192    lck_spin_lock(pThis->pSpinlock);
    147193
    148     ASMAtomicXchgU8(&pThis->fSignaled, true);
    149     if (pThis->cWaiters > 0)
    150     {
    151         ASMAtomicXchgU32(&pThis->cWaking, pThis->cWaking + pThis->cWaiters);
    152         ASMAtomicXchgU32(&pThis->cWaiters, 0);
     194    uint32_t fNew = ASMAtomicUoReadU32(&pThis->fStateAndGen);
     195    fNew += 1 << RTSEMEVENTMULTIDARWIN_GEN_SHIFT;
     196    fNew |= RTSEMEVENTMULTIDARWIN_STATE_MASK;
     197    ASMAtomicWriteU32(&pThis->fStateAndGen, fNew);
     198
     199    if (pThis->fHaveBlockedThreads)
     200    {
     201        ASMAtomicWriteBool(&pThis->fHaveBlockedThreads, false);
    153202        thread_wakeup_prim((event_t)pThis, FALSE /* all threads */, THREAD_AWAKENED);
    154203    }
    155204
    156205    lck_spin_unlock(pThis->pSpinlock);
     206    rtR0SemEventMultiDarwinRelease(pThis);
    157207
    158208    RT_ASSERT_PREEMPT_CPUID();
     
    169219    RT_ASSERT_INTS_ON();
    170220
     221    rtR0SemEventMultiDarwinRetain(pThis);
    171222    lck_spin_lock(pThis->pSpinlock);
    172     ASMAtomicXchgU8(&pThis->fSignaled, false);
     223
     224    ASMAtomicAndU32(&pThis->fStateAndGen, ~RTSEMEVENTMULTIDARWIN_STATE_MASK);
     225
    173226    lck_spin_unlock(pThis->pSpinlock);
     227    rtR0SemEventMultiDarwinRelease(pThis);
    174228
    175229    RT_ASSERT_PREEMPT_CPUID();
     
    178232
    179233
    180 static int rtSemEventMultiWait(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies, wait_interrupt_t fInterruptible)
    181 {
    182     PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
     234/**
     235 * Worker for RTSemEventMultiWaitEx and RTSemEventMultiWaitExDebug.
     236 *
     237 * @returns VBox status code.
     238 * @param   pThis           The event semaphore.
     239 * @param   fFlags          See RTSemEventMultiWaitEx.
     240 * @param   uTimeout        See RTSemEventMultiWaitEx.
     241 * @param   pSrcPos         The source code position of the wait.
     242 */
     243static int rtR0SemEventMultiDarwinWait(PRTSEMEVENTMULTIINTERNAL pThis, uint32_t fFlags, uint64_t uTimeout,
     244                                       PCRTLOCKVALSRCPOS pSrcPos)
     245{
     246    /*
     247     * Validate input.
     248     */
    183249    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
    184250    AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
    185     if (cMillies)
     251    AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER);
     252    if (uTimeout != 0 || (fFlags & RTSEMWAIT_FLAGS_INDEFINITE))
    186253        RT_ASSERT_PREEMPTIBLE();
    187254
     255    rtR0SemEventMultiDarwinRetain(pThis);
    188256    lck_spin_lock(pThis->pSpinlock);
    189257
     258    /*
     259     * Is the event already signalled or do we have to wait?
     260     */
    190261    int rc;
    191     if (pThis->fSignaled)
     262    uint32_t const fOrgStateAndGen = ASMAtomicUoReadU32(&pThis->fStateAndGen);
     263    if (fOrgStateAndGen & RTSEMEVENTMULTIDARWIN_STATE_MASK)
    192264        rc = VINF_SUCCESS;
    193     else if (!cMillies)
    194         rc = VERR_TIMEOUT;
    195265    else
    196266    {
    197         ASMAtomicIncU32(&pThis->cWaiters);
    198 
    199         wait_result_t rcWait;
    200         if (cMillies == RT_INDEFINITE_WAIT)
    201             rcWait = lck_spin_sleep(pThis->pSpinlock, LCK_SLEEP_DEFAULT, (event_t)pThis, fInterruptible);
     267        /*
     268         * We have to wait. So, we'll need to convert the timeout and figure
     269         * out if it's indefinite or not.
     270         */
     271        uint64_t uNsAbsTimeout = 1;
     272        if (!(fFlags & RTSEMWAIT_FLAGS_INDEFINITE))
     273        {
     274            if (fFlags & RTSEMWAIT_FLAGS_MILLISECS)
     275                uTimeout = uTimeout < UINT64_MAX / UINT32_C(1000000) * UINT32_C(1000000)
     276                         ? uTimeout * UINT32_C(1000000)
     277                         : UINT64_MAX;
     278            if (uTimeout == UINT64_MAX)
     279                fFlags |= RTSEMWAIT_FLAGS_INDEFINITE;
     280            else
     281            {
     282                uint64_t u64Now;
     283                if (fFlags & RTSEMWAIT_FLAGS_RELATIVE)
     284                {
     285                    if (uTimeout != 0)
     286                    {
     287                        u64Now = RTTimeSystemNanoTS();
     288                        uNsAbsTimeout = u64Now + uTimeout;
     289                        if (uNsAbsTimeout < u64Now) /* overflow */
     290                            fFlags |= RTSEMWAIT_FLAGS_INDEFINITE;
     291                    }
     292                }
     293                else
     294                {
     295                    uNsAbsTimeout = uTimeout;
     296                    u64Now        = RTTimeSystemNanoTS();
     297                    uTimeout      = u64Now < uTimeout ? uTimeout - u64Now : 0;
     298                }
     299            }
     300        }
     301
     302        if (   !(fFlags & RTSEMWAIT_FLAGS_INDEFINITE)
     303            && uTimeout == 0)
     304        {
     305            /*
     306             * Poll call, we already checked the condition above so no need to
     307             * wait for anything.
     308             */
     309            rc = VERR_TIMEOUT;
     310        }
    202311        else
    203312        {
    204             uint64_t u64AbsTime;
    205             nanoseconds_to_absolutetime(cMillies * UINT64_C(1000000), &u64AbsTime);
    206             u64AbsTime += mach_absolute_time();
    207 
    208             rcWait = lck_spin_sleep_deadline(pThis->pSpinlock, LCK_SLEEP_DEFAULT,
    209                                              (event_t)pThis, fInterruptible, u64AbsTime);
     313            for (;;)
     314            {
     315                /*
     316                 * Do the actual waiting.
     317                 */
     318                ASMAtomicWriteBool(&pThis->fHaveBlockedThreads, true);
     319                wait_interrupt_t fInterruptible = fFlags & RTSEMWAIT_FLAGS_INTERRUPTIBLE ? THREAD_ABORTSAFE : THREAD_UNINT;
     320                wait_result_t    rcWait;
     321                if (fFlags & RTSEMWAIT_FLAGS_INDEFINITE)
     322                    rcWait = lck_spin_sleep(pThis->pSpinlock, LCK_SLEEP_DEFAULT, (event_t)pThis, fInterruptible);
     323                else
     324                {
     325                    uint64_t u64AbsTime;
     326                    nanoseconds_to_absolutetime(uNsAbsTimeout, &u64AbsTime);
     327                    rcWait = lck_spin_sleep_deadline(pThis->pSpinlock, LCK_SLEEP_DEFAULT,
     328                                                     (event_t)pThis, fInterruptible, u64AbsTime);
     329                }
     330
     331                /*
     332                 * Deal with the wait result.
     333                 */
     334                if (RT_LIKELY(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC))
     335                {
     336                    switch (rcWait)
     337                    {
     338                        case THREAD_AWAKENED:
     339                            if (RT_LIKELY(ASMAtomicUoReadU32(&pThis->fStateAndGen) != fOrgStateAndGen))
     340                                rc = VINF_SUCCESS;
     341                            else if (fFlags & RTSEMWAIT_FLAGS_INTERRUPTIBLE)
     342                                rc = VERR_INTERRUPTED;
     343                            else
     344                                continue; /* Seen this happen after fork/exec/something. */
     345                            break;
     346
     347                        case THREAD_TIMED_OUT:
     348                            Assert(!(fFlags & RTSEMWAIT_FLAGS_INDEFINITE));
     349                            rc = VERR_TIMEOUT;
     350                            break;
     351
     352                        case THREAD_INTERRUPTED:
     353                            Assert(fInterruptible != THREAD_UNINT);
     354                            rc = VERR_INTERRUPTED;
     355                            break;
     356
     357                        case THREAD_RESTART:
     358                            AssertMsg(pThis->u32Magic == ~RTSEMEVENTMULTI_MAGIC, ("%#x\n", pThis->u32Magic));
     359                            rc = VERR_SEM_DESTROYED;
     360                            break;
     361
     362                        default:
     363                            AssertMsgFailed(("rcWait=%d\n", rcWait));
     364                            rc = VERR_INTERNAL_ERROR_3;
     365                            break;
     366                    }
     367                }
     368                else
     369                    rc = VERR_SEM_DESTROYED;
     370                break;
     371            }
    210372        }
    211         switch (rcWait)
    212         {
    213             case THREAD_AWAKENED:
    214                 Assert(pThis->cWaking > 0);
    215                 if (    !ASMAtomicDecU32(&pThis->cWaking)
    216                     &&  pThis->u32Magic != RTSEMEVENTMULTI_MAGIC)
    217                 {
    218                     /* the event was destroyed after we woke up, as the last thread do the cleanup. */
    219                     lck_spin_unlock(pThis->pSpinlock);
    220                     Assert(g_pDarwinLockGroup);
    221                     lck_spin_destroy(pThis->pSpinlock, g_pDarwinLockGroup);
    222                     RTMemFree(pThis);
    223                     return VINF_SUCCESS;
    224                 }
    225                 rc = VINF_SUCCESS;
    226                 break;
    227 
    228             case THREAD_TIMED_OUT:
    229                 Assert(cMillies != RT_INDEFINITE_WAIT);
    230                 ASMAtomicDecU32(&pThis->cWaiters);
    231                 rc = VERR_TIMEOUT;
    232                 break;
    233 
    234             case THREAD_INTERRUPTED:
    235                 Assert(fInterruptible);
    236                 ASMAtomicDecU32(&pThis->cWaiters);
    237                 rc = VERR_INTERRUPTED;
    238                 break;
    239 
    240             case THREAD_RESTART:
    241                 /* Last one out does the cleanup. */
    242                 if (!ASMAtomicDecU32(&pThis->cWaking))
    243                 {
    244                     lck_spin_unlock(pThis->pSpinlock);
    245                     Assert(g_pDarwinLockGroup);
    246                     lck_spin_destroy(pThis->pSpinlock, g_pDarwinLockGroup);
    247                     RTMemFree(pThis);
    248                     return VERR_SEM_DESTROYED;
    249                 }
    250 
    251                 rc = VERR_SEM_DESTROYED;
    252                 break;
    253 
    254             default:
    255                 AssertMsgFailed(("rcWait=%d\n", rcWait));
    256                 rc = VERR_GENERAL_FAILURE;
    257                 break;
    258         }
    259373    }
    260374
    261375    lck_spin_unlock(pThis->pSpinlock);
     376    rtR0SemEventMultiDarwinRelease(pThis);
    262377    return rc;
    263378}
    264379
    265 
    266 RTDECL(int)  RTSemEventMultiWait(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies)
    267 {
    268     return rtSemEventMultiWait(hEventMultiSem, cMillies, THREAD_UNINT);
    269 }
    270 
    271 
    272 RTDECL(int)  RTSemEventMultiWaitNoResume(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies)
    273 {
    274     return rtSemEventMultiWait(hEventMultiSem, cMillies, THREAD_ABORTSAFE);
    275 }
    276 
     380#undef RTSemEventMultiWaitEx
     381RTDECL(int)  RTSemEventMultiWaitEx(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout)
     382{
     383#ifndef RTSEMEVENT_STRICT
     384    return rtR0SemEventMultiDarwinWait(hEventMultiSem, fFlags, uTimeout, NULL);
     385#else
     386    RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
     387    return rtR0SemEventMultiDarwinWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
     388#endif
     389}
     390
     391
     392RTDECL(int)  RTSemEventMultiWaitExDebug(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout,
     393                                        RTHCUINTPTR uId, RT_SRC_POS_DECL)
     394{
     395    RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
     396    return rtR0SemEventMultiDarwinWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
     397}
     398
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