VirtualBox

Changeset 6738 in vbox


Ignore:
Timestamp:
Feb 1, 2008 9:45:27 PM (17 years ago)
Author:
vboxsync
Message:

split up the linux and posix semaphore implementations (ring-3) to avoid code duplication and make it easier to select one or the other for each of the semaphore types.

Location:
trunk/src/VBox/Runtime
Files:
1 edited
5 copied
2 moved

Legend:

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

    r6730 r6738  
    306306        r3/posix/rand-posix.cpp \
    307307        r3/posix/RTTimeNow-posix.cpp \
     308        r3/posix/semrw-posix.cpp \
    308309        r3/posix/system-posix.cpp \
    309310        r3/posix/thread-posix.cpp \
     
    312313        r3/posix/utf8-posix.cpp
    313314ifeq ($(BUILD_TARGET_ARCH),amd64)
    314  RuntimeR3_SOURCES.linux += r3/linux/sems-linux.cpp
     315 ## @todo This causes VBoxGuestR3Lib to end up with the wrong stuff
     316 #        when building 64-bit linux. This code won't work on 2.4.
     317 RuntimeR3_SOURCES.linux += \
     318        r3/linux/semevent-linux.cpp \
     319        r3/linux/semeventmulti-linux.cpp
     320 ifdef RT_NEW_LINUX_MUTEX_CODE
     321  RuntimeR3_SOURCES.linux += \
     322        r3/linux/semmutex-linux.cpp
     323 else
     324  RuntimeR3_SOURCES.linux += \
     325        r3/posix/semmutex-posix.cpp
     326 endif
    315327else
    316  RuntimeR3_SOURCES.linux += r3/posix/sems-posix.cpp
     328 RuntimeR3_SOURCES.linux += \
     329        r3/posix/semevent-posix.cpp \
     330        r3/posix/semeventmulti-posix.cpp \
     331        r3/posix/semmutex-posix.cpp
    317332endif
    318333
     
    376391        r3/posix/process-posix.cpp \
    377392        r3/posix/rand-posix.cpp \
    378         r3/posix/sems-posix.cpp \
     393        r3/posix/semevent-posix.cpp \
     394        r3/posix/semeventmulti-posix.cpp \
     395        r3/posix/semmutex-posix.cpp \
     396        r3/posix/semrw-posix.cpp \
    379397        r3/posix/system-posix.cpp \
    380398        r3/posix/thread-posix.cpp \
     
    405423        r3/posix/rand-posix.cpp \
    406424        r3/posix/RTTimeNow-posix.cpp \
    407         r3/posix/sems-posix.cpp \
     425        r3/posix/semevent-posix.cpp \
     426        r3/posix/semeventmulti-posix.cpp \
     427        r3/posix/semmutex-posix.cpp \
     428        r3/posix/semrw-posix.cpp \
    408429        r3/posix/system-posix.cpp \
    409430        r3/posix/thread-posix.cpp \
     
    434455        r3/posix/rand-posix.cpp \
    435456        r3/posix/RTTimeNow-posix.cpp \
    436         r3/posix/sems-posix.cpp \
     457        r3/posix/semevent-posix.cpp \
     458        r3/posix/semeventmulti-posix.cpp \
     459        r3/posix/semmutex-posix.cpp \
     460        r3/posix/semrw-posix.cpp \
    437461        r3/posix/system-posix.cpp \
    438462        r3/posix/thread-posix.cpp \
  • trunk/src/VBox/Runtime/r3/linux/semevent-linux.cpp

    r6734 r6738  
    11/* $Id$ */
    22/** @file
    3  * innotek Portable Runtime - Semaphores, Linux (AMD64 only ATM).
     3 * innotek Portable Runtime - Event Semaphore, Linux (2.6.x+).
    44 */
    55
     
    4646# define FUTEX_WAIT 0
    4747# define FUTEX_WAKE 1
    48 #endif 
     48#endif
    4949
    5050
     
    5252*   Structures and Typedefs                                                    *
    5353*******************************************************************************/
    54 
    5554/**
    56  * Linux (single wakup) event semaphore. 
     55 * Linux (single wakup) event semaphore.
    5756 */
    5857struct RTSEMEVENTINTERNAL
     
    6160    intptr_t volatile   iMagic;
    6261    /** The futex state variable.
    63      * <0 means signaled. 
     62     * <0 means signaled.
    6463     *  0 means not signaled, no waiters.
    65      * >0 means not signaled, and the value gives the number of waiters. 
     64     * >0 means not signaled, and the value gives the number of waiters.
    6665     */
    6766    int32_t volatile    cWaiters;
    68 };
    69 
    70 
    71 /**
    72  * Linux multiple wakup event semaphore.
    73  */
    74 struct RTSEMEVENTMULTIINTERNAL
    75 {
    76     /** Magic value. */
    77     intptr_t volatile   iMagic;
    78     /** The futex state variable.
    79      * -1 means signaled.
    80      *  0 means not signaled, no waiters.
    81      * >0 means not signaled, and the value gives the number of waiters.
    82      */
    83     int32_t volatile    iState;
    84 };
    85 
    86 
    87 #ifndef VBOX_REWRITTEN_MUTEX
    88 /**
    89  * Posix internal representation of a Mutex semaphore.
    90  */
    91 struct RTSEMMUTEXINTERNAL
    92 {
    93     /** pthread mutex. */
    94     pthread_mutex_t     Mutex;
    95     /** The owner of the mutex. */
    96     volatile pthread_t  Owner;
    97     /** Nesting count. */
    98     volatile uint32_t   cNesting;
    99 };
    100 #else /* VBOX_REWRITTEN_MUTEX */
    101 /**
    102  * Linux internal representation of a Mutex semaphore.
    103  */
    104 struct RTSEMMUTEXINTERNAL
    105 {
    106     /** Magic value. */
    107     intptr_t volatile   iMagic;
    108     /** The futex state variable.
    109      * 0 means unlocked.
    110      * 1 means locked, no waiters.
    111      * 2 means locked, one or more waiters.
    112      */
    113     int32_t volatile    iState;
    114     /** The owner of the mutex. */
    115     volatile pthread_t  Owner;
    116     /** Nesting count. */
    117     volatile uint32_t   cNesting;
    118 };
    119 #endif /* VBOX_REWRITTEN_MUTEX */
    120 
    121 
    122 /**
    123  * Posix internal representation of a read-write semaphore.
    124  */
    125 struct RTSEMRWINTERNAL
    126 {
    127     /** pthread rwlock. */
    128     pthread_rwlock_t    RWLock;
    129     /** Variable to check if initialized.
    130      * 0 is uninitialized, ~0 is inititialized. */
    131     volatile unsigned   uCheck;
    132     /** The write owner of the lock. */
    133     volatile pthread_t  WROwner;
    13467};
    13568
     
    175108     */
    176109    struct RTSEMEVENTINTERNAL *pIntEventSem = EventSem;
    177     AssertReturn(VALID_PTR(pIntEventSem) && pIntEventSem->iMagic == RTSEMEVENT_MAGIC, 
     110    AssertReturn(VALID_PTR(pIntEventSem) && pIntEventSem->iMagic == RTSEMEVENT_MAGIC,
    178111                 VERR_INVALID_HANDLE);
    179112
     
    202135     */
    203136    struct RTSEMEVENTINTERNAL *pIntEventSem = EventSem;
    204     AssertReturn(VALID_PTR(pIntEventSem) && pIntEventSem->iMagic == RTSEMEVENT_MAGIC, 
     137    AssertReturn(VALID_PTR(pIntEventSem) && pIntEventSem->iMagic == RTSEMEVENT_MAGIC,
    205138                 VERR_INVALID_HANDLE);
    206139    /*
     
    217150        else if (iCur < 0)
    218151            break; /* already signaled */
    219         else 
     152        else
    220153        {
    221154            /* somebody is waiting, try wake up one of them. */
     
    228161            AssertMsg(cWoken == 0, ("%ld\n", cWoken));
    229162
    230             /* 
     163            /*
    231164             * This path is taken in two situations:
    232              *      1) A waiting thread is returning from the sys_futex call with a 
     165             *      1) A waiting thread is returning from the sys_futex call with a
    233166             *         non-zero return value.
    234              *      2) There are two threads signaling the event at the 
     167             *      2) There are two threads signaling the event at the
    235168             *         same time and only one thread waiting.
    236169             *
    237              * At this point we know that nobody is activly waiting on the event but 
    238              * at the same time, we are racing someone updating the state. The current 
    239              * strategy is to spin till the thread racing us is done, this is kind of 
     170             * At this point we know that nobody is activly waiting on the event but
     171             * at the same time, we are racing someone updating the state. The current
     172             * strategy is to spin till the thread racing us is done, this is kind of
    240173             * brain dead and need fixing of course.
    241174             */
     
    261194     */
    262195    struct RTSEMEVENTINTERNAL *pIntEventSem = EventSem;
    263     AssertReturn(VALID_PTR(pIntEventSem) && pIntEventSem->iMagic == RTSEMEVENT_MAGIC, 
     196    AssertReturn(VALID_PTR(pIntEventSem) && pIntEventSem->iMagic == RTSEMEVENT_MAGIC,
    264197                 VERR_INVALID_HANDLE);
    265198
     
    287220    for (unsigned i = 0;; i++)
    288221    {
    289         /* 
    290          * Announce that we're among the waiters. 
     222        /*
     223         * Announce that we're among the waiters.
    291224         */
    292225        int32_t iNew = ASMAtomicIncS32(&pIntEventSem->cWaiters);
     
    304237            /* Did somebody wake us up from RTSemEventSignal()? */
    305238            if (rc == 0)
    306                 return VINF_SUCCESS; 
     239                return VINF_SUCCESS;
    307240
    308241            /* No, then the kernel woke us up or we failed going to sleep. Adjust the accounting. */
     
    310243            Assert(iNew >= 0);
    311244
    312             /* 
     245            /*
    313246             * Act on the wakup code.
    314247             */
     
    317250                Assert(pTimeout);
    318251                return VERR_TIMEOUT;
    319             } 
     252            }
    320253            if (rc == -EWOULDBLOCK)
    321254                /* retry with new value. */;
     
    356289}
    357290
    358 
    359 
    360 
    361 
    362 RTDECL(int)  RTSemEventMultiCreate(PRTSEMEVENTMULTI pEventMultiSem)
    363 {
    364     /*
    365      * Allocate semaphore handle.
    366      */
    367     struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem = (struct RTSEMEVENTMULTIINTERNAL *)RTMemAlloc(sizeof(struct RTSEMEVENTMULTIINTERNAL));
    368     if (pIntEventMultiSem)
    369     {
    370         pIntEventMultiSem->iMagic = RTSEMEVENTMULTI_MAGIC;
    371         pIntEventMultiSem->iState = 0;
    372         *pEventMultiSem = pIntEventMultiSem;
    373         return VINF_SUCCESS;
    374     }
    375     return  VERR_NO_MEMORY;
    376 }
    377 
    378 
    379 RTDECL(int)  RTSemEventMultiDestroy(RTSEMEVENTMULTI EventMultiSem)
    380 {
    381     /*
    382      * Validate input.
    383      */
    384     struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem = EventMultiSem;
    385     AssertReturn(VALID_PTR(pIntEventMultiSem) && pIntEventMultiSem->iMagic == RTSEMEVENTMULTI_MAGIC,
    386                  VERR_INVALID_HANDLE);
    387 
    388     /*
    389      * Invalidate the semaphore and wake up anyone waiting on it.
    390      */
    391     ASMAtomicXchgSize(&pIntEventMultiSem->iMagic, RTSEMEVENTMULTI_MAGIC + 1);
    392     if (ASMAtomicXchgS32(&pIntEventMultiSem->iState, -1) == 1)
    393     {
    394         sys_futex(&pIntEventMultiSem->iState, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
    395         usleep(1000);
    396     }
    397 
    398     /*
    399      * Free the semaphore memory and be gone.
    400      */
    401     RTMemFree(pIntEventMultiSem);
    402     return VINF_SUCCESS;
    403 }
    404 
    405 
    406 RTDECL(int)  RTSemEventMultiSignal(RTSEMEVENTMULTI EventMultiSem)
    407 {
    408     /*
    409      * Validate input.
    410      */
    411     struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem = EventMultiSem;
    412     AssertReturn(VALID_PTR(pIntEventMultiSem) && pIntEventMultiSem->iMagic == RTSEMEVENTMULTI_MAGIC,
    413                  VERR_INVALID_HANDLE);
    414     /*
    415      * Signal it.
    416      */
    417     int32_t iOld = ASMAtomicXchgS32(&pIntEventMultiSem->iState, -1);
    418     if (iOld > 0)
    419     {
    420         /* wake up sleeping threads. */
    421         long cWoken = sys_futex(&pIntEventMultiSem->iState, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
    422         AssertMsg(cWoken >= 0, ("%ld\n", cWoken)); NOREF(cWoken);
    423     }
    424     Assert(iOld == 0 || iOld == -1 || iOld == 1);
    425     return VINF_SUCCESS;
    426 }
    427 
    428 
    429 RTDECL(int)  RTSemEventMultiReset(RTSEMEVENTMULTI EventMultiSem)
    430 {
    431     /*
    432      * Validate input.
    433      */
    434     struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem = EventMultiSem;
    435     AssertReturn(VALID_PTR(pIntEventMultiSem) && pIntEventMultiSem->iMagic == RTSEMEVENTMULTI_MAGIC,
    436                  VERR_INVALID_HANDLE);
    437 #ifdef RT_STRICT
    438     int32_t i = pIntEventMultiSem->iState;
    439     Assert(i == 0 || i == -1 || i == 1);
    440 #endif
    441 
    442     /*
    443      * Reset it.
    444      */
    445     ASMAtomicCmpXchgS32(&pIntEventMultiSem->iState, 0, -1);
    446     return VINF_SUCCESS;
    447 }
    448 
    449 
    450 static int rtSemEventMultiWait(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies, bool fAutoResume)
    451 {
    452     /*
    453      * Validate input.
    454      */
    455     struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem = EventMultiSem;
    456     AssertReturn(VALID_PTR(pIntEventMultiSem) && pIntEventMultiSem->iMagic == RTSEMEVENTMULTI_MAGIC,
    457                  VERR_INVALID_HANDLE);
    458 
    459     /*
    460      * Quickly check whether it's signaled.
    461      */
    462     int32_t iCur = pIntEventMultiSem->iState;
    463     Assert(iCur == 0 || iCur == -1 || iCur == 1);
    464     if (iCur == -1)
    465         return VINF_SUCCESS;
    466     if (!cMillies)
    467         return VERR_TIMEOUT;
    468 
    469     /*
    470      * Convert timeout value.
    471      */
    472     struct timespec ts;
    473     struct timespec *pTimeout = NULL;
    474     if (cMillies != RT_INDEFINITE_WAIT)
    475     {
    476         ts.tv_sec  = cMillies / 1000;
    477         ts.tv_nsec = (cMillies % 1000) * 1000000;
    478         pTimeout = &ts;
    479     }
    480 
    481     /*
    482      * The wait loop.
    483      */
    484     for (unsigned i = 0;; i++)
    485     {
    486         /*
    487          * Start waiting. We only account for there being or having been
    488          * threads waiting on the semaphore to keep things simple.
    489          */
    490         iCur = pIntEventMultiSem->iState;
    491         Assert(iCur == 0 || iCur == -1 || iCur == 1);
    492         if (    iCur == 1
    493             ||  ASMAtomicCmpXchgS32(&pIntEventMultiSem->iState, 1, 0))
    494         {
    495             long rc = sys_futex(&pIntEventMultiSem->iState, FUTEX_WAIT, 1, pTimeout, NULL, 0);
    496             if (RT_UNLIKELY(pIntEventMultiSem->iMagic != RTSEMEVENTMULTI_MAGIC))
    497                 return VERR_SEM_DESTROYED;
    498             if (rc == 0)
    499                 return VINF_SUCCESS;
    500 
    501             /*
    502              * Act on the wakup code.
    503              */
    504             if (rc == -ETIMEDOUT)
    505             {
    506                 Assert(pTimeout);
    507                 return VERR_TIMEOUT;
    508             }
    509             if (rc == -EWOULDBLOCK)
    510                 /* retry, the value changed. */;
    511             else if (rc == -EINTR)
    512             {
    513                 if (!fAutoResume)
    514                     return VERR_INTERRUPTED;
    515             }
    516             else
    517             {
    518                 /* this shouldn't happen! */
    519                 AssertMsgFailed(("rc=%ld errno=%d\n", rc, errno));
    520                 return RTErrConvertFromErrno(rc);
    521             }
    522         }
    523         else if (iCur == -1)
    524             return VINF_SUCCESS;
    525     }
    526 }
    527 
    528 
    529 RTDECL(int)  RTSemEventMultiWait(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies)
    530 {
    531     int rc = rtSemEventMultiWait(EventMultiSem, cMillies, true);
    532     Assert(rc != VERR_INTERRUPTED);
    533     return rc;
    534 }
    535 
    536 
    537 RTDECL(int)  RTSemEventMultiWaitNoResume(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies)
    538 {
    539     return rtSemEventMultiWait(EventMultiSem, cMillies, false);
    540 }
    541 
    542 
    543 
    544 
    545 
    546 /**
    547  * Validate a Mutex semaphore handle passed to one of the interface.
    548  *
    549  * @returns true if valid.
    550  * @returns false if invalid.
    551  * @param   pIntMutexSem    Pointer to the mutex semaphore to validate.
    552  */
    553 inline bool rtsemMutexValid(struct RTSEMMUTEXINTERNAL *pIntMutexSem)
    554 {
    555     if ((uintptr_t)pIntMutexSem < 0x10000)
    556         return false;
    557 
    558 #ifdef VBOX_REWRITTEN_MUTEX
    559     if (pIntMutexSem->iMagic != RTSEMMUTEX_MAGIC)
    560         return false;
    561 
    562 #endif /* VBOX_REWRITTEN_MUTEX */
    563     if (pIntMutexSem->cNesting == (uint32_t)~0)
    564         return false;
    565 
    566     return true;
    567 }
    568 
    569 
    570 #ifndef VBOX_REWRITTEN_MUTEX
    571 RTDECL(int)  RTSemMutexCreate(PRTSEMMUTEX pMutexSem)
    572 {
    573     int rc;
    574 
    575     /*
    576      * Allocate semaphore handle.
    577      */
    578     struct RTSEMMUTEXINTERNAL *pIntMutexSem = (struct RTSEMMUTEXINTERNAL *)RTMemAlloc(sizeof(struct RTSEMMUTEXINTERNAL));
    579     if (pIntMutexSem)
    580     {
    581         /*
    582          * Create the semaphore.
    583          */
    584         pthread_mutexattr_t MutexAttr;
    585         rc = pthread_mutexattr_init(&MutexAttr);
    586         if (!rc)
    587         {
    588             rc = pthread_mutex_init(&pIntMutexSem->Mutex, &MutexAttr);
    589             if (!rc)
    590             {
    591                 pthread_mutexattr_destroy(&MutexAttr);
    592 
    593                 pIntMutexSem->Owner    = (pthread_t)~0;
    594                 pIntMutexSem->cNesting = 0;
    595 
    596                 *pMutexSem = pIntMutexSem;
    597                 return VINF_SUCCESS;
    598             }
    599             pthread_mutexattr_destroy(&MutexAttr);
    600         }
    601         RTMemFree(pIntMutexSem);
    602     }
    603     else
    604         rc = VERR_NO_MEMORY;
    605 
    606     return rc;
    607 }
    608 
    609 
    610 RTDECL(int)  RTSemMutexDestroy(RTSEMMUTEX MutexSem)
    611 {
    612     /*
    613      * Validate input.
    614      */
    615     if (!rtsemMutexValid(MutexSem))
    616     {
    617         AssertMsgFailed(("Invalid handle %p!\n", MutexSem));
    618         return VERR_INVALID_HANDLE;
    619     }
    620 
    621     /*
    622      * Try destroy it.
    623      */
    624     struct RTSEMMUTEXINTERNAL *pIntMutexSem = MutexSem;
    625     int rc = pthread_mutex_destroy(&pIntMutexSem->Mutex);
    626     if (rc)
    627     {
    628         AssertMsgFailed(("Failed to destroy mutex sem %p, rc=%d.\n", MutexSem, rc));
    629         return RTErrConvertFromErrno(rc);
    630     }
    631 
    632     /*
    633      * Free the memory and be gone.
    634      */
    635     pIntMutexSem->Owner    = (pthread_t)~0;
    636     pIntMutexSem->cNesting = ~0;
    637     RTMemTmpFree(pIntMutexSem);
    638 
    639     return VINF_SUCCESS;
    640 }
    641 
    642 
    643 RTDECL(int)  RTSemMutexRequest(RTSEMMUTEX MutexSem, unsigned cMillies)
    644 {
    645     /*
    646      * Validate input.
    647      */
    648     if (!rtsemMutexValid(MutexSem))
    649     {
    650         AssertMsgFailed(("Invalid handle %p!\n", MutexSem));
    651         return VERR_INVALID_HANDLE;
    652     }
    653 
    654     /*
    655      * Check if nested request.
    656      */
    657     pthread_t                       Self = pthread_self();
    658     struct RTSEMMUTEXINTERNAL    *pIntMutexSem = MutexSem;
    659     if (    pIntMutexSem->Owner == Self
    660         &&  pIntMutexSem->cNesting > 0)
    661     {
    662         pIntMutexSem->cNesting++;
    663         return VINF_SUCCESS;
    664     }
    665 
    666     /*
    667      * Lock it.
    668      */
    669     if (cMillies == RT_INDEFINITE_WAIT)
    670     {
    671         /* take mutex */
    672         int rc = pthread_mutex_lock(&pIntMutexSem->Mutex);
    673         if (rc)
    674         {
    675             AssertMsgFailed(("Failed to lock mutex sem %p, rc=%d.\n", MutexSem, rc)); NOREF(rc);
    676             return RTErrConvertFromErrno(rc);
    677         }
    678     }
    679     else
    680     {
    681         /*
    682          * Get current time and calc end of wait time.
    683          */
    684         struct timespec     ts = {0,0};
    685         clock_gettime(CLOCK_REALTIME, &ts);
    686         if (cMillies != 0)
    687         {
    688             ts.tv_nsec += (cMillies % 1000) * 1000000;
    689             ts.tv_sec  += cMillies / 1000;
    690             if (ts.tv_nsec >= 1000000000)
    691             {
    692                 ts.tv_nsec -= 1000000000;
    693                 ts.tv_sec++;
    694             }
    695         }
    696 
    697         /* take mutex */
    698         int rc = pthread_mutex_timedlock(&pIntMutexSem->Mutex, &ts);
    699         if (rc)
    700         {
    701             AssertMsg(rc == ETIMEDOUT, ("Failed to lock mutex sem %p, rc=%d.\n", MutexSem, rc)); NOREF(rc);
    702             return RTErrConvertFromErrno(rc);
    703         }
    704     }
    705 
    706     /*
    707      * Set the owner and nesting.
    708      */
    709     pIntMutexSem->Owner = Self;
    710     ASMAtomicXchgU32(&pIntMutexSem->cNesting, 1);
    711 
    712     return VINF_SUCCESS;
    713 }
    714 
    715 
    716 RTDECL(int)  RTSemMutexRequestNoResume(RTSEMMUTEX MutexSem, unsigned cMillies)
    717 {
    718     /* EINTR isn't returned by the wait functions we're using. */
    719     return RTSemMutexRequest(MutexSem, cMillies);
    720 }
    721 
    722 
    723 RTDECL(int)  RTSemMutexRelease(RTSEMMUTEX MutexSem)
    724 {
    725     /*
    726      * Validate input.
    727      */
    728     if (!rtsemMutexValid(MutexSem))
    729     {
    730         AssertMsgFailed(("Invalid handle %p!\n", MutexSem));
    731         return VERR_INVALID_HANDLE;
    732     }
    733 
    734     /*
    735      * Check if nested.
    736      */
    737     pthread_t                       Self = pthread_self();
    738     struct RTSEMMUTEXINTERNAL    *pIntMutexSem = MutexSem;
    739     if (    pIntMutexSem->Owner != Self
    740         ||  pIntMutexSem->cNesting == (uint32_t)~0)
    741     {
    742         AssertMsgFailed(("Not owner of mutex %p!! Self=%08x Owner=%08x cNesting=%d\n",
    743                          pIntMutexSem, Self, pIntMutexSem->Owner, pIntMutexSem->cNesting));
    744         return VERR_NOT_OWNER;
    745     }
    746 
    747     /*
    748      * If nested we'll just pop a nesting.
    749      */
    750     if (pIntMutexSem->cNesting > 1)
    751     {
    752         pIntMutexSem->cNesting--;
    753         return VINF_SUCCESS;
    754     }
    755 
    756     /*
    757      * Clear the state. (cNesting == 1)
    758      */
    759     pIntMutexSem->Owner    = (pthread_t)~0;
    760     ASMAtomicXchgU32(&pIntMutexSem->cNesting, 0);
    761 
    762     /*
    763      * Unlock mutex semaphore.
    764      */
    765     int rc = pthread_mutex_unlock(&pIntMutexSem->Mutex);
    766     if (rc)
    767     {
    768         AssertMsgFailed(("Failed to unlock mutex sem %p, rc=%d.\n", MutexSem, rc)); NOREF(rc);
    769         return RTErrConvertFromErrno(rc);
    770     }
    771 
    772     return VINF_SUCCESS;
    773 }
    774 #else /* VBOX_REWRITTEN_MUTEX */
    775 RTDECL(int)  RTSemMutexCreate(PRTSEMMUTEX pMutexSem)
    776 {
    777     /*
    778      * Allocate semaphore handle.
    779      */
    780     struct RTSEMMUTEXINTERNAL *pIntMutexSem = (struct RTSEMMUTEXINTERNAL *)RTMemAlloc(sizeof(struct RTSEMMUTEXINTERNAL));
    781     if (pIntMutexSem)
    782     {
    783         pIntMutexSem->iMagic   = RTSEMMUTEX_MAGIC;
    784         pIntMutexSem->iState   = 0;
    785         pIntMutexSem->Owner    = (pthread_t)~0;
    786         pIntMutexSem->cNesting = 0;
    787 
    788         *pMutexSem = pIntMutexSem;
    789         return VINF_SUCCESS;
    790     }
    791 
    792     return VERR_NO_MEMORY;
    793 }
    794 
    795 
    796 RTDECL(int)  RTSemMutexDestroy(RTSEMMUTEX MutexSem)
    797 {
    798     struct RTSEMMUTEXINTERNAL *pIntMutexSem = MutexSem;
    799     /*
    800      * Validate input.
    801      */
    802     if (!rtsemMutexValid(pIntMutexSem))
    803     {
    804         AssertMsgFailed(("Invalid handle %p!\n", MutexSem));
    805         return VERR_INVALID_HANDLE;
    806     }
    807 
    808     /*
    809      * Invalidate the semaphore and wake up anyone waiting on it.
    810      */
    811     ASMAtomicXchgSize(&pIntMutexSem->iMagic, RTSEMMUTEX_MAGIC + 1);
    812     if (ASMAtomicXchgS32(&pIntMutexSem->iState, 0) > 0)
    813     {
    814         sys_futex(&pIntMutexSem->iState, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
    815         usleep(1000);
    816     }
    817     pIntMutexSem->Owner    = (pthread_t)~0;
    818     pIntMutexSem->cNesting = ~0;
    819 
    820     /*
    821      * Free the semaphore memory and be gone.
    822      */
    823     RTMemFree(pIntMutexSem);
    824     return VINF_SUCCESS;
    825 }
    826 
    827 
    828 static int rtsemMutexRequest(RTSEMMUTEX MutexSem, unsigned cMillies, bool fAutoResume)
    829 {
    830     /*
    831      * Validate input.
    832      */
    833     struct RTSEMMUTEXINTERNAL *pIntMutexSem = MutexSem;
    834     if (!rtsemMutexValid(pIntMutexSem))
    835     {
    836         AssertMsgFailed(("Invalid handle %p!\n", MutexSem));
    837         return VERR_INVALID_HANDLE;
    838     }
    839 
    840     /*
    841      * Check if nested request.
    842      */
    843     pthread_t Self = pthread_self();
    844     if (    pIntMutexSem->Owner == Self
    845         &&  pIntMutexSem->cNesting > 0)
    846     {
    847         pIntMutexSem->cNesting++;
    848         return VINF_SUCCESS;
    849     }
    850 
    851     /*
    852      * Convert timeout value.
    853      */
    854     struct timespec ts;
    855     struct timespec *pTimeout = NULL;
    856     if (cMillies != RT_INDEFINITE_WAIT)
    857     {
    858         ts.tv_sec  = cMillies / 1000;
    859         ts.tv_nsec = (cMillies % 1000) * 1000000;
    860         pTimeout = &ts;
    861     }
    862 
    863     /*
    864      * Lock the mutex.
    865      */
    866     int32_t iOld;
    867     ASMAtomicCmpXchgExS32(&pIntMutexSem->iState, 1, 0, &iOld);
    868     if (RT_UNLIKELY(iOld != 0))
    869     {
    870         iOld = ASMAtomicXchgS32(&pIntMutexSem->iState, 2);
    871         while (iOld != 0)
    872         {
    873             /*
    874              * Go to sleep.
    875              */
    876             long rc = sys_futex(&pIntMutexSem->iState, FUTEX_WAIT, 2, pTimeout, NULL, 0);
    877             if (RT_UNLIKELY(pIntMutexSem->iMagic != RTSEMMUTEX_MAGIC))
    878                 return VERR_SEM_DESTROYED;
    879 
    880             /*
    881              * Act on the wakup code.
    882              */
    883             if (rc == -ETIMEDOUT)
    884             {
    885                 Assert(pTimeout);
    886                 return VERR_TIMEOUT;
    887             }
    888             if (rc == 0)
    889                 /* we'll leave the loop now unless another thread is faster */;
    890             else if (rc == -EWOULDBLOCK)
    891                 /* retry with new value. */;
    892             else if (rc == -EINTR)
    893             {
    894                 if (!fAutoResume)
    895                     return VERR_INTERRUPTED;
    896             }
    897             else
    898             {
    899                 /* this shouldn't happen! */
    900                 AssertMsgFailed(("rc=%ld errno=%d\n", rc, errno));
    901                 return RTErrConvertFromErrno(rc);
    902             }
    903 
    904             iOld = ASMAtomicXchgS32(&pIntMutexSem->iState, 2);
    905         }
    906     }
    907 
    908     /*
    909      * Set the owner and nesting.
    910      */
    911     pIntMutexSem->Owner = Self;
    912     ASMAtomicXchgU32(&pIntMutexSem->cNesting, 1);
    913     return VINF_SUCCESS;
    914 }
    915 
    916 
    917 RTDECL(int)  RTSemMutexRequest(RTSEMMUTEX MutexSem, unsigned cMillies)
    918 {
    919     int rc = rtsemMutexRequest(MutexSem, cMillies, true);
    920     Assert(rc != VERR_INTERRUPTED);
    921     return rc;
    922 }
    923 
    924 
    925 RTDECL(int)  RTSemMutexRequestNoResume(RTSEMMUTEX MutexSem, unsigned cMillies)
    926 {
    927     return rtsemMutexRequest(MutexSem, cMillies, false);
    928 }
    929 
    930 
    931 RTDECL(int)  RTSemMutexRelease(RTSEMMUTEX MutexSem)
    932 {
    933     /*
    934      * Validate input.
    935      */
    936     struct RTSEMMUTEXINTERNAL *pIntMutexSem = MutexSem;
    937     if (!rtsemMutexValid(pIntMutexSem))
    938     {
    939         AssertMsgFailed(("Invalid handle %p!\n", MutexSem));
    940         return VERR_INVALID_HANDLE;
    941     }
    942 
    943     /*
    944      * Check if nested.
    945      */
    946     pthread_t Self = pthread_self();
    947     if (    pIntMutexSem->Owner != Self
    948         ||  pIntMutexSem->cNesting == (uint32_t)~0)
    949     {
    950         AssertMsgFailed(("Not owner of mutex %p!! Self=%08x Owner=%08x cNesting=%d\n",
    951                          pIntMutexSem, Self, pIntMutexSem->Owner, pIntMutexSem->cNesting));
    952         return VERR_NOT_OWNER;
    953     }
    954 
    955     /*
    956      * If nested we'll just pop a nesting.
    957      */
    958     if (pIntMutexSem->cNesting > 1)
    959     {
    960         pIntMutexSem->cNesting--;
    961         return VINF_SUCCESS;
    962     }
    963 
    964     /*
    965      * Clear the state. (cNesting == 1)
    966      */
    967     pIntMutexSem->Owner = (pthread_t)~0;
    968     ASMAtomicXchgU32(&pIntMutexSem->cNesting, 0);
    969 
    970     /*
    971      * Release the mutex.
    972      */
    973     int32_t iNew = ASMAtomicDecS32(&pIntMutexSem->iState);
    974     if (iNew != 0)
    975     {
    976         /* somebody is waiting, try wake up one of them. */
    977         ASMAtomicXchgS32(&pIntMutexSem->iState, 0);
    978         (void)sys_futex(&pIntMutexSem->iState, FUTEX_WAKE, 1, NULL, NULL, 0);
    979     }
    980     return VINF_SUCCESS;
    981 }
    982 #endif /* VBOX_REWRITTEN_MUTEX */
    983 
    984 
    985 
    986 
    987 /**
    988  * Validate a read-write semaphore handle passed to one of the interface.
    989  *
    990  * @returns true if valid.
    991  * @returns false if invalid.
    992  * @param   pIntRWSem   Pointer to the read-write semaphore to validate.
    993  */
    994 inline bool rtsemRWValid(struct RTSEMRWINTERNAL *pIntRWSem)
    995 {
    996     if ((uintptr_t)pIntRWSem < 0x10000)
    997         return false;
    998 
    999     if (pIntRWSem->uCheck != (unsigned)~0)
    1000         return false;
    1001 
    1002     return true;
    1003 }
    1004 
    1005 
    1006 RTDECL(int)   RTSemRWCreate(PRTSEMRW pRWSem)
    1007 {
    1008     int rc;
    1009 
    1010     /*
    1011      * Allocate handle.
    1012      */
    1013     struct RTSEMRWINTERNAL *pIntRWSem = (struct RTSEMRWINTERNAL *)RTMemAlloc(sizeof(struct RTSEMRWINTERNAL));
    1014     if (pIntRWSem)
    1015     {
    1016         /*
    1017          * Create the rwlock.
    1018          */
    1019         pthread_rwlockattr_t    Attr;
    1020         rc = pthread_rwlockattr_init(&Attr);
    1021         if (!rc)
    1022         {
    1023             rc = pthread_rwlock_init(&pIntRWSem->RWLock, &Attr);
    1024             if (!rc)
    1025             {
    1026                 pIntRWSem->uCheck = ~0;
    1027                 pIntRWSem->WROwner = (pthread_t)~0;
    1028                 *pRWSem = pIntRWSem;
    1029                 return VINF_SUCCESS;
    1030             }
    1031         }
    1032 
    1033         rc = RTErrConvertFromErrno(rc);
    1034         RTMemFree(pIntRWSem);
    1035     }
    1036     else
    1037         rc = VERR_NO_MEMORY;
    1038 
    1039     return rc;
    1040 }
    1041 
    1042 
    1043 RTDECL(int)   RTSemRWDestroy(RTSEMRW RWSem)
    1044 {
    1045     /*
    1046      * Validate input.
    1047      */
    1048     if (!rtsemRWValid(RWSem))
    1049     {
    1050         AssertMsgFailed(("Invalid handle %p!\n", RWSem));
    1051         return VERR_INVALID_HANDLE;
    1052     }
    1053 
    1054     /*
    1055      * Try destroy it.
    1056      */
    1057     struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
    1058     int rc = pthread_rwlock_destroy(&pIntRWSem->RWLock);
    1059     if (!rc)
    1060     {
    1061         pIntRWSem->uCheck = 0;
    1062         RTMemFree(pIntRWSem);
    1063         rc = VINF_SUCCESS;
    1064     }
    1065     else
    1066     {
    1067         AssertMsgFailed(("Failed to destroy read-write sem %p, rc=%d.\n", RWSem, rc));
    1068         rc = RTErrConvertFromErrno(rc);
    1069     }
    1070 
    1071     return rc;
    1072 }
    1073 
    1074 
    1075 RTDECL(int)   RTSemRWRequestRead(RTSEMRW RWSem, unsigned cMillies)
    1076 {
    1077     /*
    1078      * Validate input.
    1079      */
    1080     if (!rtsemRWValid(RWSem))
    1081     {
    1082         AssertMsgFailed(("Invalid handle %p!\n", RWSem));
    1083         return VERR_INVALID_HANDLE;
    1084     }
    1085 
    1086     /*
    1087      * Try lock it.
    1088      */
    1089     struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
    1090     if (cMillies == RT_INDEFINITE_WAIT)
    1091     {
    1092         /* take rwlock */
    1093         int rc = pthread_rwlock_rdlock(&pIntRWSem->RWLock);
    1094         if (rc)
    1095         {
    1096             AssertMsgFailed(("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
    1097             return RTErrConvertFromErrno(rc);
    1098         }
    1099     }
    1100     else
    1101     {
    1102         /*
    1103          * Get current time and calc end of wait time.
    1104          */
    1105         struct timespec     ts = {0,0};
    1106         clock_gettime(CLOCK_REALTIME, &ts);
    1107         if (cMillies != 0)
    1108         {
    1109             ts.tv_nsec += (cMillies % 1000) * 1000000;
    1110             ts.tv_sec  += cMillies / 1000;
    1111             if (ts.tv_nsec >= 1000000000)
    1112             {
    1113                 ts.tv_nsec -= 1000000000;
    1114                 ts.tv_sec++;
    1115             }
    1116         }
    1117 
    1118         /* take rwlock */
    1119         int rc = pthread_rwlock_timedrdlock(&pIntRWSem->RWLock, &ts);
    1120         if (rc)
    1121         {
    1122             AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
    1123             return RTErrConvertFromErrno(rc);
    1124         }
    1125     }
    1126 
    1127     return VINF_SUCCESS;
    1128 }
    1129 
    1130 
    1131 RTDECL(int)   RTSemRWRequestReadNoResume(RTSEMRW RWSem, unsigned cMillies)
    1132 {
    1133     /* EINTR isn't returned by the wait functions we're using. */
    1134     return RTSemRWRequestRead(RWSem, cMillies);
    1135 }
    1136 
    1137 
    1138 RTDECL(int)   RTSemRWReleaseRead(RTSEMRW RWSem)
    1139 {
    1140     /*
    1141      * Validate input.
    1142      */
    1143     if (!rtsemRWValid(RWSem))
    1144     {
    1145         AssertMsgFailed(("Invalid handle %p!\n", RWSem));
    1146         return VERR_INVALID_HANDLE;
    1147     }
    1148 
    1149     /*
    1150      * Try unlock it.
    1151      */
    1152     struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
    1153     if (pIntRWSem->WROwner == pthread_self())
    1154     {
    1155         AssertMsgFailed(("Tried to read unlock when write owner - read-write sem %p.\n", RWSem));
    1156         return VERR_NOT_OWNER;
    1157     }
    1158     int rc = pthread_rwlock_unlock(&pIntRWSem->RWLock);
    1159     if (rc)
    1160     {
    1161         AssertMsgFailed(("Failed read unlock read-write sem %p, rc=%d.\n", RWSem, rc));
    1162         return RTErrConvertFromErrno(rc);
    1163     }
    1164 
    1165     return VINF_SUCCESS;
    1166 }
    1167 
    1168 
    1169 RTDECL(int)   RTSemRWRequestWrite(RTSEMRW RWSem, unsigned cMillies)
    1170 {
    1171     /*
    1172      * Validate input.
    1173      */
    1174     if (!rtsemRWValid(RWSem))
    1175     {
    1176         AssertMsgFailed(("Invalid handle %p!\n", RWSem));
    1177         return VERR_INVALID_HANDLE;
    1178     }
    1179 
    1180     /*
    1181      * Try lock it.
    1182      */
    1183     struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
    1184     if (cMillies == RT_INDEFINITE_WAIT)
    1185     {
    1186         /* take rwlock */
    1187         int rc = pthread_rwlock_wrlock(&pIntRWSem->RWLock);
    1188         if (rc)
    1189         {
    1190             AssertMsgFailed(("Failed write lock read-write sem %p, rc=%d.\n", RWSem, rc));
    1191             return RTErrConvertFromErrno(rc);
    1192         }
    1193     }
    1194     else
    1195     {
    1196         /*
    1197          * Get current time and calc end of wait time.
    1198          */
    1199         struct timespec     ts = {0,0};
    1200         clock_gettime(CLOCK_REALTIME, &ts);
    1201         if (cMillies != 0)
    1202         {
    1203             ts.tv_nsec += (cMillies % 1000) * 1000000;
    1204             ts.tv_sec  += cMillies / 1000;
    1205             if (ts.tv_nsec >= 1000000000)
    1206             {
    1207                 ts.tv_nsec -= 1000000000;
    1208                 ts.tv_sec++;
    1209             }
    1210         }
    1211 
    1212         /* take rwlock */
    1213         int rc = pthread_rwlock_timedwrlock(&pIntRWSem->RWLock, &ts);
    1214         if (rc)
    1215         {
    1216             AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
    1217             return RTErrConvertFromErrno(rc);
    1218         }
    1219     }
    1220 
    1221     ASMAtomicXchgPtr((void * volatile *)&pIntRWSem->WROwner, (void *)pthread_self());
    1222 
    1223     return VINF_SUCCESS;
    1224 }
    1225 
    1226 
    1227 RTDECL(int)   RTSemRWRequestWriteNoResume(RTSEMRW RWSem, unsigned cMillies)
    1228 {
    1229     /* EINTR isn't returned by the wait functions we're using. */
    1230     return RTSemRWRequestWrite(RWSem, cMillies);
    1231 }
    1232 
    1233 
    1234 RTDECL(int)   RTSemRWReleaseWrite(RTSEMRW RWSem)
    1235 {
    1236     /*
    1237      * Validate input.
    1238      */
    1239     if (!rtsemRWValid(RWSem))
    1240     {
    1241         AssertMsgFailed(("Invalid handle %p!\n", RWSem));
    1242         return VERR_INVALID_HANDLE;
    1243     }
    1244 
    1245     /*
    1246      * Try unlock it.
    1247      */
    1248     pthread_t                   Self = pthread_self();
    1249     struct RTSEMRWINTERNAL   *pIntRWSem = RWSem;
    1250     if (pIntRWSem->WROwner != Self)
    1251     {
    1252         AssertMsgFailed(("Not Write owner!\n"));
    1253         return VERR_NOT_OWNER;
    1254     }
    1255 
    1256     /*
    1257      * Try unlock it.
    1258      */
    1259     AssertMsg(sizeof(pthread_t) == sizeof(void *), ("pthread_t is not the size of a pointer but %d bytes\n", sizeof(pthread_t)));
    1260     ASMAtomicXchgPtr((void * volatile *)&pIntRWSem->WROwner, (void *)(uintptr_t)~0);
    1261     int rc = pthread_rwlock_unlock(&pIntRWSem->RWLock);
    1262     if (rc)
    1263     {
    1264         AssertMsgFailed(("Failed write unlock read-write sem %p, rc=%d.\n", RWSem, rc));
    1265         return RTErrConvertFromErrno(rc);
    1266     }
    1267 
    1268     return VINF_SUCCESS;
    1269 }
    1270 
  • trunk/src/VBox/Runtime/r3/linux/semeventmulti-linux.cpp

    r6734 r6738  
    11/* $Id$ */
    22/** @file
    3  * innotek Portable Runtime - Semaphores, Linux (AMD64 only ATM).
     3 * innotek Portable Runtime - Multiple Release Event Semaphore, Linux (2.6.x+).
    44 */
    55
     
    4646# define FUTEX_WAIT 0
    4747# define FUTEX_WAKE 1
    48 #endif 
     48#endif
    4949
    5050
     
    5252*   Structures and Typedefs                                                    *
    5353*******************************************************************************/
    54 
    5554/**
    56  * Linux (single wakup) event semaphore.
    57  */
    58 struct RTSEMEVENTINTERNAL
     55 * Linux multiple wakup event semaphore.
     56 */
     57struct RTSEMEVENTMULTIINTERNAL
    5958{
    6059    /** Magic value. */
    6160    intptr_t volatile   iMagic;
    6261    /** The futex state variable.
    63      * <0 means signaled.
     62     * -1 means signaled.
    6463     *  0 means not signaled, no waiters.
    65      * >0 means not signaled, and the value gives the number of waiters.
    66      */
    67     int32_t volatile    cWaiters;
    68 };
    69 
    70 
    71 /**
    72  * Linux multiple wakup event semaphore.
    73  */
    74 struct RTSEMEVENTMULTIINTERNAL
    75 {
    76     /** Magic value. */
    77     intptr_t volatile   iMagic;
    78     /** The futex state variable.
    79      * -1 means signaled.
    80      *  0 means not signaled, no waiters.
    81      * >0 means not signaled, and the value gives the number of waiters.
     64     * >0 means not signaled, and the value gives the number of waiters.
    8265     */
    8366    int32_t volatile    iState;
    84 };
    85 
    86 
    87 #ifndef VBOX_REWRITTEN_MUTEX
    88 /**
    89  * Posix internal representation of a Mutex semaphore.
    90  */
    91 struct RTSEMMUTEXINTERNAL
    92 {
    93     /** pthread mutex. */
    94     pthread_mutex_t     Mutex;
    95     /** The owner of the mutex. */
    96     volatile pthread_t  Owner;
    97     /** Nesting count. */
    98     volatile uint32_t   cNesting;
    99 };
    100 #else /* VBOX_REWRITTEN_MUTEX */
    101 /**
    102  * Linux internal representation of a Mutex semaphore.
    103  */
    104 struct RTSEMMUTEXINTERNAL
    105 {
    106     /** Magic value. */
    107     intptr_t volatile   iMagic;
    108     /** The futex state variable.
    109      * 0 means unlocked.
    110      * 1 means locked, no waiters.
    111      * 2 means locked, one or more waiters.
    112      */
    113     int32_t volatile    iState;
    114     /** The owner of the mutex. */
    115     volatile pthread_t  Owner;
    116     /** Nesting count. */
    117     volatile uint32_t   cNesting;
    118 };
    119 #endif /* VBOX_REWRITTEN_MUTEX */
    120 
    121 
    122 /**
    123  * Posix internal representation of a read-write semaphore.
    124  */
    125 struct RTSEMRWINTERNAL
    126 {
    127     /** pthread rwlock. */
    128     pthread_rwlock_t    RWLock;
    129     /** Variable to check if initialized.
    130      * 0 is uninitialized, ~0 is inititialized. */
    131     volatile unsigned   uCheck;
    132     /** The write owner of the lock. */
    133     volatile pthread_t  WROwner;
    13467};
    13568
     
    14982    return rc;
    15083}
    151 
    152 
    153 
    154 RTDECL(int)  RTSemEventCreate(PRTSEMEVENT pEventSem)
    155 {
    156     /*
    157      * Allocate semaphore handle.
    158      */
    159     struct RTSEMEVENTINTERNAL *pIntEventSem = (struct RTSEMEVENTINTERNAL *)RTMemAlloc(sizeof(struct RTSEMEVENTINTERNAL));
    160     if (pIntEventSem)
    161     {
    162         pIntEventSem->iMagic = RTSEMEVENT_MAGIC;
    163         pIntEventSem->cWaiters = 0;
    164         *pEventSem = pIntEventSem;
    165         return VINF_SUCCESS;
    166     }
    167     return  VERR_NO_MEMORY;
    168 }
    169 
    170 
    171 RTDECL(int)  RTSemEventDestroy(RTSEMEVENT EventSem)
    172 {
    173     /*
    174      * Validate input.
    175      */
    176     struct RTSEMEVENTINTERNAL *pIntEventSem = EventSem;
    177     AssertReturn(VALID_PTR(pIntEventSem) && pIntEventSem->iMagic == RTSEMEVENT_MAGIC,
    178                  VERR_INVALID_HANDLE);
    179 
    180     /*
    181      * Invalidate the semaphore and wake up anyone waiting on it.
    182      */
    183     ASMAtomicXchgSize(&pIntEventSem->iMagic, RTSEMEVENT_MAGIC + 1);
    184     if (ASMAtomicXchgS32(&pIntEventSem->cWaiters, INT32_MIN / 2) > 0)
    185     {
    186         sys_futex(&pIntEventSem->cWaiters, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
    187         usleep(1000);
    188     }
    189 
    190     /*
    191      * Free the semaphore memory and be gone.
    192      */
    193     RTMemFree(pIntEventSem);
    194     return VINF_SUCCESS;
    195 }
    196 
    197 
    198 RTDECL(int)  RTSemEventSignal(RTSEMEVENT EventSem)
    199 {
    200     /*
    201      * Validate input.
    202      */
    203     struct RTSEMEVENTINTERNAL *pIntEventSem = EventSem;
    204     AssertReturn(VALID_PTR(pIntEventSem) && pIntEventSem->iMagic == RTSEMEVENT_MAGIC,
    205                  VERR_INVALID_HANDLE);
    206     /*
    207      * Try signal it.
    208      */
    209     for (unsigned i = 0;; i++)
    210     {
    211         int32_t iCur = pIntEventSem->cWaiters;
    212         if (iCur == 0)
    213         {
    214             if (ASMAtomicCmpXchgS32(&pIntEventSem->cWaiters, -1, 0))
    215                 break; /* nobody is waiting */
    216         }
    217         else if (iCur < 0)
    218             break; /* already signaled */
    219         else
    220         {
    221             /* somebody is waiting, try wake up one of them. */
    222             long cWoken = sys_futex(&pIntEventSem->cWaiters, FUTEX_WAKE, 1, NULL, NULL, 0);
    223             if (RT_LIKELY(cWoken == 1))
    224             {
    225                 ASMAtomicDecS32(&pIntEventSem->cWaiters);
    226                 break;
    227             }
    228             AssertMsg(cWoken == 0, ("%ld\n", cWoken));
    229 
    230             /*
    231              * This path is taken in two situations:
    232              *      1) A waiting thread is returning from the sys_futex call with a
    233              *         non-zero return value.
    234              *      2) There are two threads signaling the event at the
    235              *         same time and only one thread waiting.
    236              *
    237              * At this point we know that nobody is activly waiting on the event but
    238              * at the same time, we are racing someone updating the state. The current
    239              * strategy is to spin till the thread racing us is done, this is kind of
    240              * brain dead and need fixing of course.
    241              */
    242             if (RT_UNLIKELY(i > 32))
    243             {
    244                 if ((i % 128) == 127)
    245                     usleep(1000);
    246                 else if (!(i % 4))
    247                     pthread_yield();
    248                 else
    249                     AssertReleaseMsg(i < 4096, ("iCur=%#x pIntEventSem=%p\n", iCur, pIntEventSem));
    250             }
    251         }
    252     }
    253     return VINF_SUCCESS;
    254 }
    255 
    256 
    257 static int rtSemEventWait(RTSEMEVENT EventSem, unsigned cMillies, bool fAutoResume)
    258 {
    259     /*
    260      * Validate input.
    261      */
    262     struct RTSEMEVENTINTERNAL *pIntEventSem = EventSem;
    263     AssertReturn(VALID_PTR(pIntEventSem) && pIntEventSem->iMagic == RTSEMEVENT_MAGIC,
    264                  VERR_INVALID_HANDLE);
    265 
    266     /*
    267      * Quickly check whether it's signaled.
    268      */
    269     if (ASMAtomicCmpXchgS32(&pIntEventSem->cWaiters, 0, -1))
    270         return VINF_SUCCESS;
    271 
    272     /*
    273      * Convert timeout value.
    274      */
    275     struct timespec ts;
    276     struct timespec *pTimeout = 0;
    277     if (cMillies != RT_INDEFINITE_WAIT)
    278     {
    279         ts.tv_sec  = cMillies / 1000;
    280         ts.tv_nsec = (cMillies % 1000) * 1000000;
    281         pTimeout = &ts;
    282     }
    283 
    284     /*
    285      * The wait loop.
    286      */
    287     for (unsigned i = 0;; i++)
    288     {
    289         /*
    290          * Announce that we're among the waiters.
    291          */
    292         int32_t iNew = ASMAtomicIncS32(&pIntEventSem->cWaiters);
    293         if (iNew == 0)
    294             return VINF_SUCCESS;
    295         if (RT_LIKELY(iNew > 0))
    296         {
    297             /*
    298              * Go to sleep.
    299              */
    300             long rc = sys_futex(&pIntEventSem->cWaiters, FUTEX_WAIT, iNew, pTimeout, NULL, 0);
    301             if (RT_UNLIKELY(pIntEventSem->iMagic != RTSEMEVENT_MAGIC))
    302                 return VERR_SEM_DESTROYED;
    303 
    304             /* Did somebody wake us up from RTSemEventSignal()? */
    305             if (rc == 0)
    306                 return VINF_SUCCESS;
    307 
    308             /* No, then the kernel woke us up or we failed going to sleep. Adjust the accounting. */
    309             iNew = ASMAtomicDecS32(&pIntEventSem->cWaiters);
    310             Assert(iNew >= 0);
    311 
    312             /*
    313              * Act on the wakup code.
    314              */
    315             if (rc == -ETIMEDOUT)
    316             {
    317                 Assert(pTimeout);
    318                 return VERR_TIMEOUT;
    319             }
    320             if (rc == -EWOULDBLOCK)
    321                 /* retry with new value. */;
    322             else if (rc == -EINTR)
    323             {
    324                 if (!fAutoResume)
    325                     return VERR_INTERRUPTED;
    326             }
    327             else
    328             {
    329                 /* this shouldn't happen! */
    330                 AssertMsgFailed(("rc=%ld errno=%d\n", rc, errno));
    331                 return RTErrConvertFromErrno(rc);
    332             }
    333         }
    334         else
    335         {
    336             /* this can't happen. */
    337             if (RT_UNLIKELY(pIntEventSem->iMagic != RTSEMEVENT_MAGIC))
    338                 return VERR_SEM_DESTROYED;
    339             AssertReleaseMsgFailed(("iNew=%d\n", iNew));
    340         }
    341     }
    342 }
    343 
    344 
    345 RTDECL(int)  RTSemEventWait(RTSEMEVENT EventSem, unsigned cMillies)
    346 {
    347     int rc = rtSemEventWait(EventSem, cMillies, true);
    348     Assert(rc != VERR_INTERRUPTED);
    349     return rc;
    350 }
    351 
    352 
    353 RTDECL(int)  RTSemEventWaitNoResume(RTSEMEVENT EventSem, unsigned cMillies)
    354 {
    355     return rtSemEventWait(EventSem, cMillies, false);
    356 }
    357 
    358 
    359 
    36084
    36185
     
    383107     */
    384108    struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem = EventMultiSem;
    385     AssertReturn(VALID_PTR(pIntEventMultiSem) && pIntEventMultiSem->iMagic == RTSEMEVENTMULTI_MAGIC, 
     109    AssertReturn(VALID_PTR(pIntEventMultiSem) && pIntEventMultiSem->iMagic == RTSEMEVENTMULTI_MAGIC,
    386110                 VERR_INVALID_HANDLE);
    387111
     
    410134     */
    411135    struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem = EventMultiSem;
    412     AssertReturn(VALID_PTR(pIntEventMultiSem) && pIntEventMultiSem->iMagic == RTSEMEVENTMULTI_MAGIC, 
     136    AssertReturn(VALID_PTR(pIntEventMultiSem) && pIntEventMultiSem->iMagic == RTSEMEVENTMULTI_MAGIC,
    413137                 VERR_INVALID_HANDLE);
    414138    /*
     
    433157     */
    434158    struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem = EventMultiSem;
    435     AssertReturn(VALID_PTR(pIntEventMultiSem) && pIntEventMultiSem->iMagic == RTSEMEVENTMULTI_MAGIC, 
     159    AssertReturn(VALID_PTR(pIntEventMultiSem) && pIntEventMultiSem->iMagic == RTSEMEVENTMULTI_MAGIC,
    436160                 VERR_INVALID_HANDLE);
    437161#ifdef RT_STRICT
    438162    int32_t i = pIntEventMultiSem->iState;
    439163    Assert(i == 0 || i == -1 || i == 1);
    440 #endif 
     164#endif
    441165
    442166    /*
     
    454178     */
    455179    struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem = EventMultiSem;
    456     AssertReturn(VALID_PTR(pIntEventMultiSem) && pIntEventMultiSem->iMagic == RTSEMEVENTMULTI_MAGIC, 
     180    AssertReturn(VALID_PTR(pIntEventMultiSem) && pIntEventMultiSem->iMagic == RTSEMEVENTMULTI_MAGIC,
    457181                 VERR_INVALID_HANDLE);
    458182
     
    485209    {
    486210        /*
    487          * Start waiting. We only account for there being or having been 
     211         * Start waiting. We only account for there being or having been
    488212         * threads waiting on the semaphore to keep things simple.
    489213         */
     
    497221                return VERR_SEM_DESTROYED;
    498222            if (rc == 0)
    499                 return VINF_SUCCESS; 
    500 
    501             /* 
     223                return VINF_SUCCESS;
     224
     225            /*
    502226             * Act on the wakup code.
    503227             */
     
    506230                Assert(pTimeout);
    507231                return VERR_TIMEOUT;
    508             } 
     232            }
    509233            if (rc == -EWOULDBLOCK)
    510234                /* retry, the value changed. */;
     
    540264}
    541265
    542 
    543 
    544 
    545 
    546 /**
    547  * Validate a Mutex semaphore handle passed to one of the interface.
    548  *
    549  * @returns true if valid.
    550  * @returns false if invalid.
    551  * @param   pIntMutexSem    Pointer to the mutex semaphore to validate.
    552  */
    553 inline bool rtsemMutexValid(struct RTSEMMUTEXINTERNAL *pIntMutexSem)
    554 {
    555     if ((uintptr_t)pIntMutexSem < 0x10000)
    556         return false;
    557 
    558 #ifdef VBOX_REWRITTEN_MUTEX
    559     if (pIntMutexSem->iMagic != RTSEMMUTEX_MAGIC)
    560         return false;
    561 
    562 #endif /* VBOX_REWRITTEN_MUTEX */
    563     if (pIntMutexSem->cNesting == (uint32_t)~0)
    564         return false;
    565 
    566     return true;
    567 }
    568 
    569 
    570 #ifndef VBOX_REWRITTEN_MUTEX
    571 RTDECL(int)  RTSemMutexCreate(PRTSEMMUTEX pMutexSem)
    572 {
    573     int rc;
    574 
    575     /*
    576      * Allocate semaphore handle.
    577      */
    578     struct RTSEMMUTEXINTERNAL *pIntMutexSem = (struct RTSEMMUTEXINTERNAL *)RTMemAlloc(sizeof(struct RTSEMMUTEXINTERNAL));
    579     if (pIntMutexSem)
    580     {
    581         /*
    582          * Create the semaphore.
    583          */
    584         pthread_mutexattr_t MutexAttr;
    585         rc = pthread_mutexattr_init(&MutexAttr);
    586         if (!rc)
    587         {
    588             rc = pthread_mutex_init(&pIntMutexSem->Mutex, &MutexAttr);
    589             if (!rc)
    590             {
    591                 pthread_mutexattr_destroy(&MutexAttr);
    592 
    593                 pIntMutexSem->Owner    = (pthread_t)~0;
    594                 pIntMutexSem->cNesting = 0;
    595 
    596                 *pMutexSem = pIntMutexSem;
    597                 return VINF_SUCCESS;
    598             }
    599             pthread_mutexattr_destroy(&MutexAttr);
    600         }
    601         RTMemFree(pIntMutexSem);
    602     }
    603     else
    604         rc = VERR_NO_MEMORY;
    605 
    606     return rc;
    607 }
    608 
    609 
    610 RTDECL(int)  RTSemMutexDestroy(RTSEMMUTEX MutexSem)
    611 {
    612     /*
    613      * Validate input.
    614      */
    615     if (!rtsemMutexValid(MutexSem))
    616     {
    617         AssertMsgFailed(("Invalid handle %p!\n", MutexSem));
    618         return VERR_INVALID_HANDLE;
    619     }
    620 
    621     /*
    622      * Try destroy it.
    623      */
    624     struct RTSEMMUTEXINTERNAL *pIntMutexSem = MutexSem;
    625     int rc = pthread_mutex_destroy(&pIntMutexSem->Mutex);
    626     if (rc)
    627     {
    628         AssertMsgFailed(("Failed to destroy mutex sem %p, rc=%d.\n", MutexSem, rc));
    629         return RTErrConvertFromErrno(rc);
    630     }
    631 
    632     /*
    633      * Free the memory and be gone.
    634      */
    635     pIntMutexSem->Owner    = (pthread_t)~0;
    636     pIntMutexSem->cNesting = ~0;
    637     RTMemTmpFree(pIntMutexSem);
    638 
    639     return VINF_SUCCESS;
    640 }
    641 
    642 
    643 RTDECL(int)  RTSemMutexRequest(RTSEMMUTEX MutexSem, unsigned cMillies)
    644 {
    645     /*
    646      * Validate input.
    647      */
    648     if (!rtsemMutexValid(MutexSem))
    649     {
    650         AssertMsgFailed(("Invalid handle %p!\n", MutexSem));
    651         return VERR_INVALID_HANDLE;
    652     }
    653 
    654     /*
    655      * Check if nested request.
    656      */
    657     pthread_t                       Self = pthread_self();
    658     struct RTSEMMUTEXINTERNAL    *pIntMutexSem = MutexSem;
    659     if (    pIntMutexSem->Owner == Self
    660         &&  pIntMutexSem->cNesting > 0)
    661     {
    662         pIntMutexSem->cNesting++;
    663         return VINF_SUCCESS;
    664     }
    665 
    666     /*
    667      * Lock it.
    668      */
    669     if (cMillies == RT_INDEFINITE_WAIT)
    670     {
    671         /* take mutex */
    672         int rc = pthread_mutex_lock(&pIntMutexSem->Mutex);
    673         if (rc)
    674         {
    675             AssertMsgFailed(("Failed to lock mutex sem %p, rc=%d.\n", MutexSem, rc)); NOREF(rc);
    676             return RTErrConvertFromErrno(rc);
    677         }
    678     }
    679     else
    680     {
    681         /*
    682          * Get current time and calc end of wait time.
    683          */
    684         struct timespec     ts = {0,0};
    685         clock_gettime(CLOCK_REALTIME, &ts);
    686         if (cMillies != 0)
    687         {
    688             ts.tv_nsec += (cMillies % 1000) * 1000000;
    689             ts.tv_sec  += cMillies / 1000;
    690             if (ts.tv_nsec >= 1000000000)
    691             {
    692                 ts.tv_nsec -= 1000000000;
    693                 ts.tv_sec++;
    694             }
    695         }
    696 
    697         /* take mutex */
    698         int rc = pthread_mutex_timedlock(&pIntMutexSem->Mutex, &ts);
    699         if (rc)
    700         {
    701             AssertMsg(rc == ETIMEDOUT, ("Failed to lock mutex sem %p, rc=%d.\n", MutexSem, rc)); NOREF(rc);
    702             return RTErrConvertFromErrno(rc);
    703         }
    704     }
    705 
    706     /*
    707      * Set the owner and nesting.
    708      */
    709     pIntMutexSem->Owner = Self;
    710     ASMAtomicXchgU32(&pIntMutexSem->cNesting, 1);
    711 
    712     return VINF_SUCCESS;
    713 }
    714 
    715 
    716 RTDECL(int)  RTSemMutexRequestNoResume(RTSEMMUTEX MutexSem, unsigned cMillies)
    717 {
    718     /* EINTR isn't returned by the wait functions we're using. */
    719     return RTSemMutexRequest(MutexSem, cMillies);
    720 }
    721 
    722 
    723 RTDECL(int)  RTSemMutexRelease(RTSEMMUTEX MutexSem)
    724 {
    725     /*
    726      * Validate input.
    727      */
    728     if (!rtsemMutexValid(MutexSem))
    729     {
    730         AssertMsgFailed(("Invalid handle %p!\n", MutexSem));
    731         return VERR_INVALID_HANDLE;
    732     }
    733 
    734     /*
    735      * Check if nested.
    736      */
    737     pthread_t                       Self = pthread_self();
    738     struct RTSEMMUTEXINTERNAL    *pIntMutexSem = MutexSem;
    739     if (    pIntMutexSem->Owner != Self
    740         ||  pIntMutexSem->cNesting == (uint32_t)~0)
    741     {
    742         AssertMsgFailed(("Not owner of mutex %p!! Self=%08x Owner=%08x cNesting=%d\n",
    743                          pIntMutexSem, Self, pIntMutexSem->Owner, pIntMutexSem->cNesting));
    744         return VERR_NOT_OWNER;
    745     }
    746 
    747     /*
    748      * If nested we'll just pop a nesting.
    749      */
    750     if (pIntMutexSem->cNesting > 1)
    751     {
    752         pIntMutexSem->cNesting--;
    753         return VINF_SUCCESS;
    754     }
    755 
    756     /*
    757      * Clear the state. (cNesting == 1)
    758      */
    759     pIntMutexSem->Owner    = (pthread_t)~0;
    760     ASMAtomicXchgU32(&pIntMutexSem->cNesting, 0);
    761 
    762     /*
    763      * Unlock mutex semaphore.
    764      */
    765     int rc = pthread_mutex_unlock(&pIntMutexSem->Mutex);
    766     if (rc)
    767     {
    768         AssertMsgFailed(("Failed to unlock mutex sem %p, rc=%d.\n", MutexSem, rc)); NOREF(rc);
    769         return RTErrConvertFromErrno(rc);
    770     }
    771 
    772     return VINF_SUCCESS;
    773 }
    774 #else /* VBOX_REWRITTEN_MUTEX */
    775 RTDECL(int)  RTSemMutexCreate(PRTSEMMUTEX pMutexSem)
    776 {
    777     /*
    778      * Allocate semaphore handle.
    779      */
    780     struct RTSEMMUTEXINTERNAL *pIntMutexSem = (struct RTSEMMUTEXINTERNAL *)RTMemAlloc(sizeof(struct RTSEMMUTEXINTERNAL));
    781     if (pIntMutexSem)
    782     {
    783         pIntMutexSem->iMagic   = RTSEMMUTEX_MAGIC;
    784         pIntMutexSem->iState   = 0;
    785         pIntMutexSem->Owner    = (pthread_t)~0;
    786         pIntMutexSem->cNesting = 0;
    787 
    788         *pMutexSem = pIntMutexSem;
    789         return VINF_SUCCESS;
    790     }
    791 
    792     return VERR_NO_MEMORY;
    793 }
    794 
    795 
    796 RTDECL(int)  RTSemMutexDestroy(RTSEMMUTEX MutexSem)
    797 {
    798     struct RTSEMMUTEXINTERNAL *pIntMutexSem = MutexSem;
    799     /*
    800      * Validate input.
    801      */
    802     if (!rtsemMutexValid(pIntMutexSem))
    803     {
    804         AssertMsgFailed(("Invalid handle %p!\n", MutexSem));
    805         return VERR_INVALID_HANDLE;
    806     }
    807 
    808     /*
    809      * Invalidate the semaphore and wake up anyone waiting on it.
    810      */
    811     ASMAtomicXchgSize(&pIntMutexSem->iMagic, RTSEMMUTEX_MAGIC + 1);
    812     if (ASMAtomicXchgS32(&pIntMutexSem->iState, 0) > 0)
    813     {
    814         sys_futex(&pIntMutexSem->iState, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
    815         usleep(1000);
    816     }
    817     pIntMutexSem->Owner    = (pthread_t)~0;
    818     pIntMutexSem->cNesting = ~0;
    819 
    820     /*
    821      * Free the semaphore memory and be gone.
    822      */
    823     RTMemFree(pIntMutexSem);
    824     return VINF_SUCCESS;
    825 }
    826 
    827 
    828 static int rtsemMutexRequest(RTSEMMUTEX MutexSem, unsigned cMillies, bool fAutoResume)
    829 {
    830     /*
    831      * Validate input.
    832      */
    833     struct RTSEMMUTEXINTERNAL *pIntMutexSem = MutexSem;
    834     if (!rtsemMutexValid(pIntMutexSem))
    835     {
    836         AssertMsgFailed(("Invalid handle %p!\n", MutexSem));
    837         return VERR_INVALID_HANDLE;
    838     }
    839 
    840     /*
    841      * Check if nested request.
    842      */
    843     pthread_t Self = pthread_self();
    844     if (    pIntMutexSem->Owner == Self
    845         &&  pIntMutexSem->cNesting > 0)
    846     {
    847         pIntMutexSem->cNesting++;
    848         return VINF_SUCCESS;
    849     }
    850 
    851     /*
    852      * Convert timeout value.
    853      */
    854     struct timespec ts;
    855     struct timespec *pTimeout = NULL;
    856     if (cMillies != RT_INDEFINITE_WAIT)
    857     {
    858         ts.tv_sec  = cMillies / 1000;
    859         ts.tv_nsec = (cMillies % 1000) * 1000000;
    860         pTimeout = &ts;
    861     }
    862 
    863     /*
    864      * Lock the mutex.
    865      */
    866     int32_t iOld;
    867     ASMAtomicCmpXchgExS32(&pIntMutexSem->iState, 1, 0, &iOld);
    868     if (RT_UNLIKELY(iOld != 0))
    869     {
    870         iOld = ASMAtomicXchgS32(&pIntMutexSem->iState, 2);
    871         while (iOld != 0)
    872         {
    873             /*
    874              * Go to sleep.
    875              */
    876             long rc = sys_futex(&pIntMutexSem->iState, FUTEX_WAIT, 2, pTimeout, NULL, 0);
    877             if (RT_UNLIKELY(pIntMutexSem->iMagic != RTSEMMUTEX_MAGIC))
    878                 return VERR_SEM_DESTROYED;
    879 
    880             /*
    881              * Act on the wakup code.
    882              */
    883             if (rc == -ETIMEDOUT)
    884             {
    885                 Assert(pTimeout);
    886                 return VERR_TIMEOUT;
    887             }
    888             if (rc == 0)
    889                 /* we'll leave the loop now unless another thread is faster */;
    890             else if (rc == -EWOULDBLOCK)
    891                 /* retry with new value. */;
    892             else if (rc == -EINTR)
    893             {
    894                 if (!fAutoResume)
    895                     return VERR_INTERRUPTED;
    896             }
    897             else
    898             {
    899                 /* this shouldn't happen! */
    900                 AssertMsgFailed(("rc=%ld errno=%d\n", rc, errno));
    901                 return RTErrConvertFromErrno(rc);
    902             }
    903 
    904             iOld = ASMAtomicXchgS32(&pIntMutexSem->iState, 2);
    905         }
    906     }
    907 
    908     /*
    909      * Set the owner and nesting.
    910      */
    911     pIntMutexSem->Owner = Self;
    912     ASMAtomicXchgU32(&pIntMutexSem->cNesting, 1);
    913     return VINF_SUCCESS;
    914 }
    915 
    916 
    917 RTDECL(int)  RTSemMutexRequest(RTSEMMUTEX MutexSem, unsigned cMillies)
    918 {
    919     int rc = rtsemMutexRequest(MutexSem, cMillies, true);
    920     Assert(rc != VERR_INTERRUPTED);
    921     return rc;
    922 }
    923 
    924 
    925 RTDECL(int)  RTSemMutexRequestNoResume(RTSEMMUTEX MutexSem, unsigned cMillies)
    926 {
    927     return rtsemMutexRequest(MutexSem, cMillies, false);
    928 }
    929 
    930 
    931 RTDECL(int)  RTSemMutexRelease(RTSEMMUTEX MutexSem)
    932 {
    933     /*
    934      * Validate input.
    935      */
    936     struct RTSEMMUTEXINTERNAL *pIntMutexSem = MutexSem;
    937     if (!rtsemMutexValid(pIntMutexSem))
    938     {
    939         AssertMsgFailed(("Invalid handle %p!\n", MutexSem));
    940         return VERR_INVALID_HANDLE;
    941     }
    942 
    943     /*
    944      * Check if nested.
    945      */
    946     pthread_t Self = pthread_self();
    947     if (    pIntMutexSem->Owner != Self
    948         ||  pIntMutexSem->cNesting == (uint32_t)~0)
    949     {
    950         AssertMsgFailed(("Not owner of mutex %p!! Self=%08x Owner=%08x cNesting=%d\n",
    951                          pIntMutexSem, Self, pIntMutexSem->Owner, pIntMutexSem->cNesting));
    952         return VERR_NOT_OWNER;
    953     }
    954 
    955     /*
    956      * If nested we'll just pop a nesting.
    957      */
    958     if (pIntMutexSem->cNesting > 1)
    959     {
    960         pIntMutexSem->cNesting--;
    961         return VINF_SUCCESS;
    962     }
    963 
    964     /*
    965      * Clear the state. (cNesting == 1)
    966      */
    967     pIntMutexSem->Owner = (pthread_t)~0;
    968     ASMAtomicXchgU32(&pIntMutexSem->cNesting, 0);
    969 
    970     /*
    971      * Release the mutex.
    972      */
    973     int32_t iNew = ASMAtomicDecS32(&pIntMutexSem->iState);
    974     if (iNew != 0)
    975     {
    976         /* somebody is waiting, try wake up one of them. */
    977         ASMAtomicXchgS32(&pIntMutexSem->iState, 0);
    978         (void)sys_futex(&pIntMutexSem->iState, FUTEX_WAKE, 1, NULL, NULL, 0);
    979     }
    980     return VINF_SUCCESS;
    981 }
    982 #endif /* VBOX_REWRITTEN_MUTEX */
    983 
    984 
    985 
    986 
    987 /**
    988  * Validate a read-write semaphore handle passed to one of the interface.
    989  *
    990  * @returns true if valid.
    991  * @returns false if invalid.
    992  * @param   pIntRWSem   Pointer to the read-write semaphore to validate.
    993  */
    994 inline bool rtsemRWValid(struct RTSEMRWINTERNAL *pIntRWSem)
    995 {
    996     if ((uintptr_t)pIntRWSem < 0x10000)
    997         return false;
    998 
    999     if (pIntRWSem->uCheck != (unsigned)~0)
    1000         return false;
    1001 
    1002     return true;
    1003 }
    1004 
    1005 
    1006 RTDECL(int)   RTSemRWCreate(PRTSEMRW pRWSem)
    1007 {
    1008     int rc;
    1009 
    1010     /*
    1011      * Allocate handle.
    1012      */
    1013     struct RTSEMRWINTERNAL *pIntRWSem = (struct RTSEMRWINTERNAL *)RTMemAlloc(sizeof(struct RTSEMRWINTERNAL));
    1014     if (pIntRWSem)
    1015     {
    1016         /*
    1017          * Create the rwlock.
    1018          */
    1019         pthread_rwlockattr_t    Attr;
    1020         rc = pthread_rwlockattr_init(&Attr);
    1021         if (!rc)
    1022         {
    1023             rc = pthread_rwlock_init(&pIntRWSem->RWLock, &Attr);
    1024             if (!rc)
    1025             {
    1026                 pIntRWSem->uCheck = ~0;
    1027                 pIntRWSem->WROwner = (pthread_t)~0;
    1028                 *pRWSem = pIntRWSem;
    1029                 return VINF_SUCCESS;
    1030             }
    1031         }
    1032 
    1033         rc = RTErrConvertFromErrno(rc);
    1034         RTMemFree(pIntRWSem);
    1035     }
    1036     else
    1037         rc = VERR_NO_MEMORY;
    1038 
    1039     return rc;
    1040 }
    1041 
    1042 
    1043 RTDECL(int)   RTSemRWDestroy(RTSEMRW RWSem)
    1044 {
    1045     /*
    1046      * Validate input.
    1047      */
    1048     if (!rtsemRWValid(RWSem))
    1049     {
    1050         AssertMsgFailed(("Invalid handle %p!\n", RWSem));
    1051         return VERR_INVALID_HANDLE;
    1052     }
    1053 
    1054     /*
    1055      * Try destroy it.
    1056      */
    1057     struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
    1058     int rc = pthread_rwlock_destroy(&pIntRWSem->RWLock);
    1059     if (!rc)
    1060     {
    1061         pIntRWSem->uCheck = 0;
    1062         RTMemFree(pIntRWSem);
    1063         rc = VINF_SUCCESS;
    1064     }
    1065     else
    1066     {
    1067         AssertMsgFailed(("Failed to destroy read-write sem %p, rc=%d.\n", RWSem, rc));
    1068         rc = RTErrConvertFromErrno(rc);
    1069     }
    1070 
    1071     return rc;
    1072 }
    1073 
    1074 
    1075 RTDECL(int)   RTSemRWRequestRead(RTSEMRW RWSem, unsigned cMillies)
    1076 {
    1077     /*
    1078      * Validate input.
    1079      */
    1080     if (!rtsemRWValid(RWSem))
    1081     {
    1082         AssertMsgFailed(("Invalid handle %p!\n", RWSem));
    1083         return VERR_INVALID_HANDLE;
    1084     }
    1085 
    1086     /*
    1087      * Try lock it.
    1088      */
    1089     struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
    1090     if (cMillies == RT_INDEFINITE_WAIT)
    1091     {
    1092         /* take rwlock */
    1093         int rc = pthread_rwlock_rdlock(&pIntRWSem->RWLock);
    1094         if (rc)
    1095         {
    1096             AssertMsgFailed(("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
    1097             return RTErrConvertFromErrno(rc);
    1098         }
    1099     }
    1100     else
    1101     {
    1102         /*
    1103          * Get current time and calc end of wait time.
    1104          */
    1105         struct timespec     ts = {0,0};
    1106         clock_gettime(CLOCK_REALTIME, &ts);
    1107         if (cMillies != 0)
    1108         {
    1109             ts.tv_nsec += (cMillies % 1000) * 1000000;
    1110             ts.tv_sec  += cMillies / 1000;
    1111             if (ts.tv_nsec >= 1000000000)
    1112             {
    1113                 ts.tv_nsec -= 1000000000;
    1114                 ts.tv_sec++;
    1115             }
    1116         }
    1117 
    1118         /* take rwlock */
    1119         int rc = pthread_rwlock_timedrdlock(&pIntRWSem->RWLock, &ts);
    1120         if (rc)
    1121         {
    1122             AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
    1123             return RTErrConvertFromErrno(rc);
    1124         }
    1125     }
    1126 
    1127     return VINF_SUCCESS;
    1128 }
    1129 
    1130 
    1131 RTDECL(int)   RTSemRWRequestReadNoResume(RTSEMRW RWSem, unsigned cMillies)
    1132 {
    1133     /* EINTR isn't returned by the wait functions we're using. */
    1134     return RTSemRWRequestRead(RWSem, cMillies);
    1135 }
    1136 
    1137 
    1138 RTDECL(int)   RTSemRWReleaseRead(RTSEMRW RWSem)
    1139 {
    1140     /*
    1141      * Validate input.
    1142      */
    1143     if (!rtsemRWValid(RWSem))
    1144     {
    1145         AssertMsgFailed(("Invalid handle %p!\n", RWSem));
    1146         return VERR_INVALID_HANDLE;
    1147     }
    1148 
    1149     /*
    1150      * Try unlock it.
    1151      */
    1152     struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
    1153     if (pIntRWSem->WROwner == pthread_self())
    1154     {
    1155         AssertMsgFailed(("Tried to read unlock when write owner - read-write sem %p.\n", RWSem));
    1156         return VERR_NOT_OWNER;
    1157     }
    1158     int rc = pthread_rwlock_unlock(&pIntRWSem->RWLock);
    1159     if (rc)
    1160     {
    1161         AssertMsgFailed(("Failed read unlock read-write sem %p, rc=%d.\n", RWSem, rc));
    1162         return RTErrConvertFromErrno(rc);
    1163     }
    1164 
    1165     return VINF_SUCCESS;
    1166 }
    1167 
    1168 
    1169 RTDECL(int)   RTSemRWRequestWrite(RTSEMRW RWSem, unsigned cMillies)
    1170 {
    1171     /*
    1172      * Validate input.
    1173      */
    1174     if (!rtsemRWValid(RWSem))
    1175     {
    1176         AssertMsgFailed(("Invalid handle %p!\n", RWSem));
    1177         return VERR_INVALID_HANDLE;
    1178     }
    1179 
    1180     /*
    1181      * Try lock it.
    1182      */
    1183     struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
    1184     if (cMillies == RT_INDEFINITE_WAIT)
    1185     {
    1186         /* take rwlock */
    1187         int rc = pthread_rwlock_wrlock(&pIntRWSem->RWLock);
    1188         if (rc)
    1189         {
    1190             AssertMsgFailed(("Failed write lock read-write sem %p, rc=%d.\n", RWSem, rc));
    1191             return RTErrConvertFromErrno(rc);
    1192         }
    1193     }
    1194     else
    1195     {
    1196         /*
    1197          * Get current time and calc end of wait time.
    1198          */
    1199         struct timespec     ts = {0,0};
    1200         clock_gettime(CLOCK_REALTIME, &ts);
    1201         if (cMillies != 0)
    1202         {
    1203             ts.tv_nsec += (cMillies % 1000) * 1000000;
    1204             ts.tv_sec  += cMillies / 1000;
    1205             if (ts.tv_nsec >= 1000000000)
    1206             {
    1207                 ts.tv_nsec -= 1000000000;
    1208                 ts.tv_sec++;
    1209             }
    1210         }
    1211 
    1212         /* take rwlock */
    1213         int rc = pthread_rwlock_timedwrlock(&pIntRWSem->RWLock, &ts);
    1214         if (rc)
    1215         {
    1216             AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
    1217             return RTErrConvertFromErrno(rc);
    1218         }
    1219     }
    1220 
    1221     ASMAtomicXchgPtr((void * volatile *)&pIntRWSem->WROwner, (void *)pthread_self());
    1222 
    1223     return VINF_SUCCESS;
    1224 }
    1225 
    1226 
    1227 RTDECL(int)   RTSemRWRequestWriteNoResume(RTSEMRW RWSem, unsigned cMillies)
    1228 {
    1229     /* EINTR isn't returned by the wait functions we're using. */
    1230     return RTSemRWRequestWrite(RWSem, cMillies);
    1231 }
    1232 
    1233 
    1234 RTDECL(int)   RTSemRWReleaseWrite(RTSEMRW RWSem)
    1235 {
    1236     /*
    1237      * Validate input.
    1238      */
    1239     if (!rtsemRWValid(RWSem))
    1240     {
    1241         AssertMsgFailed(("Invalid handle %p!\n", RWSem));
    1242         return VERR_INVALID_HANDLE;
    1243     }
    1244 
    1245     /*
    1246      * Try unlock it.
    1247      */
    1248     pthread_t                   Self = pthread_self();
    1249     struct RTSEMRWINTERNAL   *pIntRWSem = RWSem;
    1250     if (pIntRWSem->WROwner != Self)
    1251     {
    1252         AssertMsgFailed(("Not Write owner!\n"));
    1253         return VERR_NOT_OWNER;
    1254     }
    1255 
    1256     /*
    1257      * Try unlock it.
    1258      */
    1259     AssertMsg(sizeof(pthread_t) == sizeof(void *), ("pthread_t is not the size of a pointer but %d bytes\n", sizeof(pthread_t)));
    1260     ASMAtomicXchgPtr((void * volatile *)&pIntRWSem->WROwner, (void *)(uintptr_t)~0);
    1261     int rc = pthread_rwlock_unlock(&pIntRWSem->RWLock);
    1262     if (rc)
    1263     {
    1264         AssertMsgFailed(("Failed write unlock read-write sem %p, rc=%d.\n", RWSem, rc));
    1265         return RTErrConvertFromErrno(rc);
    1266     }
    1267 
    1268     return VINF_SUCCESS;
    1269 }
    1270 
  • trunk/src/VBox/Runtime/r3/linux/semmutex-linux.cpp

    r6737 r6738  
    11/* $Id$ */
    22/** @file
    3  * innotek Portable Runtime - Semaphores, Linux (AMD64 only ATM).
     3 * innotek Portable Runtime - Mutex Semaphore, Linux  (2.6.x+).
    44 */
    55
     
    4646# define FUTEX_WAIT 0
    4747# define FUTEX_WAKE 1
    48 #endif 
     48#endif
    4949
    5050
     
    5252*   Structures and Typedefs                                                    *
    5353*******************************************************************************/
    54 
    55 /**
    56  * Linux (single wakup) event semaphore.
    57  */
    58 struct RTSEMEVENTINTERNAL
    59 {
    60     /** Magic value. */
    61     intptr_t volatile   iMagic;
    62     /** The futex state variable.
    63      * <0 means signaled.
    64      *  0 means not signaled, no waiters.
    65      * >0 means not signaled, and the value gives the number of waiters.
    66      */
    67     int32_t volatile    cWaiters;
    68 };
    69 
    70 
    71 /**
    72  * Linux multiple wakup event semaphore.
    73  */
    74 struct RTSEMEVENTMULTIINTERNAL
    75 {
    76     /** Magic value. */
    77     intptr_t volatile   iMagic;
    78     /** The futex state variable.
    79      * -1 means signaled.
    80      *  0 means not signaled, no waiters.
    81      * >0 means not signaled, and the value gives the number of waiters.
    82      */
    83     int32_t volatile    iState;
    84 };
    85 
    86 
    87 #ifndef VBOX_REWRITTEN_MUTEX
    88 /**
    89  * Posix internal representation of a Mutex semaphore.
    90  */
    91 struct RTSEMMUTEXINTERNAL
    92 {
    93     /** pthread mutex. */
    94     pthread_mutex_t     Mutex;
    95     /** The owner of the mutex. */
    96     volatile pthread_t  Owner;
    97     /** Nesting count. */
    98     volatile uint32_t   cNesting;
    99 };
    100 #else /* VBOX_REWRITTEN_MUTEX */
    10154/**
    10255 * Linux internal representation of a Mutex semaphore.
     
    11770    volatile uint32_t   cNesting;
    11871};
    119 #endif /* VBOX_REWRITTEN_MUTEX */
    120 
    121 
    122 /**
    123  * Posix internal representation of a read-write semaphore.
    124  */
    125 struct RTSEMRWINTERNAL
    126 {
    127     /** pthread rwlock. */
    128     pthread_rwlock_t    RWLock;
    129     /** Variable to check if initialized.
    130      * 0 is uninitialized, ~0 is inititialized. */
    131     volatile unsigned   uCheck;
    132     /** The write owner of the lock. */
    133     volatile pthread_t  WROwner;
    134 };
    13572
    13673
     
    14986    return rc;
    15087}
    151 
    152 
    153 
    154 RTDECL(int)  RTSemEventCreate(PRTSEMEVENT pEventSem)
    155 {
    156     /*
    157      * Allocate semaphore handle.
    158      */
    159     struct RTSEMEVENTINTERNAL *pIntEventSem = (struct RTSEMEVENTINTERNAL *)RTMemAlloc(sizeof(struct RTSEMEVENTINTERNAL));
    160     if (pIntEventSem)
    161     {
    162         pIntEventSem->iMagic = RTSEMEVENT_MAGIC;
    163         pIntEventSem->cWaiters = 0;
    164         *pEventSem = pIntEventSem;
    165         return VINF_SUCCESS;
    166     }
    167     return  VERR_NO_MEMORY;
    168 }
    169 
    170 
    171 RTDECL(int)  RTSemEventDestroy(RTSEMEVENT EventSem)
    172 {
    173     /*
    174      * Validate input.
    175      */
    176     struct RTSEMEVENTINTERNAL *pIntEventSem = EventSem;
    177     AssertReturn(VALID_PTR(pIntEventSem) && pIntEventSem->iMagic == RTSEMEVENT_MAGIC,
    178                  VERR_INVALID_HANDLE);
    179 
    180     /*
    181      * Invalidate the semaphore and wake up anyone waiting on it.
    182      */
    183     ASMAtomicXchgSize(&pIntEventSem->iMagic, RTSEMEVENT_MAGIC + 1);
    184     if (ASMAtomicXchgS32(&pIntEventSem->cWaiters, INT32_MIN / 2) > 0)
    185     {
    186         sys_futex(&pIntEventSem->cWaiters, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
    187         usleep(1000);
    188     }
    189 
    190     /*
    191      * Free the semaphore memory and be gone.
    192      */
    193     RTMemFree(pIntEventSem);
    194     return VINF_SUCCESS;
    195 }
    196 
    197 
    198 RTDECL(int)  RTSemEventSignal(RTSEMEVENT EventSem)
    199 {
    200     /*
    201      * Validate input.
    202      */
    203     struct RTSEMEVENTINTERNAL *pIntEventSem = EventSem;
    204     AssertReturn(VALID_PTR(pIntEventSem) && pIntEventSem->iMagic == RTSEMEVENT_MAGIC,
    205                  VERR_INVALID_HANDLE);
    206     /*
    207      * Try signal it.
    208      */
    209     for (unsigned i = 0;; i++)
    210     {
    211         int32_t iCur = pIntEventSem->cWaiters;
    212         if (iCur == 0)
    213         {
    214             if (ASMAtomicCmpXchgS32(&pIntEventSem->cWaiters, -1, 0))
    215                 break; /* nobody is waiting */
    216         }
    217         else if (iCur < 0)
    218             break; /* already signaled */
    219         else
    220         {
    221             /* somebody is waiting, try wake up one of them. */
    222             long cWoken = sys_futex(&pIntEventSem->cWaiters, FUTEX_WAKE, 1, NULL, NULL, 0);
    223             if (RT_LIKELY(cWoken == 1))
    224             {
    225                 ASMAtomicDecS32(&pIntEventSem->cWaiters);
    226                 break;
    227             }
    228             AssertMsg(cWoken == 0, ("%ld\n", cWoken));
    229 
    230             /*
    231              * This path is taken in two situations:
    232              *      1) A waiting thread is returning from the sys_futex call with a
    233              *         non-zero return value.
    234              *      2) There are two threads signaling the event at the
    235              *         same time and only one thread waiting.
    236              *
    237              * At this point we know that nobody is activly waiting on the event but
    238              * at the same time, we are racing someone updating the state. The current
    239              * strategy is to spin till the thread racing us is done, this is kind of
    240              * brain dead and need fixing of course.
    241              */
    242             if (RT_UNLIKELY(i > 32))
    243             {
    244                 if ((i % 128) == 127)
    245                     usleep(1000);
    246                 else if (!(i % 4))
    247                     pthread_yield();
    248                 else
    249                     AssertReleaseMsg(i < 4096, ("iCur=%#x pIntEventSem=%p\n", iCur, pIntEventSem));
    250             }
    251         }
    252     }
    253     return VINF_SUCCESS;
    254 }
    255 
    256 
    257 static int rtSemEventWait(RTSEMEVENT EventSem, unsigned cMillies, bool fAutoResume)
    258 {
    259     /*
    260      * Validate input.
    261      */
    262     struct RTSEMEVENTINTERNAL *pIntEventSem = EventSem;
    263     AssertReturn(VALID_PTR(pIntEventSem) && pIntEventSem->iMagic == RTSEMEVENT_MAGIC,
    264                  VERR_INVALID_HANDLE);
    265 
    266     /*
    267      * Quickly check whether it's signaled.
    268      */
    269     if (ASMAtomicCmpXchgS32(&pIntEventSem->cWaiters, 0, -1))
    270         return VINF_SUCCESS;
    271 
    272     /*
    273      * Convert timeout value.
    274      */
    275     struct timespec ts;
    276     struct timespec *pTimeout = 0;
    277     if (cMillies != RT_INDEFINITE_WAIT)
    278     {
    279         ts.tv_sec  = cMillies / 1000;
    280         ts.tv_nsec = (cMillies % 1000) * 1000000;
    281         pTimeout = &ts;
    282     }
    283 
    284     /*
    285      * The wait loop.
    286      */
    287     for (unsigned i = 0;; i++)
    288     {
    289         /*
    290          * Announce that we're among the waiters.
    291          */
    292         int32_t iNew = ASMAtomicIncS32(&pIntEventSem->cWaiters);
    293         if (iNew == 0)
    294             return VINF_SUCCESS;
    295         if (RT_LIKELY(iNew > 0))
    296         {
    297             /*
    298              * Go to sleep.
    299              */
    300             long rc = sys_futex(&pIntEventSem->cWaiters, FUTEX_WAIT, iNew, pTimeout, NULL, 0);
    301             if (RT_UNLIKELY(pIntEventSem->iMagic != RTSEMEVENT_MAGIC))
    302                 return VERR_SEM_DESTROYED;
    303 
    304             /* Did somebody wake us up from RTSemEventSignal()? */
    305             if (rc == 0)
    306                 return VINF_SUCCESS;
    307 
    308             /* No, then the kernel woke us up or we failed going to sleep. Adjust the accounting. */
    309             iNew = ASMAtomicDecS32(&pIntEventSem->cWaiters);
    310             Assert(iNew >= 0);
    311 
    312             /*
    313              * Act on the wakup code.
    314              */
    315             if (rc == -ETIMEDOUT)
    316             {
    317                 Assert(pTimeout);
    318                 return VERR_TIMEOUT;
    319             }
    320             if (rc == -EWOULDBLOCK)
    321                 /* retry with new value. */;
    322             else if (rc == -EINTR)
    323             {
    324                 if (!fAutoResume)
    325                     return VERR_INTERRUPTED;
    326             }
    327             else
    328             {
    329                 /* this shouldn't happen! */
    330                 AssertMsgFailed(("rc=%ld errno=%d\n", rc, errno));
    331                 return RTErrConvertFromErrno(rc);
    332             }
    333         }
    334         else
    335         {
    336             /* this can't happen. */
    337             if (RT_UNLIKELY(pIntEventSem->iMagic != RTSEMEVENT_MAGIC))
    338                 return VERR_SEM_DESTROYED;
    339             AssertReleaseMsgFailed(("iNew=%d\n", iNew));
    340         }
    341     }
    342 }
    343 
    344 
    345 RTDECL(int)  RTSemEventWait(RTSEMEVENT EventSem, unsigned cMillies)
    346 {
    347     int rc = rtSemEventWait(EventSem, cMillies, true);
    348     Assert(rc != VERR_INTERRUPTED);
    349     return rc;
    350 }
    351 
    352 
    353 RTDECL(int)  RTSemEventWaitNoResume(RTSEMEVENT EventSem, unsigned cMillies)
    354 {
    355     return rtSemEventWait(EventSem, cMillies, false);
    356 }
    357 
    358 
    359 
    360 
    361 
    362 RTDECL(int)  RTSemEventMultiCreate(PRTSEMEVENTMULTI pEventMultiSem)
    363 {
    364     /*
    365      * Allocate semaphore handle.
    366      */
    367     struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem = (struct RTSEMEVENTMULTIINTERNAL *)RTMemAlloc(sizeof(struct RTSEMEVENTMULTIINTERNAL));
    368     if (pIntEventMultiSem)
    369     {
    370         pIntEventMultiSem->iMagic = RTSEMEVENTMULTI_MAGIC;
    371         pIntEventMultiSem->iState = 0;
    372         *pEventMultiSem = pIntEventMultiSem;
    373         return VINF_SUCCESS;
    374     }
    375     return  VERR_NO_MEMORY;
    376 }
    377 
    378 
    379 RTDECL(int)  RTSemEventMultiDestroy(RTSEMEVENTMULTI EventMultiSem)
    380 {
    381     /*
    382      * Validate input.
    383      */
    384     struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem = EventMultiSem;
    385     AssertReturn(VALID_PTR(pIntEventMultiSem) && pIntEventMultiSem->iMagic == RTSEMEVENTMULTI_MAGIC,
    386                  VERR_INVALID_HANDLE);
    387 
    388     /*
    389      * Invalidate the semaphore and wake up anyone waiting on it.
    390      */
    391     ASMAtomicXchgSize(&pIntEventMultiSem->iMagic, RTSEMEVENTMULTI_MAGIC + 1);
    392     if (ASMAtomicXchgS32(&pIntEventMultiSem->iState, -1) == 1)
    393     {
    394         sys_futex(&pIntEventMultiSem->iState, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
    395         usleep(1000);
    396     }
    397 
    398     /*
    399      * Free the semaphore memory and be gone.
    400      */
    401     RTMemFree(pIntEventMultiSem);
    402     return VINF_SUCCESS;
    403 }
    404 
    405 
    406 RTDECL(int)  RTSemEventMultiSignal(RTSEMEVENTMULTI EventMultiSem)
    407 {
    408     /*
    409      * Validate input.
    410      */
    411     struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem = EventMultiSem;
    412     AssertReturn(VALID_PTR(pIntEventMultiSem) && pIntEventMultiSem->iMagic == RTSEMEVENTMULTI_MAGIC,
    413                  VERR_INVALID_HANDLE);
    414     /*
    415      * Signal it.
    416      */
    417     int32_t iOld = ASMAtomicXchgS32(&pIntEventMultiSem->iState, -1);
    418     if (iOld > 0)
    419     {
    420         /* wake up sleeping threads. */
    421         long cWoken = sys_futex(&pIntEventMultiSem->iState, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
    422         AssertMsg(cWoken >= 0, ("%ld\n", cWoken)); NOREF(cWoken);
    423     }
    424     Assert(iOld == 0 || iOld == -1 || iOld == 1);
    425     return VINF_SUCCESS;
    426 }
    427 
    428 
    429 RTDECL(int)  RTSemEventMultiReset(RTSEMEVENTMULTI EventMultiSem)
    430 {
    431     /*
    432      * Validate input.
    433      */
    434     struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem = EventMultiSem;
    435     AssertReturn(VALID_PTR(pIntEventMultiSem) && pIntEventMultiSem->iMagic == RTSEMEVENTMULTI_MAGIC,
    436                  VERR_INVALID_HANDLE);
    437 #ifdef RT_STRICT
    438     int32_t i = pIntEventMultiSem->iState;
    439     Assert(i == 0 || i == -1 || i == 1);
    440 #endif
    441 
    442     /*
    443      * Reset it.
    444      */
    445     ASMAtomicCmpXchgS32(&pIntEventMultiSem->iState, 0, -1);
    446     return VINF_SUCCESS;
    447 }
    448 
    449 
    450 static int rtSemEventMultiWait(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies, bool fAutoResume)
    451 {
    452     /*
    453      * Validate input.
    454      */
    455     struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem = EventMultiSem;
    456     AssertReturn(VALID_PTR(pIntEventMultiSem) && pIntEventMultiSem->iMagic == RTSEMEVENTMULTI_MAGIC,
    457                  VERR_INVALID_HANDLE);
    458 
    459     /*
    460      * Quickly check whether it's signaled.
    461      */
    462     int32_t iCur = pIntEventMultiSem->iState;
    463     Assert(iCur == 0 || iCur == -1 || iCur == 1);
    464     if (iCur == -1)
    465         return VINF_SUCCESS;
    466     if (!cMillies)
    467         return VERR_TIMEOUT;
    468 
    469     /*
    470      * Convert timeout value.
    471      */
    472     struct timespec ts;
    473     struct timespec *pTimeout = NULL;
    474     if (cMillies != RT_INDEFINITE_WAIT)
    475     {
    476         ts.tv_sec  = cMillies / 1000;
    477         ts.tv_nsec = (cMillies % 1000) * 1000000;
    478         pTimeout = &ts;
    479     }
    480 
    481     /*
    482      * The wait loop.
    483      */
    484     for (unsigned i = 0;; i++)
    485     {
    486         /*
    487          * Start waiting. We only account for there being or having been
    488          * threads waiting on the semaphore to keep things simple.
    489          */
    490         iCur = pIntEventMultiSem->iState;
    491         Assert(iCur == 0 || iCur == -1 || iCur == 1);
    492         if (    iCur == 1
    493             ||  ASMAtomicCmpXchgS32(&pIntEventMultiSem->iState, 1, 0))
    494         {
    495             long rc = sys_futex(&pIntEventMultiSem->iState, FUTEX_WAIT, 1, pTimeout, NULL, 0);
    496             if (RT_UNLIKELY(pIntEventMultiSem->iMagic != RTSEMEVENTMULTI_MAGIC))
    497                 return VERR_SEM_DESTROYED;
    498             if (rc == 0)
    499                 return VINF_SUCCESS;
    500 
    501             /*
    502              * Act on the wakup code.
    503              */
    504             if (rc == -ETIMEDOUT)
    505             {
    506                 Assert(pTimeout);
    507                 return VERR_TIMEOUT;
    508             }
    509             if (rc == -EWOULDBLOCK)
    510                 /* retry, the value changed. */;
    511             else if (rc == -EINTR)
    512             {
    513                 if (!fAutoResume)
    514                     return VERR_INTERRUPTED;
    515             }
    516             else
    517             {
    518                 /* this shouldn't happen! */
    519                 AssertMsgFailed(("rc=%ld errno=%d\n", rc, errno));
    520                 return RTErrConvertFromErrno(rc);
    521             }
    522         }
    523         else if (iCur == -1)
    524             return VINF_SUCCESS;
    525     }
    526 }
    527 
    528 
    529 RTDECL(int)  RTSemEventMultiWait(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies)
    530 {
    531     int rc = rtSemEventMultiWait(EventMultiSem, cMillies, true);
    532     Assert(rc != VERR_INTERRUPTED);
    533     return rc;
    534 }
    535 
    536 
    537 RTDECL(int)  RTSemEventMultiWaitNoResume(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies)
    538 {
    539     return rtSemEventMultiWait(EventMultiSem, cMillies, false);
    540 }
    541 
    542 
    543 
    54488
    54589
     
    556100        return false;
    557101
    558 #ifdef VBOX_REWRITTEN_MUTEX
    559102    if (pIntMutexSem->iMagic != RTSEMMUTEX_MAGIC)
    560103        return false;
    561104
    562 #endif /* VBOX_REWRITTEN_MUTEX */
    563105    if (pIntMutexSem->cNesting == (uint32_t)~0)
    564106        return false;
     
    568110
    569111
    570 #ifndef VBOX_REWRITTEN_MUTEX
    571 RTDECL(int)  RTSemMutexCreate(PRTSEMMUTEX pMutexSem)
    572 {
    573     int rc;
    574 
    575     /*
    576      * Allocate semaphore handle.
    577      */
    578     struct RTSEMMUTEXINTERNAL *pIntMutexSem = (struct RTSEMMUTEXINTERNAL *)RTMemAlloc(sizeof(struct RTSEMMUTEXINTERNAL));
    579     if (pIntMutexSem)
    580     {
    581         /*
    582          * Create the semaphore.
    583          */
    584         pthread_mutexattr_t MutexAttr;
    585         rc = pthread_mutexattr_init(&MutexAttr);
    586         if (!rc)
    587         {
    588             rc = pthread_mutex_init(&pIntMutexSem->Mutex, &MutexAttr);
    589             if (!rc)
    590             {
    591                 pthread_mutexattr_destroy(&MutexAttr);
    592 
    593                 pIntMutexSem->Owner    = (pthread_t)~0;
    594                 pIntMutexSem->cNesting = 0;
    595 
    596                 *pMutexSem = pIntMutexSem;
    597                 return VINF_SUCCESS;
    598             }
    599             pthread_mutexattr_destroy(&MutexAttr);
    600         }
    601         RTMemFree(pIntMutexSem);
    602     }
    603     else
    604         rc = VERR_NO_MEMORY;
    605 
    606     return rc;
    607 }
    608 
    609 
    610 RTDECL(int)  RTSemMutexDestroy(RTSEMMUTEX MutexSem)
    611 {
    612     /*
    613      * Validate input.
    614      */
    615     if (!rtsemMutexValid(MutexSem))
    616     {
    617         AssertMsgFailed(("Invalid handle %p!\n", MutexSem));
    618         return VERR_INVALID_HANDLE;
    619     }
    620 
    621     /*
    622      * Try destroy it.
    623      */
    624     struct RTSEMMUTEXINTERNAL *pIntMutexSem = MutexSem;
    625     int rc = pthread_mutex_destroy(&pIntMutexSem->Mutex);
    626     if (rc)
    627     {
    628         AssertMsgFailed(("Failed to destroy mutex sem %p, rc=%d.\n", MutexSem, rc));
    629         return RTErrConvertFromErrno(rc);
    630     }
    631 
    632     /*
    633      * Free the memory and be gone.
    634      */
    635     pIntMutexSem->Owner    = (pthread_t)~0;
    636     pIntMutexSem->cNesting = ~0;
    637     RTMemTmpFree(pIntMutexSem);
    638 
    639     return VINF_SUCCESS;
    640 }
    641 
    642 
    643 RTDECL(int)  RTSemMutexRequest(RTSEMMUTEX MutexSem, unsigned cMillies)
    644 {
    645     /*
    646      * Validate input.
    647      */
    648     if (!rtsemMutexValid(MutexSem))
    649     {
    650         AssertMsgFailed(("Invalid handle %p!\n", MutexSem));
    651         return VERR_INVALID_HANDLE;
    652     }
    653 
    654     /*
    655      * Check if nested request.
    656      */
    657     pthread_t                       Self = pthread_self();
    658     struct RTSEMMUTEXINTERNAL    *pIntMutexSem = MutexSem;
    659     if (    pIntMutexSem->Owner == Self
    660         &&  pIntMutexSem->cNesting > 0)
    661     {
    662         pIntMutexSem->cNesting++;
    663         return VINF_SUCCESS;
    664     }
    665 
    666     /*
    667      * Lock it.
    668      */
    669     if (cMillies == RT_INDEFINITE_WAIT)
    670     {
    671         /* take mutex */
    672         int rc = pthread_mutex_lock(&pIntMutexSem->Mutex);
    673         if (rc)
    674         {
    675             AssertMsgFailed(("Failed to lock mutex sem %p, rc=%d.\n", MutexSem, rc)); NOREF(rc);
    676             return RTErrConvertFromErrno(rc);
    677         }
    678     }
    679     else
    680     {
    681         /*
    682          * Get current time and calc end of wait time.
    683          */
    684         struct timespec     ts = {0,0};
    685         clock_gettime(CLOCK_REALTIME, &ts);
    686         if (cMillies != 0)
    687         {
    688             ts.tv_nsec += (cMillies % 1000) * 1000000;
    689             ts.tv_sec  += cMillies / 1000;
    690             if (ts.tv_nsec >= 1000000000)
    691             {
    692                 ts.tv_nsec -= 1000000000;
    693                 ts.tv_sec++;
    694             }
    695         }
    696 
    697         /* take mutex */
    698         int rc = pthread_mutex_timedlock(&pIntMutexSem->Mutex, &ts);
    699         if (rc)
    700         {
    701             AssertMsg(rc == ETIMEDOUT, ("Failed to lock mutex sem %p, rc=%d.\n", MutexSem, rc)); NOREF(rc);
    702             return RTErrConvertFromErrno(rc);
    703         }
    704     }
    705 
    706     /*
    707      * Set the owner and nesting.
    708      */
    709     pIntMutexSem->Owner = Self;
    710     ASMAtomicXchgU32(&pIntMutexSem->cNesting, 1);
    711 
    712     return VINF_SUCCESS;
    713 }
    714 
    715 
    716 RTDECL(int)  RTSemMutexRequestNoResume(RTSEMMUTEX MutexSem, unsigned cMillies)
    717 {
    718     /* EINTR isn't returned by the wait functions we're using. */
    719     return RTSemMutexRequest(MutexSem, cMillies);
    720 }
    721 
    722 
    723 RTDECL(int)  RTSemMutexRelease(RTSEMMUTEX MutexSem)
    724 {
    725     /*
    726      * Validate input.
    727      */
    728     if (!rtsemMutexValid(MutexSem))
    729     {
    730         AssertMsgFailed(("Invalid handle %p!\n", MutexSem));
    731         return VERR_INVALID_HANDLE;
    732     }
    733 
    734     /*
    735      * Check if nested.
    736      */
    737     pthread_t                       Self = pthread_self();
    738     struct RTSEMMUTEXINTERNAL    *pIntMutexSem = MutexSem;
    739     if (    pIntMutexSem->Owner != Self
    740         ||  pIntMutexSem->cNesting == (uint32_t)~0)
    741     {
    742         AssertMsgFailed(("Not owner of mutex %p!! Self=%08x Owner=%08x cNesting=%d\n",
    743                          pIntMutexSem, Self, pIntMutexSem->Owner, pIntMutexSem->cNesting));
    744         return VERR_NOT_OWNER;
    745     }
    746 
    747     /*
    748      * If nested we'll just pop a nesting.
    749      */
    750     if (pIntMutexSem->cNesting > 1)
    751     {
    752         pIntMutexSem->cNesting--;
    753         return VINF_SUCCESS;
    754     }
    755 
    756     /*
    757      * Clear the state. (cNesting == 1)
    758      */
    759     pIntMutexSem->Owner    = (pthread_t)~0;
    760     ASMAtomicXchgU32(&pIntMutexSem->cNesting, 0);
    761 
    762     /*
    763      * Unlock mutex semaphore.
    764      */
    765     int rc = pthread_mutex_unlock(&pIntMutexSem->Mutex);
    766     if (rc)
    767     {
    768         AssertMsgFailed(("Failed to unlock mutex sem %p, rc=%d.\n", MutexSem, rc)); NOREF(rc);
    769         return RTErrConvertFromErrno(rc);
    770     }
    771 
    772     return VINF_SUCCESS;
    773 }
    774 #else /* VBOX_REWRITTEN_MUTEX */
    775112RTDECL(int)  RTSemMutexCreate(PRTSEMMUTEX pMutexSem)
    776113{
     
    913250         * When leaving this loop, iState is set to 2. This means that we gained the
    914251         * Lock and there are _possibly_ some waiters. We don't know exactly as another
    915          * Thread might entered this loop at nearly the same time. Therefore we will
     252         * thread might entered this loop at nearly the same time. Therefore we will
    916253         * call futex_wakeup once too often (if _no_ other thread entered this loop).
    917254         * The key problem is the simple futex_wait test for x != y (iState != 2) in
     
    994331    return VINF_SUCCESS;
    995332}
    996 #endif /* VBOX_REWRITTEN_MUTEX */
    997 
    998 
    999 
    1000 
    1001 /**
    1002  * Validate a read-write semaphore handle passed to one of the interface.
    1003  *
    1004  * @returns true if valid.
    1005  * @returns false if invalid.
    1006  * @param   pIntRWSem   Pointer to the read-write semaphore to validate.
    1007  */
    1008 inline bool rtsemRWValid(struct RTSEMRWINTERNAL *pIntRWSem)
    1009 {
    1010     if ((uintptr_t)pIntRWSem < 0x10000)
    1011         return false;
    1012 
    1013     if (pIntRWSem->uCheck != (unsigned)~0)
    1014         return false;
    1015 
    1016     return true;
    1017 }
    1018 
    1019 
    1020 RTDECL(int)   RTSemRWCreate(PRTSEMRW pRWSem)
    1021 {
    1022     int rc;
    1023 
    1024     /*
    1025      * Allocate handle.
    1026      */
    1027     struct RTSEMRWINTERNAL *pIntRWSem = (struct RTSEMRWINTERNAL *)RTMemAlloc(sizeof(struct RTSEMRWINTERNAL));
    1028     if (pIntRWSem)
    1029     {
    1030         /*
    1031          * Create the rwlock.
    1032          */
    1033         pthread_rwlockattr_t    Attr;
    1034         rc = pthread_rwlockattr_init(&Attr);
    1035         if (!rc)
    1036         {
    1037             rc = pthread_rwlock_init(&pIntRWSem->RWLock, &Attr);
    1038             if (!rc)
    1039             {
    1040                 pIntRWSem->uCheck = ~0;
    1041                 pIntRWSem->WROwner = (pthread_t)~0;
    1042                 *pRWSem = pIntRWSem;
    1043                 return VINF_SUCCESS;
    1044             }
    1045         }
    1046 
    1047         rc = RTErrConvertFromErrno(rc);
    1048         RTMemFree(pIntRWSem);
    1049     }
    1050     else
    1051         rc = VERR_NO_MEMORY;
    1052 
    1053     return rc;
    1054 }
    1055 
    1056 
    1057 RTDECL(int)   RTSemRWDestroy(RTSEMRW RWSem)
    1058 {
    1059     /*
    1060      * Validate input.
    1061      */
    1062     if (!rtsemRWValid(RWSem))
    1063     {
    1064         AssertMsgFailed(("Invalid handle %p!\n", RWSem));
    1065         return VERR_INVALID_HANDLE;
    1066     }
    1067 
    1068     /*
    1069      * Try destroy it.
    1070      */
    1071     struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
    1072     int rc = pthread_rwlock_destroy(&pIntRWSem->RWLock);
    1073     if (!rc)
    1074     {
    1075         pIntRWSem->uCheck = 0;
    1076         RTMemFree(pIntRWSem);
    1077         rc = VINF_SUCCESS;
    1078     }
    1079     else
    1080     {
    1081         AssertMsgFailed(("Failed to destroy read-write sem %p, rc=%d.\n", RWSem, rc));
    1082         rc = RTErrConvertFromErrno(rc);
    1083     }
    1084 
    1085     return rc;
    1086 }
    1087 
    1088 
    1089 RTDECL(int)   RTSemRWRequestRead(RTSEMRW RWSem, unsigned cMillies)
    1090 {
    1091     /*
    1092      * Validate input.
    1093      */
    1094     if (!rtsemRWValid(RWSem))
    1095     {
    1096         AssertMsgFailed(("Invalid handle %p!\n", RWSem));
    1097         return VERR_INVALID_HANDLE;
    1098     }
    1099 
    1100     /*
    1101      * Try lock it.
    1102      */
    1103     struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
    1104     if (cMillies == RT_INDEFINITE_WAIT)
    1105     {
    1106         /* take rwlock */
    1107         int rc = pthread_rwlock_rdlock(&pIntRWSem->RWLock);
    1108         if (rc)
    1109         {
    1110             AssertMsgFailed(("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
    1111             return RTErrConvertFromErrno(rc);
    1112         }
    1113     }
    1114     else
    1115     {
    1116         /*
    1117          * Get current time and calc end of wait time.
    1118          */
    1119         struct timespec     ts = {0,0};
    1120         clock_gettime(CLOCK_REALTIME, &ts);
    1121         if (cMillies != 0)
    1122         {
    1123             ts.tv_nsec += (cMillies % 1000) * 1000000;
    1124             ts.tv_sec  += cMillies / 1000;
    1125             if (ts.tv_nsec >= 1000000000)
    1126             {
    1127                 ts.tv_nsec -= 1000000000;
    1128                 ts.tv_sec++;
    1129             }
    1130         }
    1131 
    1132         /* take rwlock */
    1133         int rc = pthread_rwlock_timedrdlock(&pIntRWSem->RWLock, &ts);
    1134         if (rc)
    1135         {
    1136             AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
    1137             return RTErrConvertFromErrno(rc);
    1138         }
    1139     }
    1140 
    1141     return VINF_SUCCESS;
    1142 }
    1143 
    1144 
    1145 RTDECL(int)   RTSemRWRequestReadNoResume(RTSEMRW RWSem, unsigned cMillies)
    1146 {
    1147     /* EINTR isn't returned by the wait functions we're using. */
    1148     return RTSemRWRequestRead(RWSem, cMillies);
    1149 }
    1150 
    1151 
    1152 RTDECL(int)   RTSemRWReleaseRead(RTSEMRW RWSem)
    1153 {
    1154     /*
    1155      * Validate input.
    1156      */
    1157     if (!rtsemRWValid(RWSem))
    1158     {
    1159         AssertMsgFailed(("Invalid handle %p!\n", RWSem));
    1160         return VERR_INVALID_HANDLE;
    1161     }
    1162 
    1163     /*
    1164      * Try unlock it.
    1165      */
    1166     struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
    1167     if (pIntRWSem->WROwner == pthread_self())
    1168     {
    1169         AssertMsgFailed(("Tried to read unlock when write owner - read-write sem %p.\n", RWSem));
    1170         return VERR_NOT_OWNER;
    1171     }
    1172     int rc = pthread_rwlock_unlock(&pIntRWSem->RWLock);
    1173     if (rc)
    1174     {
    1175         AssertMsgFailed(("Failed read unlock read-write sem %p, rc=%d.\n", RWSem, rc));
    1176         return RTErrConvertFromErrno(rc);
    1177     }
    1178 
    1179     return VINF_SUCCESS;
    1180 }
    1181 
    1182 
    1183 RTDECL(int)   RTSemRWRequestWrite(RTSEMRW RWSem, unsigned cMillies)
    1184 {
    1185     /*
    1186      * Validate input.
    1187      */
    1188     if (!rtsemRWValid(RWSem))
    1189     {
    1190         AssertMsgFailed(("Invalid handle %p!\n", RWSem));
    1191         return VERR_INVALID_HANDLE;
    1192     }
    1193 
    1194     /*
    1195      * Try lock it.
    1196      */
    1197     struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
    1198     if (cMillies == RT_INDEFINITE_WAIT)
    1199     {
    1200         /* take rwlock */
    1201         int rc = pthread_rwlock_wrlock(&pIntRWSem->RWLock);
    1202         if (rc)
    1203         {
    1204             AssertMsgFailed(("Failed write lock read-write sem %p, rc=%d.\n", RWSem, rc));
    1205             return RTErrConvertFromErrno(rc);
    1206         }
    1207     }
    1208     else
    1209     {
    1210         /*
    1211          * Get current time and calc end of wait time.
    1212          */
    1213         struct timespec     ts = {0,0};
    1214         clock_gettime(CLOCK_REALTIME, &ts);
    1215         if (cMillies != 0)
    1216         {
    1217             ts.tv_nsec += (cMillies % 1000) * 1000000;
    1218             ts.tv_sec  += cMillies / 1000;
    1219             if (ts.tv_nsec >= 1000000000)
    1220             {
    1221                 ts.tv_nsec -= 1000000000;
    1222                 ts.tv_sec++;
    1223             }
    1224         }
    1225 
    1226         /* take rwlock */
    1227         int rc = pthread_rwlock_timedwrlock(&pIntRWSem->RWLock, &ts);
    1228         if (rc)
    1229         {
    1230             AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
    1231             return RTErrConvertFromErrno(rc);
    1232         }
    1233     }
    1234 
    1235     ASMAtomicXchgPtr((void * volatile *)&pIntRWSem->WROwner, (void *)pthread_self());
    1236 
    1237     return VINF_SUCCESS;
    1238 }
    1239 
    1240 
    1241 RTDECL(int)   RTSemRWRequestWriteNoResume(RTSEMRW RWSem, unsigned cMillies)
    1242 {
    1243     /* EINTR isn't returned by the wait functions we're using. */
    1244     return RTSemRWRequestWrite(RWSem, cMillies);
    1245 }
    1246 
    1247 
    1248 RTDECL(int)   RTSemRWReleaseWrite(RTSEMRW RWSem)
    1249 {
    1250     /*
    1251      * Validate input.
    1252      */
    1253     if (!rtsemRWValid(RWSem))
    1254     {
    1255         AssertMsgFailed(("Invalid handle %p!\n", RWSem));
    1256         return VERR_INVALID_HANDLE;
    1257     }
    1258 
    1259     /*
    1260      * Try unlock it.
    1261      */
    1262     pthread_t                   Self = pthread_self();
    1263     struct RTSEMRWINTERNAL   *pIntRWSem = RWSem;
    1264     if (pIntRWSem->WROwner != Self)
    1265     {
    1266         AssertMsgFailed(("Not Write owner!\n"));
    1267         return VERR_NOT_OWNER;
    1268     }
    1269 
    1270     /*
    1271      * Try unlock it.
    1272      */
    1273     AssertMsg(sizeof(pthread_t) == sizeof(void *), ("pthread_t is not the size of a pointer but %d bytes\n", sizeof(pthread_t)));
    1274     ASMAtomicXchgPtr((void * volatile *)&pIntRWSem->WROwner, (void *)(uintptr_t)~0);
    1275     int rc = pthread_rwlock_unlock(&pIntRWSem->RWLock);
    1276     if (rc)
    1277     {
    1278         AssertMsgFailed(("Failed write unlock read-write sem %p, rc=%d.\n", RWSem, rc));
    1279         return RTErrConvertFromErrno(rc);
    1280     }
    1281 
    1282     return VINF_SUCCESS;
    1283 }
    1284 
     333
  • trunk/src/VBox/Runtime/r3/posix/semevent-posix.cpp

    r6734 r6738  
    11/* $Id$ */
    22/** @file
    3  * innotek Portable Runtime - Semaphores, POSIX.
     3 * innotek Portable Runtime - Event Semaphore, POSIX.
    44 */
    55
     
    5656 * The POSIX implementation uses a mutex and a condition variable to implement
    5757 * the automatic reset event semaphore semantics.
    58  *
    59  * This must be identical to RTSEMEVENTMULTIINTERNAL!
    6058 */
    6159struct RTSEMEVENTINTERNAL
     
    7270};
    7371
    74 /** Posix internal representation of a Mutex Multi semaphore.
    75  * This must be identical to RTSEMEVENTINTERNAL! */
    76 struct RTSEMEVENTMULTIINTERNAL
    77 {
    78     /** pthread condition. */
    79     pthread_cond_t      Cond;
    80     /** pthread mutex which protects the condition and the event state. */
    81     pthread_mutex_t     Mutex;
    82     /** The state of the semaphore.
    83      * This is operated while owning mutex and using atomic updating. */
    84     volatile uint32_t   u32State;
    85     /** Number of waiters. */
    86     volatile uint32_t   cWaiters;
    87 };
    88 
    89 /** The valus of the u32State variable in a RTSEMEVENTINTERNAL and RTSEMEVENTMULTIINTERNAL.
     72/** The valus of the u32State variable in a RTSEMEVENTINTERNAL.
    9073 * @{ */
    9174/** The object isn't initialized. */
     
    9679#define EVENT_STATE_NOT_SIGNALED    0x00ff00ff
    9780/** @} */
    98 
    99 
    100 /** Posix internal representation of a Mutex semaphore. */
    101 struct RTSEMMUTEXINTERNAL
    102 {
    103     /** pthread mutex. */
    104     pthread_mutex_t     Mutex;
    105     /** The owner of the mutex. */
    106     volatile pthread_t  Owner;
    107     /** Nesting count. */
    108     volatile uint32_t   cNesting;
    109 };
    110 
    111 /** Posix internal representation of a read-write semaphore. */
    112 struct RTSEMRWINTERNAL
    113 {
    114     /** pthread rwlock. */
    115     pthread_rwlock_t    RWLock;
    116     /** Variable to check if initialized.
    117      * 0 is uninitialized, ~0 is inititialized. */
    118     volatile unsigned   uCheck;
    119     /** The write owner of the lock. */
    120     volatile pthread_t  WROwner;
    121 };
    12281
    12382
     
    458417}
    459418
    460 
    461 
    462 
    463 
    464 
    465 /**
    466  * Validate an event multi semaphore handle passed to one of the interface.
    467  *
    468  * @returns true if valid.
    469  * @returns false if invalid.
    470  * @param   pIntEventMultiSem    Pointer to the event semaphore to validate.
    471  */
    472 inline bool rtsemEventMultiValid(struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem)
    473 {
    474     if ((uintptr_t)pIntEventMultiSem < 0x10000)
    475         return false;
    476 
    477     uint32_t    u32 = pIntEventMultiSem->u32State; /* this is volatile, so a explicit read like this is needed. */
    478     if (    u32 != EVENT_STATE_NOT_SIGNALED
    479         &&  u32 != EVENT_STATE_SIGNALED)
    480         return false;
    481 
    482     return true;
    483 }
    484 
    485 
    486 RTDECL(int)  RTSemEventMultiCreate(PRTSEMEVENTMULTI pEventMultiSem)
    487 {
    488     /* the code and the structure is identical with other type for this function. */
    489     return RTSemEventCreate((PRTSEMEVENT)pEventMultiSem);
    490 }
    491 
    492 
    493 RTDECL(int)  RTSemEventMultiDestroy(RTSEMEVENTMULTI EventMultiSem)
    494 {
    495     /* the code and the structure is identical with other type for this function. */
    496     return RTSemEventDestroy((RTSEMEVENT)EventMultiSem);
    497 }
    498 
    499 
    500 RTDECL(int)  RTSemEventMultiSignal(RTSEMEVENTMULTI EventMultiSem)
    501 {
    502     /* the code and the structure is identical with other type for this function. */
    503     return RTSemEventSignal((RTSEMEVENT)EventMultiSem);
    504 }
    505 
    506 
    507 RTDECL(int)  RTSemEventMultiReset(RTSEMEVENTMULTI EventMultiSem)
    508 {
    509     /*
    510      * Validate input.
    511      */
    512     if (!rtsemEventMultiValid(EventMultiSem))
    513     {
    514         AssertMsgFailed(("Invalid handle %p!\n", EventMultiSem));
    515         return VERR_INVALID_HANDLE;
    516     }
    517 
    518     /*
    519      * Lock the mutex semaphore.
    520      */
    521     struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem = EventMultiSem;
    522     int rc = pthread_mutex_lock(&pIntEventMultiSem->Mutex);
    523     if (rc)
    524     {
    525         AssertMsgFailed(("Failed to lock event multi sem %p, rc=%d.\n", EventMultiSem, rc));
    526         return RTErrConvertFromErrno(rc);
    527     }
    528 
    529     /*
    530      * Check the state.
    531      */
    532     if (pIntEventMultiSem->u32State == EVENT_STATE_SIGNALED)
    533         ASMAtomicXchgU32(&pIntEventMultiSem->u32State, EVENT_STATE_NOT_SIGNALED);
    534     else if (pIntEventMultiSem->u32State != EVENT_STATE_NOT_SIGNALED)
    535         rc = VERR_SEM_DESTROYED;
    536 
    537     /*
    538      * Release the mutex and return.
    539      */
    540     rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);
    541     if (rc)
    542     {
    543         AssertMsgFailed(("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc));
    544         return RTErrConvertFromErrno(rc);
    545     }
    546 
    547     return VINF_SUCCESS;
    548 
    549 }
    550 
    551 
    552 static int rtSemEventMultiWait(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies, bool fAutoResume)
    553 {
    554     /*
    555      * Validate input.
    556      */
    557     if (!rtsemEventMultiValid(EventMultiSem))
    558     {
    559         AssertMsgFailed(("Invalid handle %p!\n", EventMultiSem));
    560         return VERR_INVALID_HANDLE;
    561     }
    562 
    563     /*
    564      * Timed or indefinite wait?
    565      */
    566     struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem = EventMultiSem;
    567     if (cMillies == RT_INDEFINITE_WAIT)
    568     {
    569         /* take mutex */
    570         int rc = pthread_mutex_lock(&pIntEventMultiSem->Mutex);
    571         if (rc)
    572         {
    573             AssertMsgFailed(("Failed to lock event multi sem %p, rc=%d.\n", EventMultiSem, rc));
    574             return RTErrConvertFromErrno(rc);
    575         }
    576         ASMAtomicIncU32(&pIntEventMultiSem->cWaiters);
    577 
    578         for (;;)
    579         {
    580             /* check state. */
    581             if (pIntEventMultiSem->u32State == EVENT_STATE_SIGNALED)
    582             {
    583                 ASMAtomicDecU32(&pIntEventMultiSem->cWaiters);
    584                 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);
    585                 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc);
    586                 return VINF_SUCCESS;
    587             }
    588             if (pIntEventMultiSem->u32State == EVENT_STATE_UNINITIALIZED)
    589             {
    590                 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);
    591                 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc);
    592                 return VERR_SEM_DESTROYED;
    593             }
    594 
    595             /* wait */
    596             rc = pthread_cond_wait(&pIntEventMultiSem->Cond, &pIntEventMultiSem->Mutex);
    597             if (rc)
    598             {
    599                 AssertMsgFailed(("Failed to wait on event multi sem %p, rc=%d.\n", EventMultiSem, rc));
    600                 ASMAtomicDecU32(&pIntEventMultiSem->cWaiters);
    601                 int rc2 = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);
    602                 AssertMsg(!rc2, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc2)); NOREF(rc2);
    603                 return RTErrConvertFromErrno(rc);
    604             }
    605         }
    606     }
    607     else
    608     {
    609         /*
    610          * Get current time and calc end of wait time.
    611          */
    612         struct timespec     ts = {0,0};
    613 #ifdef RT_OS_DARWIN
    614         struct timeval      tv = {0,0};
    615         gettimeofday(&tv, NULL);
    616         ts.tv_sec = tv.tv_sec;
    617         ts.tv_nsec = tv.tv_usec * 1000;
    618 #else
    619         clock_gettime(CLOCK_REALTIME, &ts);
    620 #endif
    621         if (cMillies != 0)
    622         {
    623             ts.tv_nsec += (cMillies % 1000) * 1000000;
    624             ts.tv_sec  += cMillies / 1000;
    625             if (ts.tv_nsec >= 1000000000)
    626             {
    627                 ts.tv_nsec -= 1000000000;
    628                 ts.tv_sec++;
    629             }
    630         }
    631 
    632         /* take mutex */
    633 #ifdef RT_OS_DARWIN
    634         int rc = pthread_mutex_lock(&pIntEventMultiSem->Mutex);
    635 #else
    636         int rc = pthread_mutex_timedlock(&pIntEventMultiSem->Mutex, &ts);
    637 #endif
    638         if (rc)
    639         {
    640             AssertMsg(rc == ETIMEDOUT, ("Failed to lock event multi sem %p, rc=%d.\n", EventMultiSem, rc));
    641             return RTErrConvertFromErrno(rc);
    642         }
    643         ASMAtomicIncU32(&pIntEventMultiSem->cWaiters);
    644 
    645         for (;;)
    646         {
    647             /* check state. */
    648             if (pIntEventMultiSem->u32State == EVENT_STATE_SIGNALED)
    649             {
    650                 ASMAtomicXchgU32(&pIntEventMultiSem->u32State, EVENT_STATE_NOT_SIGNALED);
    651                 ASMAtomicDecU32(&pIntEventMultiSem->cWaiters);
    652                 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);
    653                 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc);
    654                 return VINF_SUCCESS;
    655             }
    656             if (pIntEventMultiSem->u32State == EVENT_STATE_UNINITIALIZED)
    657             {
    658                 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);
    659                 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc);
    660                 return VERR_SEM_DESTROYED;
    661             }
    662 
    663             /* wait */
    664             rc = pthread_cond_timedwait(&pIntEventMultiSem->Cond, &pIntEventMultiSem->Mutex, &ts);
    665             if (rc && (rc != EINTR || !fAutoResume)) /* according to SuS this function shall not return EINTR, but linux man page says differently. */
    666             {
    667                 AssertMsg(rc == ETIMEDOUT, ("Failed to wait on event multi sem %p, rc=%d.\n", EventMultiSem, rc));
    668                 ASMAtomicDecU32(&pIntEventMultiSem->cWaiters);
    669                 int rc2 = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);
    670                 AssertMsg(!rc2, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc2)); NOREF(rc2);
    671                 return RTErrConvertFromErrno(rc);
    672             }
    673         }
    674     }
    675 }
    676 
    677 
    678 RTDECL(int)  RTSemEventMultiWait(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies)
    679 {
    680     int rc = rtSemEventMultiWait(EventMultiSem, cMillies, true);
    681     Assert(rc != VERR_INTERRUPTED);
    682     return rc;
    683 }
    684 
    685 
    686 RTDECL(int)  RTSemEventMultiWaitNoResume(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies)
    687 {
    688     return rtSemEventMultiWait(EventMultiSem, cMillies, false);
    689 }
    690 
    691 
    692 
    693 
    694 
    695 /**
    696  * Validate a Mutex semaphore handle passed to one of the interface.
    697  *
    698  * @returns true if valid.
    699  * @returns false if invalid.
    700  * @param   pIntMutexSem    Pointer to the mutex semaphore to validate.
    701  */
    702 inline bool rtsemMutexValid(struct RTSEMMUTEXINTERNAL *pIntMutexSem)
    703 {
    704     if ((uintptr_t)pIntMutexSem < 0x10000)
    705         return false;
    706 
    707     if (pIntMutexSem->cNesting == (uint32_t)~0)
    708         return false;
    709 
    710     return true;
    711 }
    712 
    713 
    714 RTDECL(int)  RTSemMutexCreate(PRTSEMMUTEX pMutexSem)
    715 {
    716     int rc;
    717 
    718     /*
    719      * Allocate semaphore handle.
    720      */
    721     struct RTSEMMUTEXINTERNAL *pIntMutexSem = (struct RTSEMMUTEXINTERNAL *)RTMemAlloc(sizeof(struct RTSEMMUTEXINTERNAL));
    722     if (pIntMutexSem)
    723     {
    724         /*
    725          * Create the semaphore.
    726          */
    727         pthread_mutexattr_t MutexAttr;
    728         rc = pthread_mutexattr_init(&MutexAttr);
    729         if (!rc)
    730         {
    731             rc = pthread_mutex_init(&pIntMutexSem->Mutex, &MutexAttr);
    732             if (!rc)
    733             {
    734                 pthread_mutexattr_destroy(&MutexAttr);
    735 
    736                 pIntMutexSem->Owner    = (pthread_t)-1;
    737                 pIntMutexSem->cNesting = 0;
    738 
    739                 *pMutexSem = pIntMutexSem;
    740                 return VINF_SUCCESS;
    741             }
    742             pthread_mutexattr_destroy(&MutexAttr);
    743         }
    744         RTMemFree(pIntMutexSem);
    745     }
    746     else
    747         rc = VERR_NO_MEMORY;
    748 
    749     return rc;
    750 }
    751 
    752 
    753 RTDECL(int)  RTSemMutexDestroy(RTSEMMUTEX MutexSem)
    754 {
    755     /*
    756      * Validate input.
    757      */
    758     if (!rtsemMutexValid(MutexSem))
    759     {
    760         AssertMsgFailed(("Invalid handle %p!\n", MutexSem));
    761         return VERR_INVALID_HANDLE;
    762     }
    763 
    764     /*
    765      * Try destroy it.
    766      */
    767     struct RTSEMMUTEXINTERNAL *pIntMutexSem = MutexSem;
    768     int rc = pthread_mutex_destroy(&pIntMutexSem->Mutex);
    769     if (rc)
    770     {
    771         AssertMsgFailed(("Failed to destroy mutex sem %p, rc=%d.\n", MutexSem, rc));
    772         return RTErrConvertFromErrno(rc);
    773     }
    774 
    775     /*
    776      * Free the memory and be gone.
    777      */
    778     pIntMutexSem->Owner    = (pthread_t)-1;
    779     pIntMutexSem->cNesting = ~0;
    780     RTMemTmpFree(pIntMutexSem);
    781 
    782     return VINF_SUCCESS;
    783 }
    784 
    785 
    786 RTDECL(int)  RTSemMutexRequest(RTSEMMUTEX MutexSem, unsigned cMillies)
    787 {
    788     /*
    789      * Validate input.
    790      */
    791     if (!rtsemMutexValid(MutexSem))
    792     {
    793         AssertMsgFailed(("Invalid handle %p!\n", MutexSem));
    794         return VERR_INVALID_HANDLE;
    795     }
    796 
    797     /*
    798      * Check if nested request.
    799      */
    800     pthread_t                     Self = pthread_self();
    801     struct RTSEMMUTEXINTERNAL    *pIntMutexSem = MutexSem;
    802     if (    pIntMutexSem->Owner == Self
    803         &&  pIntMutexSem->cNesting > 0)
    804     {
    805         pIntMutexSem->cNesting++;
    806         return VINF_SUCCESS;
    807     }
    808 
    809     /*
    810      * Lock it.
    811      */
    812     if (cMillies == RT_INDEFINITE_WAIT)
    813     {
    814         /* take mutex */
    815         int rc = pthread_mutex_lock(&pIntMutexSem->Mutex);
    816         if (rc)
    817         {
    818             AssertMsgFailed(("Failed to lock mutex sem %p, rc=%d.\n", MutexSem, rc)); NOREF(rc);
    819             return RTErrConvertFromErrno(rc);
    820         }
    821     }
    822     else
    823     {
    824 #ifdef RT_OS_DARWIN
    825         AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));
    826         return VERR_NOT_IMPLEMENTED;
    827 #else /* !RT_OS_DARWIN */
    828         /*
    829          * Get current time and calc end of wait time.
    830          */
    831         struct timespec     ts = {0,0};
    832         clock_gettime(CLOCK_REALTIME, &ts);
    833         if (cMillies != 0)
    834         {
    835             ts.tv_nsec += (cMillies % 1000) * 1000000;
    836             ts.tv_sec  += cMillies / 1000;
    837             if (ts.tv_nsec >= 1000000000)
    838             {
    839                 ts.tv_nsec -= 1000000000;
    840                 ts.tv_sec++;
    841             }
    842         }
    843 
    844         /* take mutex */
    845         int rc = pthread_mutex_timedlock(&pIntMutexSem->Mutex, &ts);
    846         if (rc)
    847         {
    848             AssertMsg(rc == ETIMEDOUT, ("Failed to lock mutex sem %p, rc=%d.\n", MutexSem, rc)); NOREF(rc);
    849             return RTErrConvertFromErrno(rc);
    850         }
    851 #endif /* !RT_OS_DARWIN */
    852     }
    853 
    854     /*
    855      * Set the owner and nesting.
    856      */
    857     pIntMutexSem->Owner = Self;
    858     ASMAtomicXchgU32(&pIntMutexSem->cNesting, 1);
    859 
    860     return VINF_SUCCESS;
    861 }
    862 
    863 
    864 RTDECL(int)  RTSemMutexRequestNoResume(RTSEMMUTEX MutexSem, unsigned cMillies)
    865 {
    866     /* EINTR isn't returned by the wait functions we're using. */
    867     return RTSemMutexRequest(MutexSem, cMillies);
    868 }
    869 
    870 
    871 RTDECL(int)  RTSemMutexRelease(RTSEMMUTEX MutexSem)
    872 {
    873     /*
    874      * Validate input.
    875      */
    876     if (!rtsemMutexValid(MutexSem))
    877     {
    878         AssertMsgFailed(("Invalid handle %p!\n", MutexSem));
    879         return VERR_INVALID_HANDLE;
    880     }
    881 
    882     /*
    883      * Check if nested.
    884      */
    885     pthread_t                     Self = pthread_self();
    886     struct RTSEMMUTEXINTERNAL    *pIntMutexSem = MutexSem;
    887     if (    pIntMutexSem->Owner != Self
    888         ||  pIntMutexSem->cNesting == (uint32_t)~0)
    889     {
    890         AssertMsgFailed(("Not owner of mutex %p!! Self=%08x Owner=%08x cNesting=%d\n",
    891                          pIntMutexSem, Self, pIntMutexSem->Owner, pIntMutexSem->cNesting));
    892         return VERR_NOT_OWNER;
    893     }
    894 
    895     /*
    896      * If nested we'll just pop a nesting.
    897      */
    898     if (pIntMutexSem->cNesting > 1)
    899     {
    900         pIntMutexSem->cNesting--;
    901         return VINF_SUCCESS;
    902     }
    903 
    904     /*
    905      * Clear the state. (cNesting == 1)
    906      */
    907     pIntMutexSem->Owner    = (pthread_t)-1;
    908     ASMAtomicXchgU32(&pIntMutexSem->cNesting, 0);
    909 
    910     /*
    911      * Unlock mutex semaphore.
    912      */
    913     int rc = pthread_mutex_unlock(&pIntMutexSem->Mutex);
    914     if (rc)
    915     {
    916         AssertMsgFailed(("Failed to unlock mutex sem %p, rc=%d.\n", MutexSem, rc)); NOREF(rc);
    917         return RTErrConvertFromErrno(rc);
    918     }
    919 
    920     return VINF_SUCCESS;
    921 }
    922 
    923 
    924 
    925 
    926 
    927 /**
    928  * Validate a read-write semaphore handle passed to one of the interface.
    929  *
    930  * @returns true if valid.
    931  * @returns false if invalid.
    932  * @param   pIntRWSem   Pointer to the read-write semaphore to validate.
    933  */
    934 inline bool rtsemRWValid(struct RTSEMRWINTERNAL *pIntRWSem)
    935 {
    936     if ((uintptr_t)pIntRWSem < 0x10000)
    937         return false;
    938 
    939     if (pIntRWSem->uCheck != (unsigned)~0)
    940         return false;
    941 
    942     return true;
    943 }
    944 
    945 
    946 RTDECL(int)   RTSemRWCreate(PRTSEMRW pRWSem)
    947 {
    948     int rc;
    949 
    950     /*
    951      * Allocate handle.
    952      */
    953     struct RTSEMRWINTERNAL *pIntRWSem = (struct RTSEMRWINTERNAL *)RTMemAlloc(sizeof(struct RTSEMRWINTERNAL));
    954     if (pIntRWSem)
    955     {
    956         /*
    957          * Create the rwlock.
    958          */
    959         pthread_rwlockattr_t    Attr;
    960         rc = pthread_rwlockattr_init(&Attr);
    961         if (!rc)
    962         {
    963             rc = pthread_rwlock_init(&pIntRWSem->RWLock, &Attr);
    964             if (!rc)
    965             {
    966                 pIntRWSem->uCheck = ~0;
    967                 pIntRWSem->WROwner = (pthread_t)-1;
    968                 *pRWSem = pIntRWSem;
    969                 return VINF_SUCCESS;
    970             }
    971         }
    972 
    973         rc = RTErrConvertFromErrno(rc);
    974         RTMemFree(pIntRWSem);
    975     }
    976     else
    977         rc = VERR_NO_MEMORY;
    978 
    979     return rc;
    980 }
    981 
    982 
    983 RTDECL(int)   RTSemRWDestroy(RTSEMRW RWSem)
    984 {
    985     /*
    986      * Validate input.
    987      */
    988     if (!rtsemRWValid(RWSem))
    989     {
    990         AssertMsgFailed(("Invalid handle %p!\n", RWSem));
    991         return VERR_INVALID_HANDLE;
    992     }
    993 
    994     /*
    995      * Try destroy it.
    996      */
    997     struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
    998     int rc = pthread_rwlock_destroy(&pIntRWSem->RWLock);
    999     if (!rc)
    1000     {
    1001         pIntRWSem->uCheck = 0;
    1002         RTMemFree(pIntRWSem);
    1003         rc = VINF_SUCCESS;
    1004     }
    1005     else
    1006     {
    1007         AssertMsgFailed(("Failed to destroy read-write sem %p, rc=%d.\n", RWSem, rc));
    1008         rc = RTErrConvertFromErrno(rc);
    1009     }
    1010 
    1011     return rc;
    1012 }
    1013 
    1014 
    1015 RTDECL(int)   RTSemRWRequestRead(RTSEMRW RWSem, unsigned cMillies)
    1016 {
    1017     /*
    1018      * Validate input.
    1019      */
    1020     if (!rtsemRWValid(RWSem))
    1021     {
    1022         AssertMsgFailed(("Invalid handle %p!\n", RWSem));
    1023         return VERR_INVALID_HANDLE;
    1024     }
    1025 
    1026     /*
    1027      * Try lock it.
    1028      */
    1029     struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
    1030     if (cMillies == RT_INDEFINITE_WAIT)
    1031     {
    1032         /* take rwlock */
    1033         int rc = pthread_rwlock_rdlock(&pIntRWSem->RWLock);
    1034         if (rc)
    1035         {
    1036             AssertMsgFailed(("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
    1037             return RTErrConvertFromErrno(rc);
    1038         }
    1039     }
    1040     else
    1041     {
    1042 #ifdef RT_OS_DARWIN
    1043         AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));
    1044         return VERR_NOT_IMPLEMENTED;
    1045 #else /* !RT_OS_DARWIN */
    1046         /*
    1047          * Get current time and calc end of wait time.
    1048          */
    1049         struct timespec     ts = {0,0};
    1050         clock_gettime(CLOCK_REALTIME, &ts);
    1051         if (cMillies != 0)
    1052         {
    1053             ts.tv_nsec += (cMillies % 1000) * 1000000;
    1054             ts.tv_sec  += cMillies / 1000;
    1055             if (ts.tv_nsec >= 1000000000)
    1056             {
    1057                 ts.tv_nsec -= 1000000000;
    1058                 ts.tv_sec++;
    1059             }
    1060         }
    1061 
    1062         /* take rwlock */
    1063         int rc = pthread_rwlock_timedrdlock(&pIntRWSem->RWLock, &ts);
    1064         if (rc)
    1065         {
    1066             AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
    1067             return RTErrConvertFromErrno(rc);
    1068         }
    1069 #endif /* !RT_OS_DARWIN */
    1070     }
    1071 
    1072     return VINF_SUCCESS;
    1073 }
    1074 
    1075 
    1076 RTDECL(int)   RTSemRWRequestReadNoResume(RTSEMRW RWSem, unsigned cMillies)
    1077 {
    1078     /* EINTR isn't returned by the wait functions we're using. */
    1079     return RTSemRWRequestRead(RWSem, cMillies);
    1080 }
    1081 
    1082 
    1083 RTDECL(int)   RTSemRWReleaseRead(RTSEMRW RWSem)
    1084 {
    1085     /*
    1086      * Validate input.
    1087      */
    1088     if (!rtsemRWValid(RWSem))
    1089     {
    1090         AssertMsgFailed(("Invalid handle %p!\n", RWSem));
    1091         return VERR_INVALID_HANDLE;
    1092     }
    1093 
    1094     /*
    1095      * Try unlock it.
    1096      */
    1097     struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
    1098     if (pIntRWSem->WROwner == pthread_self())
    1099     {
    1100         AssertMsgFailed(("Tried to read unlock when write owner - read-write sem %p.\n", RWSem));
    1101         return VERR_NOT_OWNER;
    1102     }
    1103     int rc = pthread_rwlock_unlock(&pIntRWSem->RWLock);
    1104     if (rc)
    1105     {
    1106         AssertMsgFailed(("Failed read unlock read-write sem %p, rc=%d.\n", RWSem, rc));
    1107         return RTErrConvertFromErrno(rc);
    1108     }
    1109 
    1110     return VINF_SUCCESS;
    1111 }
    1112 
    1113 
    1114 RTDECL(int)   RTSemRWRequestWrite(RTSEMRW RWSem, unsigned cMillies)
    1115 {
    1116     /*
    1117      * Validate input.
    1118      */
    1119     if (!rtsemRWValid(RWSem))
    1120     {
    1121         AssertMsgFailed(("Invalid handle %p!\n", RWSem));
    1122         return VERR_INVALID_HANDLE;
    1123     }
    1124 
    1125     /*
    1126      * Try lock it.
    1127      */
    1128     struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
    1129     if (cMillies == RT_INDEFINITE_WAIT)
    1130     {
    1131         /* take rwlock */
    1132         int rc = pthread_rwlock_wrlock(&pIntRWSem->RWLock);
    1133         if (rc)
    1134         {
    1135             AssertMsgFailed(("Failed write lock read-write sem %p, rc=%d.\n", RWSem, rc));
    1136             return RTErrConvertFromErrno(rc);
    1137         }
    1138     }
    1139     else
    1140     {
    1141 #ifdef RT_OS_DARWIN
    1142         AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));
    1143         return VERR_NOT_IMPLEMENTED;
    1144 #else /* !RT_OS_DARWIN */
    1145         /*
    1146          * Get current time and calc end of wait time.
    1147          */
    1148         struct timespec     ts = {0,0};
    1149         clock_gettime(CLOCK_REALTIME, &ts);
    1150         if (cMillies != 0)
    1151         {
    1152             ts.tv_nsec += (cMillies % 1000) * 1000000;
    1153             ts.tv_sec  += cMillies / 1000;
    1154             if (ts.tv_nsec >= 1000000000)
    1155             {
    1156                 ts.tv_nsec -= 1000000000;
    1157                 ts.tv_sec++;
    1158             }
    1159         }
    1160 
    1161         /* take rwlock */
    1162         int rc = pthread_rwlock_timedwrlock(&pIntRWSem->RWLock, &ts);
    1163         if (rc)
    1164         {
    1165             AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
    1166             return RTErrConvertFromErrno(rc);
    1167         }
    1168 #endif /* !RT_OS_DARWIN */
    1169     }
    1170 
    1171 #ifdef RT_OS_SOLARIS
    1172     ASMAtomicXchgSize(&pIntRWSem->WROwner, pthread_self());
    1173 #else
    1174     ASMAtomicXchgPtr((void * volatile *)&pIntRWSem->WROwner, (void *)pthread_self());
    1175 #endif
    1176 
    1177     return VINF_SUCCESS;
    1178 }
    1179 
    1180 
    1181 RTDECL(int)   RTSemRWRequestWriteNoResume(RTSEMRW RWSem, unsigned cMillies)
    1182 {
    1183     /* EINTR isn't returned by the wait functions we're using. */
    1184     return RTSemRWRequestWrite(RWSem, cMillies);
    1185 }
    1186 
    1187 
    1188 RTDECL(int)   RTSemRWReleaseWrite(RTSEMRW RWSem)
    1189 {
    1190     /*
    1191      * Validate input.
    1192      */
    1193     if (!rtsemRWValid(RWSem))
    1194     {
    1195         AssertMsgFailed(("Invalid handle %p!\n", RWSem));
    1196         return VERR_INVALID_HANDLE;
    1197     }
    1198 
    1199     /*
    1200      * Try unlock it.
    1201      */
    1202     pthread_t                 Self = pthread_self();
    1203     struct RTSEMRWINTERNAL   *pIntRWSem = RWSem;
    1204     if (pIntRWSem->WROwner != Self)
    1205     {
    1206         AssertMsgFailed(("Not Write owner!\n"));
    1207         return VERR_NOT_OWNER;
    1208     }
    1209 
    1210     /*
    1211      * Try unlock it.
    1212      */
    1213 #ifdef RT_OS_SOLARIS
    1214     ASMAtomicXchgSize(&pIntRWSem->WROwner, (pthread_t)-1);
    1215 #else
    1216     AssertMsg(sizeof(pthread_t) == sizeof(void *), ("pthread_t is not the size of a pointer but %d bytes\n", sizeof(pthread_t)));
    1217     ASMAtomicXchgPtr((void * volatile *)&pIntRWSem->WROwner, (void *)(pthread_t)-1);
    1218 #endif
    1219     int rc = pthread_rwlock_unlock(&pIntRWSem->RWLock);
    1220     if (rc)
    1221     {
    1222         AssertMsgFailed(("Failed write unlock read-write sem %p, rc=%d.\n", RWSem, rc));
    1223         return RTErrConvertFromErrno(rc);
    1224     }
    1225 
    1226     return VINF_SUCCESS;
    1227 }
    1228 
  • trunk/src/VBox/Runtime/r3/posix/semeventmulti-posix.cpp

    r6734 r6738  
    11/* $Id$ */
    22/** @file
    3  * innotek Portable Runtime - Semaphores, POSIX.
     3 * innotek Portable Runtime - Multiple Release Event Semaphore, POSIX.
    44 */
    55
     
    3939#include <sys/time.h>
    4040
    41 #ifdef RT_OS_DARWIN
    42 # define pthread_yield() pthread_yield_np()
    43 #endif
    44 
    45 #ifdef RT_OS_SOLARIS
    46 # include <sched.h>
    47 # define pthread_yield() sched_yield()
    48 #endif
    49 
    5041
    5142/*******************************************************************************
    5243*   Structures and Typedefs                                                    *
    5344*******************************************************************************/
    54 
    55 /** Internal representation of the POSIX implementation of an Event semaphore.
     45/** Posix internal representation of a Mutex Multi semaphore.
    5646 * The POSIX implementation uses a mutex and a condition variable to implement
    57  * the automatic reset event semaphore semantics.
    58  *
    59  * This must be identical to RTSEMEVENTMULTIINTERNAL!
    60  */
    61 struct RTSEMEVENTINTERNAL
     47 * the automatic reset event semaphore semantics. */
     48struct RTSEMEVENTMULTIINTERNAL
    6249{
    6350    /** pthread condition. */
     
    7259};
    7360
    74 /** Posix internal representation of a Mutex Multi semaphore.
    75  * This must be identical to RTSEMEVENTINTERNAL! */
    76 struct RTSEMEVENTMULTIINTERNAL
    77 {
    78     /** pthread condition. */
    79     pthread_cond_t      Cond;
    80     /** pthread mutex which protects the condition and the event state. */
    81     pthread_mutex_t     Mutex;
    82     /** The state of the semaphore.
    83      * This is operated while owning mutex and using atomic updating. */
    84     volatile uint32_t   u32State;
    85     /** Number of waiters. */
    86     volatile uint32_t   cWaiters;
    87 };
    88 
    89 /** The valus of the u32State variable in a RTSEMEVENTINTERNAL and RTSEMEVENTMULTIINTERNAL.
     61/** The valus of the u32State variable in RTSEMEVENTMULTIINTERNAL.
    9062 * @{ */
    9163/** The object isn't initialized. */
    92 #define EVENT_STATE_UNINITIALIZED   0
     64#define EVENTMULTI_STATE_UNINITIALIZED   0
    9365/** The semaphore is is signaled. */
    94 #define EVENT_STATE_SIGNALED        0xff00ff00
     66#define EVENTMULTI_STATE_SIGNALED        0xff00ff00
    9567/** The semaphore is not signaled. */
    96 #define EVENT_STATE_NOT_SIGNALED    0x00ff00ff
     68#define EVENTMULTI_STATE_NOT_SIGNALED    0x00ff00ff
    9769/** @} */
    9870
    9971
    100 /** Posix internal representation of a Mutex semaphore. */
    101 struct RTSEMMUTEXINTERNAL
    102 {
    103     /** pthread mutex. */
    104     pthread_mutex_t     Mutex;
    105     /** The owner of the mutex. */
    106     volatile pthread_t  Owner;
    107     /** Nesting count. */
    108     volatile uint32_t   cNesting;
    109 };
    110 
    111 /** Posix internal representation of a read-write semaphore. */
    112 struct RTSEMRWINTERNAL
    113 {
    114     /** pthread rwlock. */
    115     pthread_rwlock_t    RWLock;
    116     /** Variable to check if initialized.
    117      * 0 is uninitialized, ~0 is inititialized. */
    118     volatile unsigned   uCheck;
    119     /** The write owner of the lock. */
    120     volatile pthread_t  WROwner;
    121 };
    122 
    12372
    12473/**
    125  * Validate an Event semaphore handle passed to one of the interface.
     74 * Validate an event multi semaphore handle passed to one of the interface.
    12675 *
    12776 * @returns true if valid.
    12877 * @returns false if invalid.
    129  * @param   pIntEventSem    Pointer to the event semaphore to validate.
     78 * @param   pThis    Pointer to the event semaphore to validate.
    13079 */
    131 inline bool rtsemEventValid(struct RTSEMEVENTINTERNAL *pIntEventSem)
    132 {
    133     if ((uintptr_t)pIntEventSem < 0x10000)
     80inline bool rtsemEventMultiValid(struct RTSEMEVENTMULTIINTERNAL *pThis)
     81{
     82    if ((uintptr_t)pThis < 0x10000)
    13483        return false;
    13584
    136     uint32_t    u32 = pIntEventSem->u32State; /* this is volatile, so a explicit read like this is needed. */
    137     if (    u32 != EVENT_STATE_NOT_SIGNALED
    138         &&  u32 != EVENT_STATE_SIGNALED)
     85    uint32_t    u32 = pThis->u32State; /* this is volatile, so a explicit read like this is needed. */
     86    if (    u32 != EVENTMULTI_STATE_NOT_SIGNALED
     87        &&  u32 != EVENTMULTI_STATE_SIGNALED)
    13988        return false;
    14089
     
    14392
    14493
    145 RTDECL(int)  RTSemEventCreate(PRTSEMEVENT pEventSem)
     94RTDECL(int)  RTSemEventMultiCreate(PRTSEMEVENTMULTI pEventMultiSem)
    14695{
    14796    int rc;
     
    15099     * Allocate semaphore handle.
    151100     */
    152     struct RTSEMEVENTINTERNAL *pIntEventSem = (struct RTSEMEVENTINTERNAL *)RTMemAlloc(sizeof(struct RTSEMEVENTINTERNAL));
    153     if (pIntEventSem)
     101    struct RTSEMEVENTMULTIINTERNAL *pThis = (struct RTSEMEVENTMULTIINTERNAL *)RTMemAlloc(sizeof(struct RTSEMEVENTMULTIINTERNAL));
     102    if (pThis)
    154103    {
    155104        /*
     
    160109        if (!rc)
    161110        {
    162             rc = pthread_cond_init(&pIntEventSem->Cond, &CondAttr);
     111            rc = pthread_cond_init(&pThis->Cond, &CondAttr);
    163112            if (!rc)
    164113            {
     
    170119                if (!rc)
    171120                {
    172                     rc = pthread_mutex_init(&pIntEventSem->Mutex, &MutexAttr);
     121                    rc = pthread_mutex_init(&pThis->Mutex, &MutexAttr);
    173122                    if (!rc)
    174123                    {
     
    176125                        pthread_condattr_destroy(&CondAttr);
    177126
    178                         ASMAtomicXchgU32(&pIntEventSem->u32State, EVENT_STATE_NOT_SIGNALED);
    179                         ASMAtomicXchgU32(&pIntEventSem->cWaiters, 0);
    180 
    181                         *pEventSem = pIntEventSem;
     127                        ASMAtomicXchgU32(&pThis->u32State, EVENTMULTI_STATE_NOT_SIGNALED);
     128                        ASMAtomicXchgU32(&pThis->cWaiters, 0);
     129
     130                        *pEventMultiSem = pThis;
    182131                        return VINF_SUCCESS;
    183132                    }
     133
    184134                    pthread_mutexattr_destroy(&MutexAttr);
    185135                }
    186                 pthread_cond_destroy(&pIntEventSem->Cond);
     136                pthread_cond_destroy(&pThis->Cond);
    187137            }
    188138            pthread_condattr_destroy(&CondAttr);
     
    190140
    191141        rc = RTErrConvertFromErrno(rc);
    192         RTMemFree(pIntEventSem);
     142        RTMemFree(pThis);
    193143    }
    194144    else
     
    196146
    197147    return rc;
    198 }
    199 
    200 
    201 RTDECL(int)  RTSemEventDestroy(RTSEMEVENT EventSem)
     148
     149}
     150
     151
     152RTDECL(int)  RTSemEventMultiDestroy(RTSEMEVENTMULTI EventMultiSem)
    202153{
    203154    /*
    204155     * Validate handle.
    205156     */
    206     if (!rtsemEventValid(EventSem))
    207     {
    208         AssertMsgFailed(("Invalid handle %p!\n", EventSem));
     157    if (!rtsemEventMultiValid(EventMultiSem))
     158    {
     159        AssertMsgFailed(("Invalid handle %p!\n", EventMultiSem));
    209160        return VERR_INVALID_HANDLE;
    210161    }
     
    212163    /*
    213164     * Abort all waiters forcing them to return failure.
    214      *
    215      */
    216     struct RTSEMEVENTINTERNAL *pIntEventSem = EventSem;
     165     */
     166    struct RTSEMEVENTMULTIINTERNAL *pThis = EventMultiSem;
    217167    int rc;
    218168    for (int i = 30; i > 0; i--)
    219169    {
    220         ASMAtomicXchgU32(&pIntEventSem->u32State, EVENT_STATE_UNINITIALIZED);
    221         rc = pthread_cond_destroy(&pIntEventSem->Cond);
     170        ASMAtomicXchgU32(&pThis->u32State, EVENTMULTI_STATE_UNINITIALIZED);
     171        rc = pthread_cond_destroy(&pThis->Cond);
    222172        if (rc != EBUSY)
    223173            break;
    224         pthread_cond_broadcast(&pIntEventSem->Cond);
     174        pthread_cond_broadcast(&pThis->Cond);
    225175        usleep(1000);
    226176    } while (rc == EBUSY);
    227177    if (rc)
    228178    {
    229         AssertMsgFailed(("Failed to destroy event sem %p, rc=%d.\n", EventSem, rc));
     179        AssertMsgFailed(("Failed to destroy event sem %p, rc=%d.\n", EventMultiSem, rc));
    230180        return RTErrConvertFromErrno(rc);
    231181    }
     
    237187    for (int i = 30; i > 0; i--)
    238188    {
    239         rc = pthread_mutex_destroy(&pIntEventSem->Mutex);
     189        rc = pthread_mutex_destroy(&pThis->Mutex);
    240190        if (rc != EBUSY)
    241191            break;
     
    244194    if (rc)
    245195    {
    246         AssertMsgFailed(("Failed to destroy event sem %p, rc=%d. (mutex)\n", EventSem, rc));
     196        AssertMsgFailed(("Failed to destroy event sem %p, rc=%d. (mutex)\n", EventMultiSem, rc));
    247197        return RTErrConvertFromErrno(rc);
    248198    }
     
    251201     * Free the semaphore memory and be gone.
    252202     */
    253     RTMemFree(pIntEventSem);
     203    RTMemFree(pThis);
    254204    return VINF_SUCCESS;
    255205}
    256206
    257207
    258 RTDECL(int)  RTSemEventSignal(RTSEMEVENT EventSem)
     208RTDECL(int)  RTSemEventMultiSignal(RTSEMEVENTMULTI EventMultiSem)
    259209{
    260210    /*
    261211     * Validate input.
    262212     */
    263     if (!rtsemEventValid(EventSem))
    264     {
    265         AssertMsgFailed(("Invalid handle %p!\n", EventSem));
     213    if (!rtsemEventMultiValid(EventMultiSem))
     214    {
     215        AssertMsgFailed(("Invalid handle %p!\n", EventMultiSem));
    266216        return VERR_INVALID_HANDLE;
    267217    }
     
    270220     * Lock the mutex semaphore.
    271221     */
    272     struct RTSEMEVENTINTERNAL *pIntEventSem = EventSem;
    273     int rc = pthread_mutex_lock(&pIntEventSem->Mutex);
    274     if (rc)
    275     {
    276         AssertMsgFailed(("Failed to lock event sem %p, rc=%d.\n", EventSem, rc));
     222    struct RTSEMEVENTMULTIINTERNAL *pThis = EventMultiSem;
     223    int rc = pthread_mutex_lock(&pThis->Mutex);
     224    if (rc)
     225    {
     226        AssertMsgFailed(("Failed to lock event sem %p, rc=%d.\n", EventMultiSem, rc));
    277227        return RTErrConvertFromErrno(rc);
    278228    }
     
    281231     * Check the state.
    282232     */
    283     if (pIntEventSem->u32State == EVENT_STATE_NOT_SIGNALED)
    284     {
    285         ASMAtomicXchgU32(&pIntEventSem->u32State, EVENT_STATE_SIGNALED);
    286         rc = pthread_cond_signal(&pIntEventSem->Cond);
    287         AssertMsg(!rc, ("Failed to signal event sem %p, rc=%d.\n", EventSem, rc));
    288     }
    289     else if (pIntEventSem->u32State == EVENT_STATE_SIGNALED)
    290     {
    291         rc = pthread_cond_signal(&pIntEventSem->Cond); /* give'm another kick... */
    292         AssertMsg(!rc, ("Failed to signal event sem %p, rc=%d. (2)\n", EventSem, rc));
     233    if (pThis->u32State == EVENTMULTI_STATE_NOT_SIGNALED)
     234    {
     235        ASMAtomicXchgU32(&pThis->u32State, EVENTMULTI_STATE_SIGNALED);
     236        rc = pthread_cond_signal(&pThis->Cond);
     237        AssertMsg(!rc, ("Failed to signal event sem %p, rc=%d.\n", EventMultiSem, rc));
     238    }
     239    else if (pThis->u32State == EVENTMULTI_STATE_SIGNALED)
     240    {
     241        rc = pthread_cond_signal(&pThis->Cond); /* give'm another kick... */
     242        AssertMsg(!rc, ("Failed to signal event sem %p, rc=%d. (2)\n", EventMultiSem, rc));
    293243    }
    294244    else
     
    298248     * Release the mutex and return.
    299249     */
    300     int rc2 = pthread_mutex_unlock(&pIntEventSem->Mutex);
    301     AssertMsg(!rc2, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc));
     250    int rc2 = pthread_mutex_unlock(&pThis->Mutex);
     251    AssertMsg(!rc2, ("Failed to unlock event sem %p, rc=%d.\n", EventMultiSem, rc));
    302252    if (rc)
    303253        return RTErrConvertFromErrno(rc);
     
    309259
    310260
    311 static int  rtSemEventWait(RTSEMEVENT EventSem, unsigned cMillies, bool fAutoResume)
     261RTDECL(int)  RTSemEventMultiReset(RTSEMEVENTMULTI EventMultiSem)
    312262{
    313263    /*
    314264     * Validate input.
    315265     */
    316     if (!rtsemEventValid(EventSem))
    317     {
    318         AssertMsgFailed(("Invalid handle %p!\n", EventSem));
     266    if (!rtsemEventMultiValid(EventMultiSem))
     267    {
     268        AssertMsgFailed(("Invalid handle %p!\n", EventMultiSem));
    319269        return VERR_INVALID_HANDLE;
    320270    }
    321271
    322272    /*
     273     * Lock the mutex semaphore.
     274     */
     275    struct RTSEMEVENTMULTIINTERNAL *pThis = EventMultiSem;
     276    int rc = pthread_mutex_lock(&pThis->Mutex);
     277    if (rc)
     278    {
     279        AssertMsgFailed(("Failed to lock event multi sem %p, rc=%d.\n", EventMultiSem, rc));
     280        return RTErrConvertFromErrno(rc);
     281    }
     282
     283    /*
     284     * Check the state.
     285     */
     286    if (pThis->u32State == EVENTMULTI_STATE_SIGNALED)
     287        ASMAtomicXchgU32(&pThis->u32State, EVENTMULTI_STATE_NOT_SIGNALED);
     288    else if (pThis->u32State != EVENTMULTI_STATE_NOT_SIGNALED)
     289        rc = VERR_SEM_DESTROYED;
     290
     291    /*
     292     * Release the mutex and return.
     293     */
     294    rc = pthread_mutex_unlock(&pThis->Mutex);
     295    if (rc)
     296    {
     297        AssertMsgFailed(("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc));
     298        return RTErrConvertFromErrno(rc);
     299    }
     300
     301    return VINF_SUCCESS;
     302
     303}
     304
     305
     306static int rtSemEventMultiWait(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies, bool fAutoResume)
     307{
     308    /*
     309     * Validate input.
     310     */
     311    if (!rtsemEventMultiValid(EventMultiSem))
     312    {
     313        AssertMsgFailed(("Invalid handle %p!\n", EventMultiSem));
     314        return VERR_INVALID_HANDLE;
     315    }
     316
     317    /*
    323318     * Timed or indefinite wait?
    324319     */
    325     struct RTSEMEVENTINTERNAL *pIntEventSem = EventSem;
     320    struct RTSEMEVENTMULTIINTERNAL *pThis = EventMultiSem;
    326321    if (cMillies == RT_INDEFINITE_WAIT)
    327322    {
    328         /* for fairness, yield before going to sleep. */
    329         if (    ASMAtomicIncU32(&pIntEventSem->cWaiters) > 1
    330             &&  pIntEventSem->u32State == EVENT_STATE_SIGNALED)
    331             pthread_yield();
    332 
    333          /* take mutex */
    334         int rc = pthread_mutex_lock(&pIntEventSem->Mutex);
     323        /* take mutex */
     324        int rc = pthread_mutex_lock(&pThis->Mutex);
    335325        if (rc)
    336326        {
    337             ASMAtomicDecU32(&pIntEventSem->cWaiters);
    338             AssertMsgFailed(("Failed to lock event sem %p, rc=%d.\n", EventSem, rc));
     327            AssertMsgFailed(("Failed to lock event multi sem %p, rc=%d.\n", EventMultiSem, rc));
    339328            return RTErrConvertFromErrno(rc);
    340329        }
     330        ASMAtomicIncU32(&pThis->cWaiters);
    341331
    342332        for (;;)
    343333        {
    344334            /* check state. */
    345             if (pIntEventSem->u32State == EVENT_STATE_SIGNALED)
    346             {
    347                 ASMAtomicXchgU32(&pIntEventSem->u32State, EVENT_STATE_NOT_SIGNALED);
    348                 ASMAtomicDecU32(&pIntEventSem->cWaiters);
    349                 rc = pthread_mutex_unlock(&pIntEventSem->Mutex);
    350                 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc)); NOREF(rc);
     335            if (pThis->u32State == EVENTMULTI_STATE_SIGNALED)
     336            {
     337                ASMAtomicDecU32(&pThis->cWaiters);
     338                rc = pthread_mutex_unlock(&pThis->Mutex);
     339                AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc);
    351340                return VINF_SUCCESS;
    352341            }
    353             if (pIntEventSem->u32State == EVENT_STATE_UNINITIALIZED)
    354             {
    355                 rc = pthread_mutex_unlock(&pIntEventSem->Mutex);
    356                 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc)); NOREF(rc);
     342            if (pThis->u32State == EVENTMULTI_STATE_UNINITIALIZED)
     343            {
     344                rc = pthread_mutex_unlock(&pThis->Mutex);
     345                AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc);
    357346                return VERR_SEM_DESTROYED;
    358347            }
    359348
    360349            /* wait */
    361             rc = pthread_cond_wait(&pIntEventSem->Cond, &pIntEventSem->Mutex);
     350            rc = pthread_cond_wait(&pThis->Cond, &pThis->Mutex);
    362351            if (rc)
    363352            {
    364                 AssertMsgFailed(("Failed to wait on event sem %p, rc=%d.\n", EventSem, rc));
    365                 ASMAtomicDecU32(&pIntEventSem->cWaiters);
    366                 int rc2 = pthread_mutex_unlock(&pIntEventSem->Mutex);
    367                 AssertMsg(!rc2, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc2)); NOREF(rc2);
     353                AssertMsgFailed(("Failed to wait on event multi sem %p, rc=%d.\n", EventMultiSem, rc));
     354                ASMAtomicDecU32(&pThis->cWaiters);
     355                int rc2 = pthread_mutex_unlock(&pThis->Mutex);
     356                AssertMsg(!rc2, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc2)); NOREF(rc2);
    368357                return RTErrConvertFromErrno(rc);
    369358            }
     
    395384        }
    396385
    397         /* for fairness, yield before going to sleep. */
    398         if (ASMAtomicIncU32(&pIntEventSem->cWaiters) > 1)
    399             pthread_yield();
    400 
    401386        /* take mutex */
    402387#ifdef RT_OS_DARWIN
    403         int rc = pthread_mutex_lock(&pIntEventSem->Mutex);
     388        int rc = pthread_mutex_lock(&pThis->Mutex);
    404389#else
    405         int rc = pthread_mutex_timedlock(&pIntEventSem->Mutex, &ts);
     390        int rc = pthread_mutex_timedlock(&pThis->Mutex, &ts);
    406391#endif
    407392        if (rc)
    408393        {
    409             ASMAtomicDecU32(&pIntEventSem->cWaiters);
    410             AssertMsg(rc == ETIMEDOUT, ("Failed to lock event sem %p, rc=%d.\n", EventSem, rc));
     394            AssertMsg(rc == ETIMEDOUT, ("Failed to lock event multi sem %p, rc=%d.\n", EventMultiSem, rc));
    411395            return RTErrConvertFromErrno(rc);
    412396        }
     397        ASMAtomicIncU32(&pThis->cWaiters);
    413398
    414399        for (;;)
    415400        {
    416401            /* check state. */
    417             if (pIntEventSem->u32State == EVENT_STATE_SIGNALED)
    418             {
    419                 ASMAtomicXchgU32(&pIntEventSem->u32State, EVENT_STATE_NOT_SIGNALED);
    420                 ASMAtomicDecU32(&pIntEventSem->cWaiters);
    421                 rc = pthread_mutex_unlock(&pIntEventSem->Mutex);
    422                 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc)); NOREF(rc);
    423                 return VINF_SUCCESS;
    424             }
    425             if (pIntEventSem->u32State == EVENT_STATE_UNINITIALIZED)
    426             {
    427                 rc = pthread_mutex_unlock(&pIntEventSem->Mutex);
    428                 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc)); NOREF(rc);
    429                 return VERR_SEM_DESTROYED;
    430             }
    431 
    432             /* wait */
    433             rc = pthread_cond_timedwait(&pIntEventSem->Cond, &pIntEventSem->Mutex, &ts);
    434             if (rc && (rc != EINTR || !fAutoResume)) /* according to SuS this function shall not return EINTR, but linux man page says differently. */
    435             {
    436                 AssertMsg(rc == ETIMEDOUT, ("Failed to wait on event sem %p, rc=%d.\n", EventSem, rc));
    437                 ASMAtomicDecU32(&pIntEventSem->cWaiters);
    438                 int rc2 = pthread_mutex_unlock(&pIntEventSem->Mutex);
    439                 AssertMsg(!rc2, ("Failed to unlock event sem %p, rc2=%d.\n", EventSem, rc2)); NOREF(rc2);
    440                 return RTErrConvertFromErrno(rc);
    441             }
    442         } /* for (;;) */
    443     }
    444 }
    445 
    446 
    447 RTDECL(int)  RTSemEventWait(RTSEMEVENT EventSem, unsigned cMillies)
    448 {
    449     int rc = rtSemEventWait(EventSem, cMillies, true);
    450     Assert(rc != VERR_INTERRUPTED);
    451     return rc;
    452 }
    453 
    454 
    455 RTDECL(int)  RTSemEventWaitNoResume(RTSEMEVENT EventSem, unsigned cMillies)
    456 {
    457     return rtSemEventWait(EventSem, cMillies, false);
    458 }
    459 
    460 
    461 
    462 
    463 
    464 
    465 /**
    466  * Validate an event multi semaphore handle passed to one of the interface.
    467  *
    468  * @returns true if valid.
    469  * @returns false if invalid.
    470  * @param   pIntEventMultiSem    Pointer to the event semaphore to validate.
    471  */
    472 inline bool rtsemEventMultiValid(struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem)
    473 {
    474     if ((uintptr_t)pIntEventMultiSem < 0x10000)
    475         return false;
    476 
    477     uint32_t    u32 = pIntEventMultiSem->u32State; /* this is volatile, so a explicit read like this is needed. */
    478     if (    u32 != EVENT_STATE_NOT_SIGNALED
    479         &&  u32 != EVENT_STATE_SIGNALED)
    480         return false;
    481 
    482     return true;
    483 }
    484 
    485 
    486 RTDECL(int)  RTSemEventMultiCreate(PRTSEMEVENTMULTI pEventMultiSem)
    487 {
    488     /* the code and the structure is identical with other type for this function. */
    489     return RTSemEventCreate((PRTSEMEVENT)pEventMultiSem);
    490 }
    491 
    492 
    493 RTDECL(int)  RTSemEventMultiDestroy(RTSEMEVENTMULTI EventMultiSem)
    494 {
    495     /* the code and the structure is identical with other type for this function. */
    496     return RTSemEventDestroy((RTSEMEVENT)EventMultiSem);
    497 }
    498 
    499 
    500 RTDECL(int)  RTSemEventMultiSignal(RTSEMEVENTMULTI EventMultiSem)
    501 {
    502     /* the code and the structure is identical with other type for this function. */
    503     return RTSemEventSignal((RTSEMEVENT)EventMultiSem);
    504 }
    505 
    506 
    507 RTDECL(int)  RTSemEventMultiReset(RTSEMEVENTMULTI EventMultiSem)
    508 {
    509     /*
    510      * Validate input.
    511      */
    512     if (!rtsemEventMultiValid(EventMultiSem))
    513     {
    514         AssertMsgFailed(("Invalid handle %p!\n", EventMultiSem));
    515         return VERR_INVALID_HANDLE;
    516     }
    517 
    518     /*
    519      * Lock the mutex semaphore.
    520      */
    521     struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem = EventMultiSem;
    522     int rc = pthread_mutex_lock(&pIntEventMultiSem->Mutex);
    523     if (rc)
    524     {
    525         AssertMsgFailed(("Failed to lock event multi sem %p, rc=%d.\n", EventMultiSem, rc));
    526         return RTErrConvertFromErrno(rc);
    527     }
    528 
    529     /*
    530      * Check the state.
    531      */
    532     if (pIntEventMultiSem->u32State == EVENT_STATE_SIGNALED)
    533         ASMAtomicXchgU32(&pIntEventMultiSem->u32State, EVENT_STATE_NOT_SIGNALED);
    534     else if (pIntEventMultiSem->u32State != EVENT_STATE_NOT_SIGNALED)
    535         rc = VERR_SEM_DESTROYED;
    536 
    537     /*
    538      * Release the mutex and return.
    539      */
    540     rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);
    541     if (rc)
    542     {
    543         AssertMsgFailed(("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc));
    544         return RTErrConvertFromErrno(rc);
    545     }
    546 
    547     return VINF_SUCCESS;
    548 
    549 }
    550 
    551 
    552 static int rtSemEventMultiWait(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies, bool fAutoResume)
    553 {
    554     /*
    555      * Validate input.
    556      */
    557     if (!rtsemEventMultiValid(EventMultiSem))
    558     {
    559         AssertMsgFailed(("Invalid handle %p!\n", EventMultiSem));
    560         return VERR_INVALID_HANDLE;
    561     }
    562 
    563     /*
    564      * Timed or indefinite wait?
    565      */
    566     struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem = EventMultiSem;
    567     if (cMillies == RT_INDEFINITE_WAIT)
    568     {
    569         /* take mutex */
    570         int rc = pthread_mutex_lock(&pIntEventMultiSem->Mutex);
    571         if (rc)
    572         {
    573             AssertMsgFailed(("Failed to lock event multi sem %p, rc=%d.\n", EventMultiSem, rc));
    574             return RTErrConvertFromErrno(rc);
    575         }
    576         ASMAtomicIncU32(&pIntEventMultiSem->cWaiters);
    577 
    578         for (;;)
    579         {
    580             /* check state. */
    581             if (pIntEventMultiSem->u32State == EVENT_STATE_SIGNALED)
    582             {
    583                 ASMAtomicDecU32(&pIntEventMultiSem->cWaiters);
    584                 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);
     402            if (pThis->u32State == EVENTMULTI_STATE_SIGNALED)
     403            {
     404                ASMAtomicXchgU32(&pThis->u32State, EVENTMULTI_STATE_NOT_SIGNALED);
     405                ASMAtomicDecU32(&pThis->cWaiters);
     406                rc = pthread_mutex_unlock(&pThis->Mutex);
    585407                AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc);
    586408                return VINF_SUCCESS;
    587409            }
    588             if (pIntEventMultiSem->u32State == EVENT_STATE_UNINITIALIZED)
    589             {
    590                 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);
     410            if (pThis->u32State == EVENTMULTI_STATE_UNINITIALIZED)
     411            {
     412                rc = pthread_mutex_unlock(&pThis->Mutex);
    591413                AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc);
    592414                return VERR_SEM_DESTROYED;
     
    594416
    595417            /* wait */
    596             rc = pthread_cond_wait(&pIntEventMultiSem->Cond, &pIntEventMultiSem->Mutex);
    597             if (rc)
    598             {
    599                 AssertMsgFailed(("Failed to wait on event multi sem %p, rc=%d.\n", EventMultiSem, rc));
    600                 ASMAtomicDecU32(&pIntEventMultiSem->cWaiters);
    601                 int rc2 = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);
    602                 AssertMsg(!rc2, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc2)); NOREF(rc2);
    603                 return RTErrConvertFromErrno(rc);
    604             }
    605         }
    606     }
    607     else
    608     {
    609         /*
    610          * Get current time and calc end of wait time.
    611          */
    612         struct timespec     ts = {0,0};
    613 #ifdef RT_OS_DARWIN
    614         struct timeval      tv = {0,0};
    615         gettimeofday(&tv, NULL);
    616         ts.tv_sec = tv.tv_sec;
    617         ts.tv_nsec = tv.tv_usec * 1000;
    618 #else
    619         clock_gettime(CLOCK_REALTIME, &ts);
    620 #endif
    621         if (cMillies != 0)
    622         {
    623             ts.tv_nsec += (cMillies % 1000) * 1000000;
    624             ts.tv_sec  += cMillies / 1000;
    625             if (ts.tv_nsec >= 1000000000)
    626             {
    627                 ts.tv_nsec -= 1000000000;
    628                 ts.tv_sec++;
    629             }
    630         }
    631 
    632         /* take mutex */
    633 #ifdef RT_OS_DARWIN
    634         int rc = pthread_mutex_lock(&pIntEventMultiSem->Mutex);
    635 #else
    636         int rc = pthread_mutex_timedlock(&pIntEventMultiSem->Mutex, &ts);
    637 #endif
    638         if (rc)
    639         {
    640             AssertMsg(rc == ETIMEDOUT, ("Failed to lock event multi sem %p, rc=%d.\n", EventMultiSem, rc));
    641             return RTErrConvertFromErrno(rc);
    642         }
    643         ASMAtomicIncU32(&pIntEventMultiSem->cWaiters);
    644 
    645         for (;;)
    646         {
    647             /* check state. */
    648             if (pIntEventMultiSem->u32State == EVENT_STATE_SIGNALED)
    649             {
    650                 ASMAtomicXchgU32(&pIntEventMultiSem->u32State, EVENT_STATE_NOT_SIGNALED);
    651                 ASMAtomicDecU32(&pIntEventMultiSem->cWaiters);
    652                 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);
    653                 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc);
    654                 return VINF_SUCCESS;
    655             }
    656             if (pIntEventMultiSem->u32State == EVENT_STATE_UNINITIALIZED)
    657             {
    658                 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);
    659                 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc);
    660                 return VERR_SEM_DESTROYED;
    661             }
    662 
    663             /* wait */
    664             rc = pthread_cond_timedwait(&pIntEventMultiSem->Cond, &pIntEventMultiSem->Mutex, &ts);
     418            rc = pthread_cond_timedwait(&pThis->Cond, &pThis->Mutex, &ts);
    665419            if (rc && (rc != EINTR || !fAutoResume)) /* according to SuS this function shall not return EINTR, but linux man page says differently. */
    666420            {
    667421                AssertMsg(rc == ETIMEDOUT, ("Failed to wait on event multi sem %p, rc=%d.\n", EventMultiSem, rc));
    668                 ASMAtomicDecU32(&pIntEventMultiSem->cWaiters);
    669                 int rc2 = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);
     422                ASMAtomicDecU32(&pThis->cWaiters);
     423                int rc2 = pthread_mutex_unlock(&pThis->Mutex);
    670424                AssertMsg(!rc2, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc2)); NOREF(rc2);
    671425                return RTErrConvertFromErrno(rc);
     
    689443}
    690444
    691 
    692 
    693 
    694 
    695 /**
    696  * Validate a Mutex semaphore handle passed to one of the interface.
    697  *
    698  * @returns true if valid.
    699  * @returns false if invalid.
    700  * @param   pIntMutexSem    Pointer to the mutex semaphore to validate.
    701  */
    702 inline bool rtsemMutexValid(struct RTSEMMUTEXINTERNAL *pIntMutexSem)
    703 {
    704     if ((uintptr_t)pIntMutexSem < 0x10000)
    705         return false;
    706 
    707     if (pIntMutexSem->cNesting == (uint32_t)~0)
    708         return false;
    709 
    710     return true;
    711 }
    712 
    713 
    714 RTDECL(int)  RTSemMutexCreate(PRTSEMMUTEX pMutexSem)
    715 {
    716     int rc;
    717 
    718     /*
    719      * Allocate semaphore handle.
    720      */
    721     struct RTSEMMUTEXINTERNAL *pIntMutexSem = (struct RTSEMMUTEXINTERNAL *)RTMemAlloc(sizeof(struct RTSEMMUTEXINTERNAL));
    722     if (pIntMutexSem)
    723     {
    724         /*
    725          * Create the semaphore.
    726          */
    727         pthread_mutexattr_t MutexAttr;
    728         rc = pthread_mutexattr_init(&MutexAttr);
    729         if (!rc)
    730         {
    731             rc = pthread_mutex_init(&pIntMutexSem->Mutex, &MutexAttr);
    732             if (!rc)
    733             {
    734                 pthread_mutexattr_destroy(&MutexAttr);
    735 
    736                 pIntMutexSem->Owner    = (pthread_t)-1;
    737                 pIntMutexSem->cNesting = 0;
    738 
    739                 *pMutexSem = pIntMutexSem;
    740                 return VINF_SUCCESS;
    741             }
    742             pthread_mutexattr_destroy(&MutexAttr);
    743         }
    744         RTMemFree(pIntMutexSem);
    745     }
    746     else
    747         rc = VERR_NO_MEMORY;
    748 
    749     return rc;
    750 }
    751 
    752 
    753 RTDECL(int)  RTSemMutexDestroy(RTSEMMUTEX MutexSem)
    754 {
    755     /*
    756      * Validate input.
    757      */
    758     if (!rtsemMutexValid(MutexSem))
    759     {
    760         AssertMsgFailed(("Invalid handle %p!\n", MutexSem));
    761         return VERR_INVALID_HANDLE;
    762     }
    763 
    764     /*
    765      * Try destroy it.
    766      */
    767     struct RTSEMMUTEXINTERNAL *pIntMutexSem = MutexSem;
    768     int rc = pthread_mutex_destroy(&pIntMutexSem->Mutex);
    769     if (rc)
    770     {
    771         AssertMsgFailed(("Failed to destroy mutex sem %p, rc=%d.\n", MutexSem, rc));
    772         return RTErrConvertFromErrno(rc);
    773     }
    774 
    775     /*
    776      * Free the memory and be gone.
    777      */
    778     pIntMutexSem->Owner    = (pthread_t)-1;
    779     pIntMutexSem->cNesting = ~0;
    780     RTMemTmpFree(pIntMutexSem);
    781 
    782     return VINF_SUCCESS;
    783 }
    784 
    785 
    786 RTDECL(int)  RTSemMutexRequest(RTSEMMUTEX MutexSem, unsigned cMillies)
    787 {
    788     /*
    789      * Validate input.
    790      */
    791     if (!rtsemMutexValid(MutexSem))
    792     {
    793         AssertMsgFailed(("Invalid handle %p!\n", MutexSem));
    794         return VERR_INVALID_HANDLE;
    795     }
    796 
    797     /*
    798      * Check if nested request.
    799      */
    800     pthread_t                     Self = pthread_self();
    801     struct RTSEMMUTEXINTERNAL    *pIntMutexSem = MutexSem;
    802     if (    pIntMutexSem->Owner == Self
    803         &&  pIntMutexSem->cNesting > 0)
    804     {
    805         pIntMutexSem->cNesting++;
    806         return VINF_SUCCESS;
    807     }
    808 
    809     /*
    810      * Lock it.
    811      */
    812     if (cMillies == RT_INDEFINITE_WAIT)
    813     {
    814         /* take mutex */
    815         int rc = pthread_mutex_lock(&pIntMutexSem->Mutex);
    816         if (rc)
    817         {
    818             AssertMsgFailed(("Failed to lock mutex sem %p, rc=%d.\n", MutexSem, rc)); NOREF(rc);
    819             return RTErrConvertFromErrno(rc);
    820         }
    821     }
    822     else
    823     {
    824 #ifdef RT_OS_DARWIN
    825         AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));
    826         return VERR_NOT_IMPLEMENTED;
    827 #else /* !RT_OS_DARWIN */
    828         /*
    829          * Get current time and calc end of wait time.
    830          */
    831         struct timespec     ts = {0,0};
    832         clock_gettime(CLOCK_REALTIME, &ts);
    833         if (cMillies != 0)
    834         {
    835             ts.tv_nsec += (cMillies % 1000) * 1000000;
    836             ts.tv_sec  += cMillies / 1000;
    837             if (ts.tv_nsec >= 1000000000)
    838             {
    839                 ts.tv_nsec -= 1000000000;
    840                 ts.tv_sec++;
    841             }
    842         }
    843 
    844         /* take mutex */
    845         int rc = pthread_mutex_timedlock(&pIntMutexSem->Mutex, &ts);
    846         if (rc)
    847         {
    848             AssertMsg(rc == ETIMEDOUT, ("Failed to lock mutex sem %p, rc=%d.\n", MutexSem, rc)); NOREF(rc);
    849             return RTErrConvertFromErrno(rc);
    850         }
    851 #endif /* !RT_OS_DARWIN */
    852     }
    853 
    854     /*
    855      * Set the owner and nesting.
    856      */
    857     pIntMutexSem->Owner = Self;
    858     ASMAtomicXchgU32(&pIntMutexSem->cNesting, 1);
    859 
    860     return VINF_SUCCESS;
    861 }
    862 
    863 
    864 RTDECL(int)  RTSemMutexRequestNoResume(RTSEMMUTEX MutexSem, unsigned cMillies)
    865 {
    866     /* EINTR isn't returned by the wait functions we're using. */
    867     return RTSemMutexRequest(MutexSem, cMillies);
    868 }
    869 
    870 
    871 RTDECL(int)  RTSemMutexRelease(RTSEMMUTEX MutexSem)
    872 {
    873     /*
    874      * Validate input.
    875      */
    876     if (!rtsemMutexValid(MutexSem))
    877     {
    878         AssertMsgFailed(("Invalid handle %p!\n", MutexSem));
    879         return VERR_INVALID_HANDLE;
    880     }
    881 
    882     /*
    883      * Check if nested.
    884      */
    885     pthread_t                     Self = pthread_self();
    886     struct RTSEMMUTEXINTERNAL    *pIntMutexSem = MutexSem;
    887     if (    pIntMutexSem->Owner != Self
    888         ||  pIntMutexSem->cNesting == (uint32_t)~0)
    889     {
    890         AssertMsgFailed(("Not owner of mutex %p!! Self=%08x Owner=%08x cNesting=%d\n",
    891                          pIntMutexSem, Self, pIntMutexSem->Owner, pIntMutexSem->cNesting));
    892         return VERR_NOT_OWNER;
    893     }
    894 
    895     /*
    896      * If nested we'll just pop a nesting.
    897      */
    898     if (pIntMutexSem->cNesting > 1)
    899     {
    900         pIntMutexSem->cNesting--;
    901         return VINF_SUCCESS;
    902     }
    903 
    904     /*
    905      * Clear the state. (cNesting == 1)
    906      */
    907     pIntMutexSem->Owner    = (pthread_t)-1;
    908     ASMAtomicXchgU32(&pIntMutexSem->cNesting, 0);
    909 
    910     /*
    911      * Unlock mutex semaphore.
    912      */
    913     int rc = pthread_mutex_unlock(&pIntMutexSem->Mutex);
    914     if (rc)
    915     {
    916         AssertMsgFailed(("Failed to unlock mutex sem %p, rc=%d.\n", MutexSem, rc)); NOREF(rc);
    917         return RTErrConvertFromErrno(rc);
    918     }
    919 
    920     return VINF_SUCCESS;
    921 }
    922 
    923 
    924 
    925 
    926 
    927 /**
    928  * Validate a read-write semaphore handle passed to one of the interface.
    929  *
    930  * @returns true if valid.
    931  * @returns false if invalid.
    932  * @param   pIntRWSem   Pointer to the read-write semaphore to validate.
    933  */
    934 inline bool rtsemRWValid(struct RTSEMRWINTERNAL *pIntRWSem)
    935 {
    936     if ((uintptr_t)pIntRWSem < 0x10000)
    937         return false;
    938 
    939     if (pIntRWSem->uCheck != (unsigned)~0)
    940         return false;
    941 
    942     return true;
    943 }
    944 
    945 
    946 RTDECL(int)   RTSemRWCreate(PRTSEMRW pRWSem)
    947 {
    948     int rc;
    949 
    950     /*
    951      * Allocate handle.
    952      */
    953     struct RTSEMRWINTERNAL *pIntRWSem = (struct RTSEMRWINTERNAL *)RTMemAlloc(sizeof(struct RTSEMRWINTERNAL));
    954     if (pIntRWSem)
    955     {
    956         /*
    957          * Create the rwlock.
    958          */
    959         pthread_rwlockattr_t    Attr;
    960         rc = pthread_rwlockattr_init(&Attr);
    961         if (!rc)
    962         {
    963             rc = pthread_rwlock_init(&pIntRWSem->RWLock, &Attr);
    964             if (!rc)
    965             {
    966                 pIntRWSem->uCheck = ~0;
    967                 pIntRWSem->WROwner = (pthread_t)-1;
    968                 *pRWSem = pIntRWSem;
    969                 return VINF_SUCCESS;
    970             }
    971         }
    972 
    973         rc = RTErrConvertFromErrno(rc);
    974         RTMemFree(pIntRWSem);
    975     }
    976     else
    977         rc = VERR_NO_MEMORY;
    978 
    979     return rc;
    980 }
    981 
    982 
    983 RTDECL(int)   RTSemRWDestroy(RTSEMRW RWSem)
    984 {
    985     /*
    986      * Validate input.
    987      */
    988     if (!rtsemRWValid(RWSem))
    989     {
    990         AssertMsgFailed(("Invalid handle %p!\n", RWSem));
    991         return VERR_INVALID_HANDLE;
    992     }
    993 
    994     /*
    995      * Try destroy it.
    996      */
    997     struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
    998     int rc = pthread_rwlock_destroy(&pIntRWSem->RWLock);
    999     if (!rc)
    1000     {
    1001         pIntRWSem->uCheck = 0;
    1002         RTMemFree(pIntRWSem);
    1003         rc = VINF_SUCCESS;
    1004     }
    1005     else
    1006     {
    1007         AssertMsgFailed(("Failed to destroy read-write sem %p, rc=%d.\n", RWSem, rc));
    1008         rc = RTErrConvertFromErrno(rc);
    1009     }
    1010 
    1011     return rc;
    1012 }
    1013 
    1014 
    1015 RTDECL(int)   RTSemRWRequestRead(RTSEMRW RWSem, unsigned cMillies)
    1016 {
    1017     /*
    1018      * Validate input.
    1019      */
    1020     if (!rtsemRWValid(RWSem))
    1021     {
    1022         AssertMsgFailed(("Invalid handle %p!\n", RWSem));
    1023         return VERR_INVALID_HANDLE;
    1024     }
    1025 
    1026     /*
    1027      * Try lock it.
    1028      */
    1029     struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
    1030     if (cMillies == RT_INDEFINITE_WAIT)
    1031     {
    1032         /* take rwlock */
    1033         int rc = pthread_rwlock_rdlock(&pIntRWSem->RWLock);
    1034         if (rc)
    1035         {
    1036             AssertMsgFailed(("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
    1037             return RTErrConvertFromErrno(rc);
    1038         }
    1039     }
    1040     else
    1041     {
    1042 #ifdef RT_OS_DARWIN
    1043         AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));
    1044         return VERR_NOT_IMPLEMENTED;
    1045 #else /* !RT_OS_DARWIN */
    1046         /*
    1047          * Get current time and calc end of wait time.
    1048          */
    1049         struct timespec     ts = {0,0};
    1050         clock_gettime(CLOCK_REALTIME, &ts);
    1051         if (cMillies != 0)
    1052         {
    1053             ts.tv_nsec += (cMillies % 1000) * 1000000;
    1054             ts.tv_sec  += cMillies / 1000;
    1055             if (ts.tv_nsec >= 1000000000)
    1056             {
    1057                 ts.tv_nsec -= 1000000000;
    1058                 ts.tv_sec++;
    1059             }
    1060         }
    1061 
    1062         /* take rwlock */
    1063         int rc = pthread_rwlock_timedrdlock(&pIntRWSem->RWLock, &ts);
    1064         if (rc)
    1065         {
    1066             AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
    1067             return RTErrConvertFromErrno(rc);
    1068         }
    1069 #endif /* !RT_OS_DARWIN */
    1070     }
    1071 
    1072     return VINF_SUCCESS;
    1073 }
    1074 
    1075 
    1076 RTDECL(int)   RTSemRWRequestReadNoResume(RTSEMRW RWSem, unsigned cMillies)
    1077 {
    1078     /* EINTR isn't returned by the wait functions we're using. */
    1079     return RTSemRWRequestRead(RWSem, cMillies);
    1080 }
    1081 
    1082 
    1083 RTDECL(int)   RTSemRWReleaseRead(RTSEMRW RWSem)
    1084 {
    1085     /*
    1086      * Validate input.
    1087      */
    1088     if (!rtsemRWValid(RWSem))
    1089     {
    1090         AssertMsgFailed(("Invalid handle %p!\n", RWSem));
    1091         return VERR_INVALID_HANDLE;
    1092     }
    1093 
    1094     /*
    1095      * Try unlock it.
    1096      */
    1097     struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
    1098     if (pIntRWSem->WROwner == pthread_self())
    1099     {
    1100         AssertMsgFailed(("Tried to read unlock when write owner - read-write sem %p.\n", RWSem));
    1101         return VERR_NOT_OWNER;
    1102     }
    1103     int rc = pthread_rwlock_unlock(&pIntRWSem->RWLock);
    1104     if (rc)
    1105     {
    1106         AssertMsgFailed(("Failed read unlock read-write sem %p, rc=%d.\n", RWSem, rc));
    1107         return RTErrConvertFromErrno(rc);
    1108     }
    1109 
    1110     return VINF_SUCCESS;
    1111 }
    1112 
    1113 
    1114 RTDECL(int)   RTSemRWRequestWrite(RTSEMRW RWSem, unsigned cMillies)
    1115 {
    1116     /*
    1117      * Validate input.
    1118      */
    1119     if (!rtsemRWValid(RWSem))
    1120     {
    1121         AssertMsgFailed(("Invalid handle %p!\n", RWSem));
    1122         return VERR_INVALID_HANDLE;
    1123     }
    1124 
    1125     /*
    1126      * Try lock it.
    1127      */
    1128     struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
    1129     if (cMillies == RT_INDEFINITE_WAIT)
    1130     {
    1131         /* take rwlock */
    1132         int rc = pthread_rwlock_wrlock(&pIntRWSem->RWLock);
    1133         if (rc)
    1134         {
    1135             AssertMsgFailed(("Failed write lock read-write sem %p, rc=%d.\n", RWSem, rc));
    1136             return RTErrConvertFromErrno(rc);
    1137         }
    1138     }
    1139     else
    1140     {
    1141 #ifdef RT_OS_DARWIN
    1142         AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));
    1143         return VERR_NOT_IMPLEMENTED;
    1144 #else /* !RT_OS_DARWIN */
    1145         /*
    1146          * Get current time and calc end of wait time.
    1147          */
    1148         struct timespec     ts = {0,0};
    1149         clock_gettime(CLOCK_REALTIME, &ts);
    1150         if (cMillies != 0)
    1151         {
    1152             ts.tv_nsec += (cMillies % 1000) * 1000000;
    1153             ts.tv_sec  += cMillies / 1000;
    1154             if (ts.tv_nsec >= 1000000000)
    1155             {
    1156                 ts.tv_nsec -= 1000000000;
    1157                 ts.tv_sec++;
    1158             }
    1159         }
    1160 
    1161         /* take rwlock */
    1162         int rc = pthread_rwlock_timedwrlock(&pIntRWSem->RWLock, &ts);
    1163         if (rc)
    1164         {
    1165             AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
    1166             return RTErrConvertFromErrno(rc);
    1167         }
    1168 #endif /* !RT_OS_DARWIN */
    1169     }
    1170 
    1171 #ifdef RT_OS_SOLARIS
    1172     ASMAtomicXchgSize(&pIntRWSem->WROwner, pthread_self());
    1173 #else
    1174     ASMAtomicXchgPtr((void * volatile *)&pIntRWSem->WROwner, (void *)pthread_self());
    1175 #endif
    1176 
    1177     return VINF_SUCCESS;
    1178 }
    1179 
    1180 
    1181 RTDECL(int)   RTSemRWRequestWriteNoResume(RTSEMRW RWSem, unsigned cMillies)
    1182 {
    1183     /* EINTR isn't returned by the wait functions we're using. */
    1184     return RTSemRWRequestWrite(RWSem, cMillies);
    1185 }
    1186 
    1187 
    1188 RTDECL(int)   RTSemRWReleaseWrite(RTSEMRW RWSem)
    1189 {
    1190     /*
    1191      * Validate input.
    1192      */
    1193     if (!rtsemRWValid(RWSem))
    1194     {
    1195         AssertMsgFailed(("Invalid handle %p!\n", RWSem));
    1196         return VERR_INVALID_HANDLE;
    1197     }
    1198 
    1199     /*
    1200      * Try unlock it.
    1201      */
    1202     pthread_t                 Self = pthread_self();
    1203     struct RTSEMRWINTERNAL   *pIntRWSem = RWSem;
    1204     if (pIntRWSem->WROwner != Self)
    1205     {
    1206         AssertMsgFailed(("Not Write owner!\n"));
    1207         return VERR_NOT_OWNER;
    1208     }
    1209 
    1210     /*
    1211      * Try unlock it.
    1212      */
    1213 #ifdef RT_OS_SOLARIS
    1214     ASMAtomicXchgSize(&pIntRWSem->WROwner, (pthread_t)-1);
    1215 #else
    1216     AssertMsg(sizeof(pthread_t) == sizeof(void *), ("pthread_t is not the size of a pointer but %d bytes\n", sizeof(pthread_t)));
    1217     ASMAtomicXchgPtr((void * volatile *)&pIntRWSem->WROwner, (void *)(pthread_t)-1);
    1218 #endif
    1219     int rc = pthread_rwlock_unlock(&pIntRWSem->RWLock);
    1220     if (rc)
    1221     {
    1222         AssertMsgFailed(("Failed write unlock read-write sem %p, rc=%d.\n", RWSem, rc));
    1223         return RTErrConvertFromErrno(rc);
    1224     }
    1225 
    1226     return VINF_SUCCESS;
    1227 }
    1228 
  • trunk/src/VBox/Runtime/r3/posix/semmutex-posix.cpp

    r6734 r6738  
    11/* $Id$ */
    22/** @file
    3  * innotek Portable Runtime - Semaphores, POSIX.
     3 * innotek Portable Runtime - Mutex Semaphore, POSIX.
    44 */
    55
     
    3939#include <sys/time.h>
    4040
    41 #ifdef RT_OS_DARWIN
    42 # define pthread_yield() pthread_yield_np()
    43 #endif
    44 
    45 #ifdef RT_OS_SOLARIS
    46 # include <sched.h>
    47 # define pthread_yield() sched_yield()
    48 #endif
    49 
    5041
    5142/*******************************************************************************
    5243*   Structures and Typedefs                                                    *
    5344*******************************************************************************/
    54 
    55 /** Internal representation of the POSIX implementation of an Event semaphore.
    56  * The POSIX implementation uses a mutex and a condition variable to implement
    57  * the automatic reset event semaphore semantics.
    58  *
    59  * This must be identical to RTSEMEVENTMULTIINTERNAL!
    60  */
    61 struct RTSEMEVENTINTERNAL
    62 {
    63     /** pthread condition. */
    64     pthread_cond_t      Cond;
    65     /** pthread mutex which protects the condition and the event state. */
    66     pthread_mutex_t     Mutex;
    67     /** The state of the semaphore.
    68      * This is operated while owning mutex and using atomic updating. */
    69     volatile uint32_t   u32State;
    70     /** Number of waiters. */
    71     volatile uint32_t   cWaiters;
    72 };
    73 
    74 /** Posix internal representation of a Mutex Multi semaphore.
    75  * This must be identical to RTSEMEVENTINTERNAL! */
    76 struct RTSEMEVENTMULTIINTERNAL
    77 {
    78     /** pthread condition. */
    79     pthread_cond_t      Cond;
    80     /** pthread mutex which protects the condition and the event state. */
    81     pthread_mutex_t     Mutex;
    82     /** The state of the semaphore.
    83      * This is operated while owning mutex and using atomic updating. */
    84     volatile uint32_t   u32State;
    85     /** Number of waiters. */
    86     volatile uint32_t   cWaiters;
    87 };
    88 
    89 /** The valus of the u32State variable in a RTSEMEVENTINTERNAL and RTSEMEVENTMULTIINTERNAL.
    90  * @{ */
    91 /** The object isn't initialized. */
    92 #define EVENT_STATE_UNINITIALIZED   0
    93 /** The semaphore is is signaled. */
    94 #define EVENT_STATE_SIGNALED        0xff00ff00
    95 /** The semaphore is not signaled. */
    96 #define EVENT_STATE_NOT_SIGNALED    0x00ff00ff
    97 /** @} */
    98 
    99 
    10045/** Posix internal representation of a Mutex semaphore. */
    10146struct RTSEMMUTEXINTERNAL
     
    10853    volatile uint32_t   cNesting;
    10954};
    110 
    111 /** Posix internal representation of a read-write semaphore. */
    112 struct RTSEMRWINTERNAL
    113 {
    114     /** pthread rwlock. */
    115     pthread_rwlock_t    RWLock;
    116     /** Variable to check if initialized.
    117      * 0 is uninitialized, ~0 is inititialized. */
    118     volatile unsigned   uCheck;
    119     /** The write owner of the lock. */
    120     volatile pthread_t  WROwner;
    121 };
    122 
    123 
    124 /**
    125  * Validate an Event semaphore handle passed to one of the interface.
    126  *
    127  * @returns true if valid.
    128  * @returns false if invalid.
    129  * @param   pIntEventSem    Pointer to the event semaphore to validate.
    130  */
    131 inline bool rtsemEventValid(struct RTSEMEVENTINTERNAL *pIntEventSem)
    132 {
    133     if ((uintptr_t)pIntEventSem < 0x10000)
    134         return false;
    135 
    136     uint32_t    u32 = pIntEventSem->u32State; /* this is volatile, so a explicit read like this is needed. */
    137     if (    u32 != EVENT_STATE_NOT_SIGNALED
    138         &&  u32 != EVENT_STATE_SIGNALED)
    139         return false;
    140 
    141     return true;
    142 }
    143 
    144 
    145 RTDECL(int)  RTSemEventCreate(PRTSEMEVENT pEventSem)
    146 {
    147     int rc;
    148 
    149     /*
    150      * Allocate semaphore handle.
    151      */
    152     struct RTSEMEVENTINTERNAL *pIntEventSem = (struct RTSEMEVENTINTERNAL *)RTMemAlloc(sizeof(struct RTSEMEVENTINTERNAL));
    153     if (pIntEventSem)
    154     {
    155         /*
    156          * Create the condition variable.
    157          */
    158         pthread_condattr_t CondAttr;
    159         rc = pthread_condattr_init(&CondAttr);
    160         if (!rc)
    161         {
    162             rc = pthread_cond_init(&pIntEventSem->Cond, &CondAttr);
    163             if (!rc)
    164             {
    165                 /*
    166                  * Create the semaphore.
    167                  */
    168                 pthread_mutexattr_t MutexAttr;
    169                 rc = pthread_mutexattr_init(&MutexAttr);
    170                 if (!rc)
    171                 {
    172                     rc = pthread_mutex_init(&pIntEventSem->Mutex, &MutexAttr);
    173                     if (!rc)
    174                     {
    175                         pthread_mutexattr_destroy(&MutexAttr);
    176                         pthread_condattr_destroy(&CondAttr);
    177 
    178                         ASMAtomicXchgU32(&pIntEventSem->u32State, EVENT_STATE_NOT_SIGNALED);
    179                         ASMAtomicXchgU32(&pIntEventSem->cWaiters, 0);
    180 
    181                         *pEventSem = pIntEventSem;
    182                         return VINF_SUCCESS;
    183                     }
    184                     pthread_mutexattr_destroy(&MutexAttr);
    185                 }
    186                 pthread_cond_destroy(&pIntEventSem->Cond);
    187             }
    188             pthread_condattr_destroy(&CondAttr);
    189         }
    190 
    191         rc = RTErrConvertFromErrno(rc);
    192         RTMemFree(pIntEventSem);
    193     }
    194     else
    195         rc = VERR_NO_MEMORY;
    196 
    197     return rc;
    198 }
    199 
    200 
    201 RTDECL(int)  RTSemEventDestroy(RTSEMEVENT EventSem)
    202 {
    203     /*
    204      * Validate handle.
    205      */
    206     if (!rtsemEventValid(EventSem))
    207     {
    208         AssertMsgFailed(("Invalid handle %p!\n", EventSem));
    209         return VERR_INVALID_HANDLE;
    210     }
    211 
    212     /*
    213      * Abort all waiters forcing them to return failure.
    214      *
    215      */
    216     struct RTSEMEVENTINTERNAL *pIntEventSem = EventSem;
    217     int rc;
    218     for (int i = 30; i > 0; i--)
    219     {
    220         ASMAtomicXchgU32(&pIntEventSem->u32State, EVENT_STATE_UNINITIALIZED);
    221         rc = pthread_cond_destroy(&pIntEventSem->Cond);
    222         if (rc != EBUSY)
    223             break;
    224         pthread_cond_broadcast(&pIntEventSem->Cond);
    225         usleep(1000);
    226     } while (rc == EBUSY);
    227     if (rc)
    228     {
    229         AssertMsgFailed(("Failed to destroy event sem %p, rc=%d.\n", EventSem, rc));
    230         return RTErrConvertFromErrno(rc);
    231     }
    232 
    233     /*
    234      * Destroy the semaphore
    235      * If it's busy we'll wait a bit to give the threads a chance to be scheduled.
    236      */
    237     for (int i = 30; i > 0; i--)
    238     {
    239         rc = pthread_mutex_destroy(&pIntEventSem->Mutex);
    240         if (rc != EBUSY)
    241             break;
    242         usleep(1000);
    243     }
    244     if (rc)
    245     {
    246         AssertMsgFailed(("Failed to destroy event sem %p, rc=%d. (mutex)\n", EventSem, rc));
    247         return RTErrConvertFromErrno(rc);
    248     }
    249 
    250     /*
    251      * Free the semaphore memory and be gone.
    252      */
    253     RTMemFree(pIntEventSem);
    254     return VINF_SUCCESS;
    255 }
    256 
    257 
    258 RTDECL(int)  RTSemEventSignal(RTSEMEVENT EventSem)
    259 {
    260     /*
    261      * Validate input.
    262      */
    263     if (!rtsemEventValid(EventSem))
    264     {
    265         AssertMsgFailed(("Invalid handle %p!\n", EventSem));
    266         return VERR_INVALID_HANDLE;
    267     }
    268 
    269     /*
    270      * Lock the mutex semaphore.
    271      */
    272     struct RTSEMEVENTINTERNAL *pIntEventSem = EventSem;
    273     int rc = pthread_mutex_lock(&pIntEventSem->Mutex);
    274     if (rc)
    275     {
    276         AssertMsgFailed(("Failed to lock event sem %p, rc=%d.\n", EventSem, rc));
    277         return RTErrConvertFromErrno(rc);
    278     }
    279 
    280     /*
    281      * Check the state.
    282      */
    283     if (pIntEventSem->u32State == EVENT_STATE_NOT_SIGNALED)
    284     {
    285         ASMAtomicXchgU32(&pIntEventSem->u32State, EVENT_STATE_SIGNALED);
    286         rc = pthread_cond_signal(&pIntEventSem->Cond);
    287         AssertMsg(!rc, ("Failed to signal event sem %p, rc=%d.\n", EventSem, rc));
    288     }
    289     else if (pIntEventSem->u32State == EVENT_STATE_SIGNALED)
    290     {
    291         rc = pthread_cond_signal(&pIntEventSem->Cond); /* give'm another kick... */
    292         AssertMsg(!rc, ("Failed to signal event sem %p, rc=%d. (2)\n", EventSem, rc));
    293     }
    294     else
    295         rc = VERR_SEM_DESTROYED;
    296 
    297     /*
    298      * Release the mutex and return.
    299      */
    300     int rc2 = pthread_mutex_unlock(&pIntEventSem->Mutex);
    301     AssertMsg(!rc2, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc));
    302     if (rc)
    303         return RTErrConvertFromErrno(rc);
    304     if (rc2)
    305         return RTErrConvertFromErrno(rc2);
    306 
    307     return VINF_SUCCESS;
    308 }
    309 
    310 
    311 static int  rtSemEventWait(RTSEMEVENT EventSem, unsigned cMillies, bool fAutoResume)
    312 {
    313     /*
    314      * Validate input.
    315      */
    316     if (!rtsemEventValid(EventSem))
    317     {
    318         AssertMsgFailed(("Invalid handle %p!\n", EventSem));
    319         return VERR_INVALID_HANDLE;
    320     }
    321 
    322     /*
    323      * Timed or indefinite wait?
    324      */
    325     struct RTSEMEVENTINTERNAL *pIntEventSem = EventSem;
    326     if (cMillies == RT_INDEFINITE_WAIT)
    327     {
    328         /* for fairness, yield before going to sleep. */
    329         if (    ASMAtomicIncU32(&pIntEventSem->cWaiters) > 1
    330             &&  pIntEventSem->u32State == EVENT_STATE_SIGNALED)
    331             pthread_yield();
    332 
    333          /* take mutex */
    334         int rc = pthread_mutex_lock(&pIntEventSem->Mutex);
    335         if (rc)
    336         {
    337             ASMAtomicDecU32(&pIntEventSem->cWaiters);
    338             AssertMsgFailed(("Failed to lock event sem %p, rc=%d.\n", EventSem, rc));
    339             return RTErrConvertFromErrno(rc);
    340         }
    341 
    342         for (;;)
    343         {
    344             /* check state. */
    345             if (pIntEventSem->u32State == EVENT_STATE_SIGNALED)
    346             {
    347                 ASMAtomicXchgU32(&pIntEventSem->u32State, EVENT_STATE_NOT_SIGNALED);
    348                 ASMAtomicDecU32(&pIntEventSem->cWaiters);
    349                 rc = pthread_mutex_unlock(&pIntEventSem->Mutex);
    350                 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc)); NOREF(rc);
    351                 return VINF_SUCCESS;
    352             }
    353             if (pIntEventSem->u32State == EVENT_STATE_UNINITIALIZED)
    354             {
    355                 rc = pthread_mutex_unlock(&pIntEventSem->Mutex);
    356                 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc)); NOREF(rc);
    357                 return VERR_SEM_DESTROYED;
    358             }
    359 
    360             /* wait */
    361             rc = pthread_cond_wait(&pIntEventSem->Cond, &pIntEventSem->Mutex);
    362             if (rc)
    363             {
    364                 AssertMsgFailed(("Failed to wait on event sem %p, rc=%d.\n", EventSem, rc));
    365                 ASMAtomicDecU32(&pIntEventSem->cWaiters);
    366                 int rc2 = pthread_mutex_unlock(&pIntEventSem->Mutex);
    367                 AssertMsg(!rc2, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc2)); NOREF(rc2);
    368                 return RTErrConvertFromErrno(rc);
    369             }
    370         }
    371     }
    372     else
    373     {
    374         /*
    375          * Get current time and calc end of wait time.
    376          */
    377         struct timespec     ts = {0,0};
    378 #ifdef RT_OS_DARWIN
    379         struct timeval      tv = {0,0};
    380         gettimeofday(&tv, NULL);
    381         ts.tv_sec = tv.tv_sec;
    382         ts.tv_nsec = tv.tv_usec * 1000;
    383 #else
    384         clock_gettime(CLOCK_REALTIME, &ts);
    385 #endif
    386         if (cMillies != 0)
    387         {
    388             ts.tv_nsec += (cMillies % 1000) * 1000000;
    389             ts.tv_sec  += cMillies / 1000;
    390             if (ts.tv_nsec >= 1000000000)
    391             {
    392                 ts.tv_nsec -= 1000000000;
    393                 ts.tv_sec++;
    394             }
    395         }
    396 
    397         /* for fairness, yield before going to sleep. */
    398         if (ASMAtomicIncU32(&pIntEventSem->cWaiters) > 1)
    399             pthread_yield();
    400 
    401         /* take mutex */
    402 #ifdef RT_OS_DARWIN
    403         int rc = pthread_mutex_lock(&pIntEventSem->Mutex);
    404 #else
    405         int rc = pthread_mutex_timedlock(&pIntEventSem->Mutex, &ts);
    406 #endif
    407         if (rc)
    408         {
    409             ASMAtomicDecU32(&pIntEventSem->cWaiters);
    410             AssertMsg(rc == ETIMEDOUT, ("Failed to lock event sem %p, rc=%d.\n", EventSem, rc));
    411             return RTErrConvertFromErrno(rc);
    412         }
    413 
    414         for (;;)
    415         {
    416             /* check state. */
    417             if (pIntEventSem->u32State == EVENT_STATE_SIGNALED)
    418             {
    419                 ASMAtomicXchgU32(&pIntEventSem->u32State, EVENT_STATE_NOT_SIGNALED);
    420                 ASMAtomicDecU32(&pIntEventSem->cWaiters);
    421                 rc = pthread_mutex_unlock(&pIntEventSem->Mutex);
    422                 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc)); NOREF(rc);
    423                 return VINF_SUCCESS;
    424             }
    425             if (pIntEventSem->u32State == EVENT_STATE_UNINITIALIZED)
    426             {
    427                 rc = pthread_mutex_unlock(&pIntEventSem->Mutex);
    428                 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc)); NOREF(rc);
    429                 return VERR_SEM_DESTROYED;
    430             }
    431 
    432             /* wait */
    433             rc = pthread_cond_timedwait(&pIntEventSem->Cond, &pIntEventSem->Mutex, &ts);
    434             if (rc && (rc != EINTR || !fAutoResume)) /* according to SuS this function shall not return EINTR, but linux man page says differently. */
    435             {
    436                 AssertMsg(rc == ETIMEDOUT, ("Failed to wait on event sem %p, rc=%d.\n", EventSem, rc));
    437                 ASMAtomicDecU32(&pIntEventSem->cWaiters);
    438                 int rc2 = pthread_mutex_unlock(&pIntEventSem->Mutex);
    439                 AssertMsg(!rc2, ("Failed to unlock event sem %p, rc2=%d.\n", EventSem, rc2)); NOREF(rc2);
    440                 return RTErrConvertFromErrno(rc);
    441             }
    442         } /* for (;;) */
    443     }
    444 }
    445 
    446 
    447 RTDECL(int)  RTSemEventWait(RTSEMEVENT EventSem, unsigned cMillies)
    448 {
    449     int rc = rtSemEventWait(EventSem, cMillies, true);
    450     Assert(rc != VERR_INTERRUPTED);
    451     return rc;
    452 }
    453 
    454 
    455 RTDECL(int)  RTSemEventWaitNoResume(RTSEMEVENT EventSem, unsigned cMillies)
    456 {
    457     return rtSemEventWait(EventSem, cMillies, false);
    458 }
    459 
    460 
    461 
    462 
    463 
    464 
    465 /**
    466  * Validate an event multi semaphore handle passed to one of the interface.
    467  *
    468  * @returns true if valid.
    469  * @returns false if invalid.
    470  * @param   pIntEventMultiSem    Pointer to the event semaphore to validate.
    471  */
    472 inline bool rtsemEventMultiValid(struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem)
    473 {
    474     if ((uintptr_t)pIntEventMultiSem < 0x10000)
    475         return false;
    476 
    477     uint32_t    u32 = pIntEventMultiSem->u32State; /* this is volatile, so a explicit read like this is needed. */
    478     if (    u32 != EVENT_STATE_NOT_SIGNALED
    479         &&  u32 != EVENT_STATE_SIGNALED)
    480         return false;
    481 
    482     return true;
    483 }
    484 
    485 
    486 RTDECL(int)  RTSemEventMultiCreate(PRTSEMEVENTMULTI pEventMultiSem)
    487 {
    488     /* the code and the structure is identical with other type for this function. */
    489     return RTSemEventCreate((PRTSEMEVENT)pEventMultiSem);
    490 }
    491 
    492 
    493 RTDECL(int)  RTSemEventMultiDestroy(RTSEMEVENTMULTI EventMultiSem)
    494 {
    495     /* the code and the structure is identical with other type for this function. */
    496     return RTSemEventDestroy((RTSEMEVENT)EventMultiSem);
    497 }
    498 
    499 
    500 RTDECL(int)  RTSemEventMultiSignal(RTSEMEVENTMULTI EventMultiSem)
    501 {
    502     /* the code and the structure is identical with other type for this function. */
    503     return RTSemEventSignal((RTSEMEVENT)EventMultiSem);
    504 }
    505 
    506 
    507 RTDECL(int)  RTSemEventMultiReset(RTSEMEVENTMULTI EventMultiSem)
    508 {
    509     /*
    510      * Validate input.
    511      */
    512     if (!rtsemEventMultiValid(EventMultiSem))
    513     {
    514         AssertMsgFailed(("Invalid handle %p!\n", EventMultiSem));
    515         return VERR_INVALID_HANDLE;
    516     }
    517 
    518     /*
    519      * Lock the mutex semaphore.
    520      */
    521     struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem = EventMultiSem;
    522     int rc = pthread_mutex_lock(&pIntEventMultiSem->Mutex);
    523     if (rc)
    524     {
    525         AssertMsgFailed(("Failed to lock event multi sem %p, rc=%d.\n", EventMultiSem, rc));
    526         return RTErrConvertFromErrno(rc);
    527     }
    528 
    529     /*
    530      * Check the state.
    531      */
    532     if (pIntEventMultiSem->u32State == EVENT_STATE_SIGNALED)
    533         ASMAtomicXchgU32(&pIntEventMultiSem->u32State, EVENT_STATE_NOT_SIGNALED);
    534     else if (pIntEventMultiSem->u32State != EVENT_STATE_NOT_SIGNALED)
    535         rc = VERR_SEM_DESTROYED;
    536 
    537     /*
    538      * Release the mutex and return.
    539      */
    540     rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);
    541     if (rc)
    542     {
    543         AssertMsgFailed(("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc));
    544         return RTErrConvertFromErrno(rc);
    545     }
    546 
    547     return VINF_SUCCESS;
    548 
    549 }
    550 
    551 
    552 static int rtSemEventMultiWait(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies, bool fAutoResume)
    553 {
    554     /*
    555      * Validate input.
    556      */
    557     if (!rtsemEventMultiValid(EventMultiSem))
    558     {
    559         AssertMsgFailed(("Invalid handle %p!\n", EventMultiSem));
    560         return VERR_INVALID_HANDLE;
    561     }
    562 
    563     /*
    564      * Timed or indefinite wait?
    565      */
    566     struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem = EventMultiSem;
    567     if (cMillies == RT_INDEFINITE_WAIT)
    568     {
    569         /* take mutex */
    570         int rc = pthread_mutex_lock(&pIntEventMultiSem->Mutex);
    571         if (rc)
    572         {
    573             AssertMsgFailed(("Failed to lock event multi sem %p, rc=%d.\n", EventMultiSem, rc));
    574             return RTErrConvertFromErrno(rc);
    575         }
    576         ASMAtomicIncU32(&pIntEventMultiSem->cWaiters);
    577 
    578         for (;;)
    579         {
    580             /* check state. */
    581             if (pIntEventMultiSem->u32State == EVENT_STATE_SIGNALED)
    582             {
    583                 ASMAtomicDecU32(&pIntEventMultiSem->cWaiters);
    584                 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);
    585                 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc);
    586                 return VINF_SUCCESS;
    587             }
    588             if (pIntEventMultiSem->u32State == EVENT_STATE_UNINITIALIZED)
    589             {
    590                 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);
    591                 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc);
    592                 return VERR_SEM_DESTROYED;
    593             }
    594 
    595             /* wait */
    596             rc = pthread_cond_wait(&pIntEventMultiSem->Cond, &pIntEventMultiSem->Mutex);
    597             if (rc)
    598             {
    599                 AssertMsgFailed(("Failed to wait on event multi sem %p, rc=%d.\n", EventMultiSem, rc));
    600                 ASMAtomicDecU32(&pIntEventMultiSem->cWaiters);
    601                 int rc2 = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);
    602                 AssertMsg(!rc2, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc2)); NOREF(rc2);
    603                 return RTErrConvertFromErrno(rc);
    604             }
    605         }
    606     }
    607     else
    608     {
    609         /*
    610          * Get current time and calc end of wait time.
    611          */
    612         struct timespec     ts = {0,0};
    613 #ifdef RT_OS_DARWIN
    614         struct timeval      tv = {0,0};
    615         gettimeofday(&tv, NULL);
    616         ts.tv_sec = tv.tv_sec;
    617         ts.tv_nsec = tv.tv_usec * 1000;
    618 #else
    619         clock_gettime(CLOCK_REALTIME, &ts);
    620 #endif
    621         if (cMillies != 0)
    622         {
    623             ts.tv_nsec += (cMillies % 1000) * 1000000;
    624             ts.tv_sec  += cMillies / 1000;
    625             if (ts.tv_nsec >= 1000000000)
    626             {
    627                 ts.tv_nsec -= 1000000000;
    628                 ts.tv_sec++;
    629             }
    630         }
    631 
    632         /* take mutex */
    633 #ifdef RT_OS_DARWIN
    634         int rc = pthread_mutex_lock(&pIntEventMultiSem->Mutex);
    635 #else
    636         int rc = pthread_mutex_timedlock(&pIntEventMultiSem->Mutex, &ts);
    637 #endif
    638         if (rc)
    639         {
    640             AssertMsg(rc == ETIMEDOUT, ("Failed to lock event multi sem %p, rc=%d.\n", EventMultiSem, rc));
    641             return RTErrConvertFromErrno(rc);
    642         }
    643         ASMAtomicIncU32(&pIntEventMultiSem->cWaiters);
    644 
    645         for (;;)
    646         {
    647             /* check state. */
    648             if (pIntEventMultiSem->u32State == EVENT_STATE_SIGNALED)
    649             {
    650                 ASMAtomicXchgU32(&pIntEventMultiSem->u32State, EVENT_STATE_NOT_SIGNALED);
    651                 ASMAtomicDecU32(&pIntEventMultiSem->cWaiters);
    652                 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);
    653                 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc);
    654                 return VINF_SUCCESS;
    655             }
    656             if (pIntEventMultiSem->u32State == EVENT_STATE_UNINITIALIZED)
    657             {
    658                 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);
    659                 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc);
    660                 return VERR_SEM_DESTROYED;
    661             }
    662 
    663             /* wait */
    664             rc = pthread_cond_timedwait(&pIntEventMultiSem->Cond, &pIntEventMultiSem->Mutex, &ts);
    665             if (rc && (rc != EINTR || !fAutoResume)) /* according to SuS this function shall not return EINTR, but linux man page says differently. */
    666             {
    667                 AssertMsg(rc == ETIMEDOUT, ("Failed to wait on event multi sem %p, rc=%d.\n", EventMultiSem, rc));
    668                 ASMAtomicDecU32(&pIntEventMultiSem->cWaiters);
    669                 int rc2 = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);
    670                 AssertMsg(!rc2, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc2)); NOREF(rc2);
    671                 return RTErrConvertFromErrno(rc);
    672             }
    673         }
    674     }
    675 }
    676 
    677 
    678 RTDECL(int)  RTSemEventMultiWait(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies)
    679 {
    680     int rc = rtSemEventMultiWait(EventMultiSem, cMillies, true);
    681     Assert(rc != VERR_INTERRUPTED);
    682     return rc;
    683 }
    684 
    685 
    686 RTDECL(int)  RTSemEventMultiWaitNoResume(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies)
    687 {
    688     return rtSemEventMultiWait(EventMultiSem, cMillies, false);
    689 }
    690 
    691 
    69255
    69356
     
    921284}
    922285
    923 
    924 
    925 
    926 
    927 /**
    928  * Validate a read-write semaphore handle passed to one of the interface.
    929  *
    930  * @returns true if valid.
    931  * @returns false if invalid.
    932  * @param   pIntRWSem   Pointer to the read-write semaphore to validate.
    933  */
    934 inline bool rtsemRWValid(struct RTSEMRWINTERNAL *pIntRWSem)
    935 {
    936     if ((uintptr_t)pIntRWSem < 0x10000)
    937         return false;
    938 
    939     if (pIntRWSem->uCheck != (unsigned)~0)
    940         return false;
    941 
    942     return true;
    943 }
    944 
    945 
    946 RTDECL(int)   RTSemRWCreate(PRTSEMRW pRWSem)
    947 {
    948     int rc;
    949 
    950     /*
    951      * Allocate handle.
    952      */
    953     struct RTSEMRWINTERNAL *pIntRWSem = (struct RTSEMRWINTERNAL *)RTMemAlloc(sizeof(struct RTSEMRWINTERNAL));
    954     if (pIntRWSem)
    955     {
    956         /*
    957          * Create the rwlock.
    958          */
    959         pthread_rwlockattr_t    Attr;
    960         rc = pthread_rwlockattr_init(&Attr);
    961         if (!rc)
    962         {
    963             rc = pthread_rwlock_init(&pIntRWSem->RWLock, &Attr);
    964             if (!rc)
    965             {
    966                 pIntRWSem->uCheck = ~0;
    967                 pIntRWSem->WROwner = (pthread_t)-1;
    968                 *pRWSem = pIntRWSem;
    969                 return VINF_SUCCESS;
    970             }
    971         }
    972 
    973         rc = RTErrConvertFromErrno(rc);
    974         RTMemFree(pIntRWSem);
    975     }
    976     else
    977         rc = VERR_NO_MEMORY;
    978 
    979     return rc;
    980 }
    981 
    982 
    983 RTDECL(int)   RTSemRWDestroy(RTSEMRW RWSem)
    984 {
    985     /*
    986      * Validate input.
    987      */
    988     if (!rtsemRWValid(RWSem))
    989     {
    990         AssertMsgFailed(("Invalid handle %p!\n", RWSem));
    991         return VERR_INVALID_HANDLE;
    992     }
    993 
    994     /*
    995      * Try destroy it.
    996      */
    997     struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
    998     int rc = pthread_rwlock_destroy(&pIntRWSem->RWLock);
    999     if (!rc)
    1000     {
    1001         pIntRWSem->uCheck = 0;
    1002         RTMemFree(pIntRWSem);
    1003         rc = VINF_SUCCESS;
    1004     }
    1005     else
    1006     {
    1007         AssertMsgFailed(("Failed to destroy read-write sem %p, rc=%d.\n", RWSem, rc));
    1008         rc = RTErrConvertFromErrno(rc);
    1009     }
    1010 
    1011     return rc;
    1012 }
    1013 
    1014 
    1015 RTDECL(int)   RTSemRWRequestRead(RTSEMRW RWSem, unsigned cMillies)
    1016 {
    1017     /*
    1018      * Validate input.
    1019      */
    1020     if (!rtsemRWValid(RWSem))
    1021     {
    1022         AssertMsgFailed(("Invalid handle %p!\n", RWSem));
    1023         return VERR_INVALID_HANDLE;
    1024     }
    1025 
    1026     /*
    1027      * Try lock it.
    1028      */
    1029     struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
    1030     if (cMillies == RT_INDEFINITE_WAIT)
    1031     {
    1032         /* take rwlock */
    1033         int rc = pthread_rwlock_rdlock(&pIntRWSem->RWLock);
    1034         if (rc)
    1035         {
    1036             AssertMsgFailed(("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
    1037             return RTErrConvertFromErrno(rc);
    1038         }
    1039     }
    1040     else
    1041     {
    1042 #ifdef RT_OS_DARWIN
    1043         AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));
    1044         return VERR_NOT_IMPLEMENTED;
    1045 #else /* !RT_OS_DARWIN */
    1046         /*
    1047          * Get current time and calc end of wait time.
    1048          */
    1049         struct timespec     ts = {0,0};
    1050         clock_gettime(CLOCK_REALTIME, &ts);
    1051         if (cMillies != 0)
    1052         {
    1053             ts.tv_nsec += (cMillies % 1000) * 1000000;
    1054             ts.tv_sec  += cMillies / 1000;
    1055             if (ts.tv_nsec >= 1000000000)
    1056             {
    1057                 ts.tv_nsec -= 1000000000;
    1058                 ts.tv_sec++;
    1059             }
    1060         }
    1061 
    1062         /* take rwlock */
    1063         int rc = pthread_rwlock_timedrdlock(&pIntRWSem->RWLock, &ts);
    1064         if (rc)
    1065         {
    1066             AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
    1067             return RTErrConvertFromErrno(rc);
    1068         }
    1069 #endif /* !RT_OS_DARWIN */
    1070     }
    1071 
    1072     return VINF_SUCCESS;
    1073 }
    1074 
    1075 
    1076 RTDECL(int)   RTSemRWRequestReadNoResume(RTSEMRW RWSem, unsigned cMillies)
    1077 {
    1078     /* EINTR isn't returned by the wait functions we're using. */
    1079     return RTSemRWRequestRead(RWSem, cMillies);
    1080 }
    1081 
    1082 
    1083 RTDECL(int)   RTSemRWReleaseRead(RTSEMRW RWSem)
    1084 {
    1085     /*
    1086      * Validate input.
    1087      */
    1088     if (!rtsemRWValid(RWSem))
    1089     {
    1090         AssertMsgFailed(("Invalid handle %p!\n", RWSem));
    1091         return VERR_INVALID_HANDLE;
    1092     }
    1093 
    1094     /*
    1095      * Try unlock it.
    1096      */
    1097     struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
    1098     if (pIntRWSem->WROwner == pthread_self())
    1099     {
    1100         AssertMsgFailed(("Tried to read unlock when write owner - read-write sem %p.\n", RWSem));
    1101         return VERR_NOT_OWNER;
    1102     }
    1103     int rc = pthread_rwlock_unlock(&pIntRWSem->RWLock);
    1104     if (rc)
    1105     {
    1106         AssertMsgFailed(("Failed read unlock read-write sem %p, rc=%d.\n", RWSem, rc));
    1107         return RTErrConvertFromErrno(rc);
    1108     }
    1109 
    1110     return VINF_SUCCESS;
    1111 }
    1112 
    1113 
    1114 RTDECL(int)   RTSemRWRequestWrite(RTSEMRW RWSem, unsigned cMillies)
    1115 {
    1116     /*
    1117      * Validate input.
    1118      */
    1119     if (!rtsemRWValid(RWSem))
    1120     {
    1121         AssertMsgFailed(("Invalid handle %p!\n", RWSem));
    1122         return VERR_INVALID_HANDLE;
    1123     }
    1124 
    1125     /*
    1126      * Try lock it.
    1127      */
    1128     struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
    1129     if (cMillies == RT_INDEFINITE_WAIT)
    1130     {
    1131         /* take rwlock */
    1132         int rc = pthread_rwlock_wrlock(&pIntRWSem->RWLock);
    1133         if (rc)
    1134         {
    1135             AssertMsgFailed(("Failed write lock read-write sem %p, rc=%d.\n", RWSem, rc));
    1136             return RTErrConvertFromErrno(rc);
    1137         }
    1138     }
    1139     else
    1140     {
    1141 #ifdef RT_OS_DARWIN
    1142         AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));
    1143         return VERR_NOT_IMPLEMENTED;
    1144 #else /* !RT_OS_DARWIN */
    1145         /*
    1146          * Get current time and calc end of wait time.
    1147          */
    1148         struct timespec     ts = {0,0};
    1149         clock_gettime(CLOCK_REALTIME, &ts);
    1150         if (cMillies != 0)
    1151         {
    1152             ts.tv_nsec += (cMillies % 1000) * 1000000;
    1153             ts.tv_sec  += cMillies / 1000;
    1154             if (ts.tv_nsec >= 1000000000)
    1155             {
    1156                 ts.tv_nsec -= 1000000000;
    1157                 ts.tv_sec++;
    1158             }
    1159         }
    1160 
    1161         /* take rwlock */
    1162         int rc = pthread_rwlock_timedwrlock(&pIntRWSem->RWLock, &ts);
    1163         if (rc)
    1164         {
    1165             AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
    1166             return RTErrConvertFromErrno(rc);
    1167         }
    1168 #endif /* !RT_OS_DARWIN */
    1169     }
    1170 
    1171 #ifdef RT_OS_SOLARIS
    1172     ASMAtomicXchgSize(&pIntRWSem->WROwner, pthread_self());
    1173 #else
    1174     ASMAtomicXchgPtr((void * volatile *)&pIntRWSem->WROwner, (void *)pthread_self());
    1175 #endif
    1176 
    1177     return VINF_SUCCESS;
    1178 }
    1179 
    1180 
    1181 RTDECL(int)   RTSemRWRequestWriteNoResume(RTSEMRW RWSem, unsigned cMillies)
    1182 {
    1183     /* EINTR isn't returned by the wait functions we're using. */
    1184     return RTSemRWRequestWrite(RWSem, cMillies);
    1185 }
    1186 
    1187 
    1188 RTDECL(int)   RTSemRWReleaseWrite(RTSEMRW RWSem)
    1189 {
    1190     /*
    1191      * Validate input.
    1192      */
    1193     if (!rtsemRWValid(RWSem))
    1194     {
    1195         AssertMsgFailed(("Invalid handle %p!\n", RWSem));
    1196         return VERR_INVALID_HANDLE;
    1197     }
    1198 
    1199     /*
    1200      * Try unlock it.
    1201      */
    1202     pthread_t                 Self = pthread_self();
    1203     struct RTSEMRWINTERNAL   *pIntRWSem = RWSem;
    1204     if (pIntRWSem->WROwner != Self)
    1205     {
    1206         AssertMsgFailed(("Not Write owner!\n"));
    1207         return VERR_NOT_OWNER;
    1208     }
    1209 
    1210     /*
    1211      * Try unlock it.
    1212      */
    1213 #ifdef RT_OS_SOLARIS
    1214     ASMAtomicXchgSize(&pIntRWSem->WROwner, (pthread_t)-1);
    1215 #else
    1216     AssertMsg(sizeof(pthread_t) == sizeof(void *), ("pthread_t is not the size of a pointer but %d bytes\n", sizeof(pthread_t)));
    1217     ASMAtomicXchgPtr((void * volatile *)&pIntRWSem->WROwner, (void *)(pthread_t)-1);
    1218 #endif
    1219     int rc = pthread_rwlock_unlock(&pIntRWSem->RWLock);
    1220     if (rc)
    1221     {
    1222         AssertMsgFailed(("Failed write unlock read-write sem %p, rc=%d.\n", RWSem, rc));
    1223         return RTErrConvertFromErrno(rc);
    1224     }
    1225 
    1226     return VINF_SUCCESS;
    1227 }
    1228 
  • trunk/src/VBox/Runtime/r3/posix/semrw-posix.cpp

    r6734 r6738  
    11/* $Id$ */
    22/** @file
    3  * innotek Portable Runtime - Semaphores, POSIX.
     3 * innotek Portable Runtime - Read-Write Semaphore, POSIX.
    44 */
    55
     
    3939#include <sys/time.h>
    4040
    41 #ifdef RT_OS_DARWIN
    42 # define pthread_yield() pthread_yield_np()
    43 #endif
    44 
    45 #ifdef RT_OS_SOLARIS
    46 # include <sched.h>
    47 # define pthread_yield() sched_yield()
    48 #endif
    49 
    5041
    5142/*******************************************************************************
    5243*   Structures and Typedefs                                                    *
    5344*******************************************************************************/
    54 
    55 /** Internal representation of the POSIX implementation of an Event semaphore.
    56  * The POSIX implementation uses a mutex and a condition variable to implement
    57  * the automatic reset event semaphore semantics.
    58  *
    59  * This must be identical to RTSEMEVENTMULTIINTERNAL!
    60  */
    61 struct RTSEMEVENTINTERNAL
    62 {
    63     /** pthread condition. */
    64     pthread_cond_t      Cond;
    65     /** pthread mutex which protects the condition and the event state. */
    66     pthread_mutex_t     Mutex;
    67     /** The state of the semaphore.
    68      * This is operated while owning mutex and using atomic updating. */
    69     volatile uint32_t   u32State;
    70     /** Number of waiters. */
    71     volatile uint32_t   cWaiters;
    72 };
    73 
    74 /** Posix internal representation of a Mutex Multi semaphore.
    75  * This must be identical to RTSEMEVENTINTERNAL! */
    76 struct RTSEMEVENTMULTIINTERNAL
    77 {
    78     /** pthread condition. */
    79     pthread_cond_t      Cond;
    80     /** pthread mutex which protects the condition and the event state. */
    81     pthread_mutex_t     Mutex;
    82     /** The state of the semaphore.
    83      * This is operated while owning mutex and using atomic updating. */
    84     volatile uint32_t   u32State;
    85     /** Number of waiters. */
    86     volatile uint32_t   cWaiters;
    87 };
    88 
    89 /** The valus of the u32State variable in a RTSEMEVENTINTERNAL and RTSEMEVENTMULTIINTERNAL.
    90  * @{ */
    91 /** The object isn't initialized. */
    92 #define EVENT_STATE_UNINITIALIZED   0
    93 /** The semaphore is is signaled. */
    94 #define EVENT_STATE_SIGNALED        0xff00ff00
    95 /** The semaphore is not signaled. */
    96 #define EVENT_STATE_NOT_SIGNALED    0x00ff00ff
    97 /** @} */
    98 
    99 
    100 /** Posix internal representation of a Mutex semaphore. */
    101 struct RTSEMMUTEXINTERNAL
    102 {
    103     /** pthread mutex. */
    104     pthread_mutex_t     Mutex;
    105     /** The owner of the mutex. */
    106     volatile pthread_t  Owner;
    107     /** Nesting count. */
    108     volatile uint32_t   cNesting;
    109 };
    110 
    11145/** Posix internal representation of a read-write semaphore. */
    11246struct RTSEMRWINTERNAL
     
    12256
    12357
     58
    12459/**
    125  * Validate an Event semaphore handle passed to one of the interface.
     60 * Validate a read-write semaphore handle passed to one of the interface.
    12661 *
    12762 * @returns true if valid.
    12863 * @returns false if invalid.
    129  * @param   pIntEventSem    Pointer to the event semaphore to validate.
     64 * @param   pIntRWSem   Pointer to the read-write semaphore to validate.
    13065 */
    131 inline bool rtsemEventValid(struct RTSEMEVENTINTERNAL *pIntEventSem)
    132 {
    133     if ((uintptr_t)pIntEventSem < 0x10000)
     66inline bool rtsemRWValid(struct RTSEMRWINTERNAL *pIntRWSem)
     67{
     68    if ((uintptr_t)pIntRWSem < 0x10000)
    13469        return false;
    13570
    136     uint32_t    u32 = pIntEventSem->u32State; /* this is volatile, so a explicit read like this is needed. */
    137     if (    u32 != EVENT_STATE_NOT_SIGNALED
    138         &&  u32 != EVENT_STATE_SIGNALED)
     71    if (pIntRWSem->uCheck != (unsigned)~0)
    13972        return false;
    14073
     
    14376
    14477
    145 RTDECL(int)  RTSemEventCreate(PRTSEMEVENT pEventSem)
     78RTDECL(int)   RTSemRWCreate(PRTSEMRW pRWSem)
    14679{
    14780    int rc;
    14881
    14982    /*
    150      * Allocate semaphore handle.
    151      */
    152     struct RTSEMEVENTINTERNAL *pIntEventSem = (struct RTSEMEVENTINTERNAL *)RTMemAlloc(sizeof(struct RTSEMEVENTINTERNAL));
    153     if (pIntEventSem)
     83     * Allocate handle.
     84     */
     85    struct RTSEMRWINTERNAL *pIntRWSem = (struct RTSEMRWINTERNAL *)RTMemAlloc(sizeof(struct RTSEMRWINTERNAL));
     86    if (pIntRWSem)
    15487    {
    15588        /*
    156          * Create the condition variable.
     89         * Create the rwlock.
    15790         */
    158         pthread_condattr_t CondAttr;
    159         rc = pthread_condattr_init(&CondAttr);
     91        pthread_rwlockattr_t    Attr;
     92        rc = pthread_rwlockattr_init(&Attr);
    16093        if (!rc)
    16194        {
    162             rc = pthread_cond_init(&pIntEventSem->Cond, &CondAttr);
     95            rc = pthread_rwlock_init(&pIntRWSem->RWLock, &Attr);
    16396            if (!rc)
    16497            {
    165                 /*
    166                  * Create the semaphore.
    167                  */
    168                 pthread_mutexattr_t MutexAttr;
    169                 rc = pthread_mutexattr_init(&MutexAttr);
    170                 if (!rc)
    171                 {
    172                     rc = pthread_mutex_init(&pIntEventSem->Mutex, &MutexAttr);
    173                     if (!rc)
    174                     {
    175                         pthread_mutexattr_destroy(&MutexAttr);
    176                         pthread_condattr_destroy(&CondAttr);
    177 
    178                         ASMAtomicXchgU32(&pIntEventSem->u32State, EVENT_STATE_NOT_SIGNALED);
    179                         ASMAtomicXchgU32(&pIntEventSem->cWaiters, 0);
    180 
    181                         *pEventSem = pIntEventSem;
    182                         return VINF_SUCCESS;
    183                     }
    184                     pthread_mutexattr_destroy(&MutexAttr);
    185                 }
    186                 pthread_cond_destroy(&pIntEventSem->Cond);
     98                pIntRWSem->uCheck = ~0;
     99                pIntRWSem->WROwner = (pthread_t)-1;
     100                *pRWSem = pIntRWSem;
     101                return VINF_SUCCESS;
    187102            }
    188             pthread_condattr_destroy(&CondAttr);
    189103        }
    190104
    191105        rc = RTErrConvertFromErrno(rc);
    192         RTMemFree(pIntEventSem);
     106        RTMemFree(pIntRWSem);
    193107    }
    194108    else
     
    199113
    200114
    201 RTDECL(int)  RTSemEventDestroy(RTSEMEVENT EventSem)
    202 {
    203     /*
    204      * Validate handle.
    205      */
    206     if (!rtsemEventValid(EventSem))
    207     {
    208         AssertMsgFailed(("Invalid handle %p!\n", EventSem));
    209         return VERR_INVALID_HANDLE;
    210     }
    211 
    212     /*
    213      * Abort all waiters forcing them to return failure.
    214      *
    215      */
    216     struct RTSEMEVENTINTERNAL *pIntEventSem = EventSem;
    217     int rc;
    218     for (int i = 30; i > 0; i--)
    219     {
    220         ASMAtomicXchgU32(&pIntEventSem->u32State, EVENT_STATE_UNINITIALIZED);
    221         rc = pthread_cond_destroy(&pIntEventSem->Cond);
    222         if (rc != EBUSY)
    223             break;
    224         pthread_cond_broadcast(&pIntEventSem->Cond);
    225         usleep(1000);
    226     } while (rc == EBUSY);
    227     if (rc)
    228     {
    229         AssertMsgFailed(("Failed to destroy event sem %p, rc=%d.\n", EventSem, rc));
    230         return RTErrConvertFromErrno(rc);
    231     }
    232 
    233     /*
    234      * Destroy the semaphore
    235      * If it's busy we'll wait a bit to give the threads a chance to be scheduled.
    236      */
    237     for (int i = 30; i > 0; i--)
    238     {
    239         rc = pthread_mutex_destroy(&pIntEventSem->Mutex);
    240         if (rc != EBUSY)
    241             break;
    242         usleep(1000);
    243     }
    244     if (rc)
    245     {
    246         AssertMsgFailed(("Failed to destroy event sem %p, rc=%d. (mutex)\n", EventSem, rc));
    247         return RTErrConvertFromErrno(rc);
    248     }
    249 
    250     /*
    251      * Free the semaphore memory and be gone.
    252      */
    253     RTMemFree(pIntEventSem);
    254     return VINF_SUCCESS;
    255 }
    256 
    257 
    258 RTDECL(int)  RTSemEventSignal(RTSEMEVENT EventSem)
    259 {
    260     /*
    261      * Validate input.
    262      */
    263     if (!rtsemEventValid(EventSem))
    264     {
    265         AssertMsgFailed(("Invalid handle %p!\n", EventSem));
    266         return VERR_INVALID_HANDLE;
    267     }
    268 
    269     /*
    270      * Lock the mutex semaphore.
    271      */
    272     struct RTSEMEVENTINTERNAL *pIntEventSem = EventSem;
    273     int rc = pthread_mutex_lock(&pIntEventSem->Mutex);
    274     if (rc)
    275     {
    276         AssertMsgFailed(("Failed to lock event sem %p, rc=%d.\n", EventSem, rc));
    277         return RTErrConvertFromErrno(rc);
    278     }
    279 
    280     /*
    281      * Check the state.
    282      */
    283     if (pIntEventSem->u32State == EVENT_STATE_NOT_SIGNALED)
    284     {
    285         ASMAtomicXchgU32(&pIntEventSem->u32State, EVENT_STATE_SIGNALED);
    286         rc = pthread_cond_signal(&pIntEventSem->Cond);
    287         AssertMsg(!rc, ("Failed to signal event sem %p, rc=%d.\n", EventSem, rc));
    288     }
    289     else if (pIntEventSem->u32State == EVENT_STATE_SIGNALED)
    290     {
    291         rc = pthread_cond_signal(&pIntEventSem->Cond); /* give'm another kick... */
    292         AssertMsg(!rc, ("Failed to signal event sem %p, rc=%d. (2)\n", EventSem, rc));
     115RTDECL(int)   RTSemRWDestroy(RTSEMRW RWSem)
     116{
     117    /*
     118     * Validate input.
     119     */
     120    if (!rtsemRWValid(RWSem))
     121    {
     122        AssertMsgFailed(("Invalid handle %p!\n", RWSem));
     123        return VERR_INVALID_HANDLE;
     124    }
     125
     126    /*
     127     * Try destroy it.
     128     */
     129    struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
     130    int rc = pthread_rwlock_destroy(&pIntRWSem->RWLock);
     131    if (!rc)
     132    {
     133        pIntRWSem->uCheck = 0;
     134        RTMemFree(pIntRWSem);
     135        rc = VINF_SUCCESS;
    293136    }
    294137    else
    295         rc = VERR_SEM_DESTROYED;
    296 
    297     /*
    298      * Release the mutex and return.
    299      */
    300     int rc2 = pthread_mutex_unlock(&pIntEventSem->Mutex);
    301     AssertMsg(!rc2, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc));
    302     if (rc)
    303         return RTErrConvertFromErrno(rc);
    304     if (rc2)
    305         return RTErrConvertFromErrno(rc2);
    306 
    307     return VINF_SUCCESS;
    308 }
    309 
    310 
    311 static int  rtSemEventWait(RTSEMEVENT EventSem, unsigned cMillies, bool fAutoResume)
    312 {
    313     /*
    314      * Validate input.
    315      */
    316     if (!rtsemEventValid(EventSem))
    317     {
    318         AssertMsgFailed(("Invalid handle %p!\n", EventSem));
    319         return VERR_INVALID_HANDLE;
    320     }
    321 
    322     /*
    323      * Timed or indefinite wait?
    324      */
    325     struct RTSEMEVENTINTERNAL *pIntEventSem = EventSem;
     138    {
     139        AssertMsgFailed(("Failed to destroy read-write sem %p, rc=%d.\n", RWSem, rc));
     140        rc = RTErrConvertFromErrno(rc);
     141    }
     142
     143    return rc;
     144}
     145
     146
     147RTDECL(int)   RTSemRWRequestRead(RTSEMRW RWSem, unsigned cMillies)
     148{
     149    /*
     150     * Validate input.
     151     */
     152    if (!rtsemRWValid(RWSem))
     153    {
     154        AssertMsgFailed(("Invalid handle %p!\n", RWSem));
     155        return VERR_INVALID_HANDLE;
     156    }
     157
     158    /*
     159     * Try lock it.
     160     */
     161    struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
    326162    if (cMillies == RT_INDEFINITE_WAIT)
    327163    {
    328         /* for fairness, yield before going to sleep. */
    329         if (    ASMAtomicIncU32(&pIntEventSem->cWaiters) > 1
    330             &&  pIntEventSem->u32State == EVENT_STATE_SIGNALED)
    331             pthread_yield();
    332 
    333          /* take mutex */
    334         int rc = pthread_mutex_lock(&pIntEventSem->Mutex);
     164        /* take rwlock */
     165        int rc = pthread_rwlock_rdlock(&pIntRWSem->RWLock);
    335166        if (rc)
    336167        {
    337             ASMAtomicDecU32(&pIntEventSem->cWaiters);
    338             AssertMsgFailed(("Failed to lock event sem %p, rc=%d.\n", EventSem, rc));
    339             return RTErrConvertFromErrno(rc);
    340         }
    341 
    342         for (;;)
    343         {
    344             /* check state. */
    345             if (pIntEventSem->u32State == EVENT_STATE_SIGNALED)
    346             {
    347                 ASMAtomicXchgU32(&pIntEventSem->u32State, EVENT_STATE_NOT_SIGNALED);
    348                 ASMAtomicDecU32(&pIntEventSem->cWaiters);
    349                 rc = pthread_mutex_unlock(&pIntEventSem->Mutex);
    350                 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc)); NOREF(rc);
    351                 return VINF_SUCCESS;
    352             }
    353             if (pIntEventSem->u32State == EVENT_STATE_UNINITIALIZED)
    354             {
    355                 rc = pthread_mutex_unlock(&pIntEventSem->Mutex);
    356                 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc)); NOREF(rc);
    357                 return VERR_SEM_DESTROYED;
    358             }
    359 
    360             /* wait */
    361             rc = pthread_cond_wait(&pIntEventSem->Cond, &pIntEventSem->Mutex);
    362             if (rc)
    363             {
    364                 AssertMsgFailed(("Failed to wait on event sem %p, rc=%d.\n", EventSem, rc));
    365                 ASMAtomicDecU32(&pIntEventSem->cWaiters);
    366                 int rc2 = pthread_mutex_unlock(&pIntEventSem->Mutex);
    367                 AssertMsg(!rc2, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc2)); NOREF(rc2);
    368                 return RTErrConvertFromErrno(rc);
    369             }
    370         }
    371     }
    372     else
    373     {
    374         /*
    375          * Get current time and calc end of wait time.
    376          */
    377         struct timespec     ts = {0,0};
    378 #ifdef RT_OS_DARWIN
    379         struct timeval      tv = {0,0};
    380         gettimeofday(&tv, NULL);
    381         ts.tv_sec = tv.tv_sec;
    382         ts.tv_nsec = tv.tv_usec * 1000;
    383 #else
    384         clock_gettime(CLOCK_REALTIME, &ts);
    385 #endif
    386         if (cMillies != 0)
    387         {
    388             ts.tv_nsec += (cMillies % 1000) * 1000000;
    389             ts.tv_sec  += cMillies / 1000;
    390             if (ts.tv_nsec >= 1000000000)
    391             {
    392                 ts.tv_nsec -= 1000000000;
    393                 ts.tv_sec++;
    394             }
    395         }
    396 
    397         /* for fairness, yield before going to sleep. */
    398         if (ASMAtomicIncU32(&pIntEventSem->cWaiters) > 1)
    399             pthread_yield();
    400 
    401         /* take mutex */
    402 #ifdef RT_OS_DARWIN
    403         int rc = pthread_mutex_lock(&pIntEventSem->Mutex);
    404 #else
    405         int rc = pthread_mutex_timedlock(&pIntEventSem->Mutex, &ts);
    406 #endif
    407         if (rc)
    408         {
    409             ASMAtomicDecU32(&pIntEventSem->cWaiters);
    410             AssertMsg(rc == ETIMEDOUT, ("Failed to lock event sem %p, rc=%d.\n", EventSem, rc));
    411             return RTErrConvertFromErrno(rc);
    412         }
    413 
    414         for (;;)
    415         {
    416             /* check state. */
    417             if (pIntEventSem->u32State == EVENT_STATE_SIGNALED)
    418             {
    419                 ASMAtomicXchgU32(&pIntEventSem->u32State, EVENT_STATE_NOT_SIGNALED);
    420                 ASMAtomicDecU32(&pIntEventSem->cWaiters);
    421                 rc = pthread_mutex_unlock(&pIntEventSem->Mutex);
    422                 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc)); NOREF(rc);
    423                 return VINF_SUCCESS;
    424             }
    425             if (pIntEventSem->u32State == EVENT_STATE_UNINITIALIZED)
    426             {
    427                 rc = pthread_mutex_unlock(&pIntEventSem->Mutex);
    428                 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc)); NOREF(rc);
    429                 return VERR_SEM_DESTROYED;
    430             }
    431 
    432             /* wait */
    433             rc = pthread_cond_timedwait(&pIntEventSem->Cond, &pIntEventSem->Mutex, &ts);
    434             if (rc && (rc != EINTR || !fAutoResume)) /* according to SuS this function shall not return EINTR, but linux man page says differently. */
    435             {
    436                 AssertMsg(rc == ETIMEDOUT, ("Failed to wait on event sem %p, rc=%d.\n", EventSem, rc));
    437                 ASMAtomicDecU32(&pIntEventSem->cWaiters);
    438                 int rc2 = pthread_mutex_unlock(&pIntEventSem->Mutex);
    439                 AssertMsg(!rc2, ("Failed to unlock event sem %p, rc2=%d.\n", EventSem, rc2)); NOREF(rc2);
    440                 return RTErrConvertFromErrno(rc);
    441             }
    442         } /* for (;;) */
    443     }
    444 }
    445 
    446 
    447 RTDECL(int)  RTSemEventWait(RTSEMEVENT EventSem, unsigned cMillies)
    448 {
    449     int rc = rtSemEventWait(EventSem, cMillies, true);
    450     Assert(rc != VERR_INTERRUPTED);
    451     return rc;
    452 }
    453 
    454 
    455 RTDECL(int)  RTSemEventWaitNoResume(RTSEMEVENT EventSem, unsigned cMillies)
    456 {
    457     return rtSemEventWait(EventSem, cMillies, false);
    458 }
    459 
    460 
    461 
    462 
    463 
    464 
    465 /**
    466  * Validate an event multi semaphore handle passed to one of the interface.
    467  *
    468  * @returns true if valid.
    469  * @returns false if invalid.
    470  * @param   pIntEventMultiSem    Pointer to the event semaphore to validate.
    471  */
    472 inline bool rtsemEventMultiValid(struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem)
    473 {
    474     if ((uintptr_t)pIntEventMultiSem < 0x10000)
    475         return false;
    476 
    477     uint32_t    u32 = pIntEventMultiSem->u32State; /* this is volatile, so a explicit read like this is needed. */
    478     if (    u32 != EVENT_STATE_NOT_SIGNALED
    479         &&  u32 != EVENT_STATE_SIGNALED)
    480         return false;
    481 
    482     return true;
    483 }
    484 
    485 
    486 RTDECL(int)  RTSemEventMultiCreate(PRTSEMEVENTMULTI pEventMultiSem)
    487 {
    488     /* the code and the structure is identical with other type for this function. */
    489     return RTSemEventCreate((PRTSEMEVENT)pEventMultiSem);
    490 }
    491 
    492 
    493 RTDECL(int)  RTSemEventMultiDestroy(RTSEMEVENTMULTI EventMultiSem)
    494 {
    495     /* the code and the structure is identical with other type for this function. */
    496     return RTSemEventDestroy((RTSEMEVENT)EventMultiSem);
    497 }
    498 
    499 
    500 RTDECL(int)  RTSemEventMultiSignal(RTSEMEVENTMULTI EventMultiSem)
    501 {
    502     /* the code and the structure is identical with other type for this function. */
    503     return RTSemEventSignal((RTSEMEVENT)EventMultiSem);
    504 }
    505 
    506 
    507 RTDECL(int)  RTSemEventMultiReset(RTSEMEVENTMULTI EventMultiSem)
    508 {
    509     /*
    510      * Validate input.
    511      */
    512     if (!rtsemEventMultiValid(EventMultiSem))
    513     {
    514         AssertMsgFailed(("Invalid handle %p!\n", EventMultiSem));
    515         return VERR_INVALID_HANDLE;
    516     }
    517 
    518     /*
    519      * Lock the mutex semaphore.
    520      */
    521     struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem = EventMultiSem;
    522     int rc = pthread_mutex_lock(&pIntEventMultiSem->Mutex);
    523     if (rc)
    524     {
    525         AssertMsgFailed(("Failed to lock event multi sem %p, rc=%d.\n", EventMultiSem, rc));
    526         return RTErrConvertFromErrno(rc);
    527     }
    528 
    529     /*
    530      * Check the state.
    531      */
    532     if (pIntEventMultiSem->u32State == EVENT_STATE_SIGNALED)
    533         ASMAtomicXchgU32(&pIntEventMultiSem->u32State, EVENT_STATE_NOT_SIGNALED);
    534     else if (pIntEventMultiSem->u32State != EVENT_STATE_NOT_SIGNALED)
    535         rc = VERR_SEM_DESTROYED;
    536 
    537     /*
    538      * Release the mutex and return.
    539      */
    540     rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);
    541     if (rc)
    542     {
    543         AssertMsgFailed(("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc));
    544         return RTErrConvertFromErrno(rc);
    545     }
    546 
    547     return VINF_SUCCESS;
    548 
    549 }
    550 
    551 
    552 static int rtSemEventMultiWait(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies, bool fAutoResume)
    553 {
    554     /*
    555      * Validate input.
    556      */
    557     if (!rtsemEventMultiValid(EventMultiSem))
    558     {
    559         AssertMsgFailed(("Invalid handle %p!\n", EventMultiSem));
    560         return VERR_INVALID_HANDLE;
    561     }
    562 
    563     /*
    564      * Timed or indefinite wait?
    565      */
    566     struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem = EventMultiSem;
    567     if (cMillies == RT_INDEFINITE_WAIT)
    568     {
    569         /* take mutex */
    570         int rc = pthread_mutex_lock(&pIntEventMultiSem->Mutex);
    571         if (rc)
    572         {
    573             AssertMsgFailed(("Failed to lock event multi sem %p, rc=%d.\n", EventMultiSem, rc));
    574             return RTErrConvertFromErrno(rc);
    575         }
    576         ASMAtomicIncU32(&pIntEventMultiSem->cWaiters);
    577 
    578         for (;;)
    579         {
    580             /* check state. */
    581             if (pIntEventMultiSem->u32State == EVENT_STATE_SIGNALED)
    582             {
    583                 ASMAtomicDecU32(&pIntEventMultiSem->cWaiters);
    584                 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);
    585                 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc);
    586                 return VINF_SUCCESS;
    587             }
    588             if (pIntEventMultiSem->u32State == EVENT_STATE_UNINITIALIZED)
    589             {
    590                 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);
    591                 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc);
    592                 return VERR_SEM_DESTROYED;
    593             }
    594 
    595             /* wait */
    596             rc = pthread_cond_wait(&pIntEventMultiSem->Cond, &pIntEventMultiSem->Mutex);
    597             if (rc)
    598             {
    599                 AssertMsgFailed(("Failed to wait on event multi sem %p, rc=%d.\n", EventMultiSem, rc));
    600                 ASMAtomicDecU32(&pIntEventMultiSem->cWaiters);
    601                 int rc2 = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);
    602                 AssertMsg(!rc2, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc2)); NOREF(rc2);
    603                 return RTErrConvertFromErrno(rc);
    604             }
    605         }
    606     }
    607     else
    608     {
    609         /*
    610          * Get current time and calc end of wait time.
    611          */
    612         struct timespec     ts = {0,0};
    613 #ifdef RT_OS_DARWIN
    614         struct timeval      tv = {0,0};
    615         gettimeofday(&tv, NULL);
    616         ts.tv_sec = tv.tv_sec;
    617         ts.tv_nsec = tv.tv_usec * 1000;
    618 #else
    619         clock_gettime(CLOCK_REALTIME, &ts);
    620 #endif
    621         if (cMillies != 0)
    622         {
    623             ts.tv_nsec += (cMillies % 1000) * 1000000;
    624             ts.tv_sec  += cMillies / 1000;
    625             if (ts.tv_nsec >= 1000000000)
    626             {
    627                 ts.tv_nsec -= 1000000000;
    628                 ts.tv_sec++;
    629             }
    630         }
    631 
    632         /* take mutex */
    633 #ifdef RT_OS_DARWIN
    634         int rc = pthread_mutex_lock(&pIntEventMultiSem->Mutex);
    635 #else
    636         int rc = pthread_mutex_timedlock(&pIntEventMultiSem->Mutex, &ts);
    637 #endif
    638         if (rc)
    639         {
    640             AssertMsg(rc == ETIMEDOUT, ("Failed to lock event multi sem %p, rc=%d.\n", EventMultiSem, rc));
    641             return RTErrConvertFromErrno(rc);
    642         }
    643         ASMAtomicIncU32(&pIntEventMultiSem->cWaiters);
    644 
    645         for (;;)
    646         {
    647             /* check state. */
    648             if (pIntEventMultiSem->u32State == EVENT_STATE_SIGNALED)
    649             {
    650                 ASMAtomicXchgU32(&pIntEventMultiSem->u32State, EVENT_STATE_NOT_SIGNALED);
    651                 ASMAtomicDecU32(&pIntEventMultiSem->cWaiters);
    652                 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);
    653                 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc);
    654                 return VINF_SUCCESS;
    655             }
    656             if (pIntEventMultiSem->u32State == EVENT_STATE_UNINITIALIZED)
    657             {
    658                 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);
    659                 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc);
    660                 return VERR_SEM_DESTROYED;
    661             }
    662 
    663             /* wait */
    664             rc = pthread_cond_timedwait(&pIntEventMultiSem->Cond, &pIntEventMultiSem->Mutex, &ts);
    665             if (rc && (rc != EINTR || !fAutoResume)) /* according to SuS this function shall not return EINTR, but linux man page says differently. */
    666             {
    667                 AssertMsg(rc == ETIMEDOUT, ("Failed to wait on event multi sem %p, rc=%d.\n", EventMultiSem, rc));
    668                 ASMAtomicDecU32(&pIntEventMultiSem->cWaiters);
    669                 int rc2 = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);
    670                 AssertMsg(!rc2, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc2)); NOREF(rc2);
    671                 return RTErrConvertFromErrno(rc);
    672             }
    673         }
    674     }
    675 }
    676 
    677 
    678 RTDECL(int)  RTSemEventMultiWait(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies)
    679 {
    680     int rc = rtSemEventMultiWait(EventMultiSem, cMillies, true);
    681     Assert(rc != VERR_INTERRUPTED);
    682     return rc;
    683 }
    684 
    685 
    686 RTDECL(int)  RTSemEventMultiWaitNoResume(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies)
    687 {
    688     return rtSemEventMultiWait(EventMultiSem, cMillies, false);
    689 }
    690 
    691 
    692 
    693 
    694 
    695 /**
    696  * Validate a Mutex semaphore handle passed to one of the interface.
    697  *
    698  * @returns true if valid.
    699  * @returns false if invalid.
    700  * @param   pIntMutexSem    Pointer to the mutex semaphore to validate.
    701  */
    702 inline bool rtsemMutexValid(struct RTSEMMUTEXINTERNAL *pIntMutexSem)
    703 {
    704     if ((uintptr_t)pIntMutexSem < 0x10000)
    705         return false;
    706 
    707     if (pIntMutexSem->cNesting == (uint32_t)~0)
    708         return false;
    709 
    710     return true;
    711 }
    712 
    713 
    714 RTDECL(int)  RTSemMutexCreate(PRTSEMMUTEX pMutexSem)
    715 {
    716     int rc;
    717 
    718     /*
    719      * Allocate semaphore handle.
    720      */
    721     struct RTSEMMUTEXINTERNAL *pIntMutexSem = (struct RTSEMMUTEXINTERNAL *)RTMemAlloc(sizeof(struct RTSEMMUTEXINTERNAL));
    722     if (pIntMutexSem)
    723     {
    724         /*
    725          * Create the semaphore.
    726          */
    727         pthread_mutexattr_t MutexAttr;
    728         rc = pthread_mutexattr_init(&MutexAttr);
    729         if (!rc)
    730         {
    731             rc = pthread_mutex_init(&pIntMutexSem->Mutex, &MutexAttr);
    732             if (!rc)
    733             {
    734                 pthread_mutexattr_destroy(&MutexAttr);
    735 
    736                 pIntMutexSem->Owner    = (pthread_t)-1;
    737                 pIntMutexSem->cNesting = 0;
    738 
    739                 *pMutexSem = pIntMutexSem;
    740                 return VINF_SUCCESS;
    741             }
    742             pthread_mutexattr_destroy(&MutexAttr);
    743         }
    744         RTMemFree(pIntMutexSem);
    745     }
    746     else
    747         rc = VERR_NO_MEMORY;
    748 
    749     return rc;
    750 }
    751 
    752 
    753 RTDECL(int)  RTSemMutexDestroy(RTSEMMUTEX MutexSem)
    754 {
    755     /*
    756      * Validate input.
    757      */
    758     if (!rtsemMutexValid(MutexSem))
    759     {
    760         AssertMsgFailed(("Invalid handle %p!\n", MutexSem));
    761         return VERR_INVALID_HANDLE;
    762     }
    763 
    764     /*
    765      * Try destroy it.
    766      */
    767     struct RTSEMMUTEXINTERNAL *pIntMutexSem = MutexSem;
    768     int rc = pthread_mutex_destroy(&pIntMutexSem->Mutex);
    769     if (rc)
    770     {
    771         AssertMsgFailed(("Failed to destroy mutex sem %p, rc=%d.\n", MutexSem, rc));
    772         return RTErrConvertFromErrno(rc);
    773     }
    774 
    775     /*
    776      * Free the memory and be gone.
    777      */
    778     pIntMutexSem->Owner    = (pthread_t)-1;
    779     pIntMutexSem->cNesting = ~0;
    780     RTMemTmpFree(pIntMutexSem);
    781 
    782     return VINF_SUCCESS;
    783 }
    784 
    785 
    786 RTDECL(int)  RTSemMutexRequest(RTSEMMUTEX MutexSem, unsigned cMillies)
    787 {
    788     /*
    789      * Validate input.
    790      */
    791     if (!rtsemMutexValid(MutexSem))
    792     {
    793         AssertMsgFailed(("Invalid handle %p!\n", MutexSem));
    794         return VERR_INVALID_HANDLE;
    795     }
    796 
    797     /*
    798      * Check if nested request.
    799      */
    800     pthread_t                     Self = pthread_self();
    801     struct RTSEMMUTEXINTERNAL    *pIntMutexSem = MutexSem;
    802     if (    pIntMutexSem->Owner == Self
    803         &&  pIntMutexSem->cNesting > 0)
    804     {
    805         pIntMutexSem->cNesting++;
    806         return VINF_SUCCESS;
    807     }
    808 
    809     /*
    810      * Lock it.
    811      */
    812     if (cMillies == RT_INDEFINITE_WAIT)
    813     {
    814         /* take mutex */
    815         int rc = pthread_mutex_lock(&pIntMutexSem->Mutex);
    816         if (rc)
    817         {
    818             AssertMsgFailed(("Failed to lock mutex sem %p, rc=%d.\n", MutexSem, rc)); NOREF(rc);
     168            AssertMsgFailed(("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
    819169            return RTErrConvertFromErrno(rc);
    820170        }
     
    842192        }
    843193
    844         /* take mutex */
    845         int rc = pthread_mutex_timedlock(&pIntMutexSem->Mutex, &ts);
     194        /* take rwlock */
     195        int rc = pthread_rwlock_timedrdlock(&pIntRWSem->RWLock, &ts);
    846196        if (rc)
    847197        {
    848             AssertMsg(rc == ETIMEDOUT, ("Failed to lock mutex sem %p, rc=%d.\n", MutexSem, rc)); NOREF(rc);
     198            AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
    849199            return RTErrConvertFromErrno(rc);
    850200        }
     
    852202    }
    853203
    854     /*
    855      * Set the owner and nesting.
    856      */
    857     pIntMutexSem->Owner = Self;
    858     ASMAtomicXchgU32(&pIntMutexSem->cNesting, 1);
    859 
    860204    return VINF_SUCCESS;
    861205}
    862206
    863207
    864 RTDECL(int)  RTSemMutexRequestNoResume(RTSEMMUTEX MutexSem, unsigned cMillies)
     208RTDECL(int)   RTSemRWRequestReadNoResume(RTSEMRW RWSem, unsigned cMillies)
    865209{
    866210    /* EINTR isn't returned by the wait functions we're using. */
    867     return RTSemMutexRequest(MutexSem, cMillies);
    868 }
    869 
    870 
    871 RTDECL(int)  RTSemMutexRelease(RTSEMMUTEX MutexSem)
    872 {
    873     /*
    874      * Validate input.
    875      */
    876     if (!rtsemMutexValid(MutexSem))
    877     {
    878         AssertMsgFailed(("Invalid handle %p!\n", MutexSem));
    879         return VERR_INVALID_HANDLE;
    880     }
    881 
    882     /*
    883      * Check if nested.
    884      */
    885     pthread_t                     Self = pthread_self();
    886     struct RTSEMMUTEXINTERNAL    *pIntMutexSem = MutexSem;
    887     if (    pIntMutexSem->Owner != Self
    888         ||  pIntMutexSem->cNesting == (uint32_t)~0)
    889     {
    890         AssertMsgFailed(("Not owner of mutex %p!! Self=%08x Owner=%08x cNesting=%d\n",
    891                          pIntMutexSem, Self, pIntMutexSem->Owner, pIntMutexSem->cNesting));
     211    return RTSemRWRequestRead(RWSem, cMillies);
     212}
     213
     214
     215RTDECL(int)   RTSemRWReleaseRead(RTSEMRW RWSem)
     216{
     217    /*
     218     * Validate input.
     219     */
     220    if (!rtsemRWValid(RWSem))
     221    {
     222        AssertMsgFailed(("Invalid handle %p!\n", RWSem));
     223        return VERR_INVALID_HANDLE;
     224    }
     225
     226    /*
     227     * Try unlock it.
     228     */
     229    struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
     230    if (pIntRWSem->WROwner == pthread_self())
     231    {
     232        AssertMsgFailed(("Tried to read unlock when write owner - read-write sem %p.\n", RWSem));
    892233        return VERR_NOT_OWNER;
    893234    }
    894 
    895     /*
    896      * If nested we'll just pop a nesting.
    897      */
    898     if (pIntMutexSem->cNesting > 1)
    899     {
    900         pIntMutexSem->cNesting--;
    901         return VINF_SUCCESS;
    902     }
    903 
    904     /*
    905      * Clear the state. (cNesting == 1)
    906      */
    907     pIntMutexSem->Owner    = (pthread_t)-1;
    908     ASMAtomicXchgU32(&pIntMutexSem->cNesting, 0);
    909 
    910     /*
    911      * Unlock mutex semaphore.
    912      */
    913     int rc = pthread_mutex_unlock(&pIntMutexSem->Mutex);
     235    int rc = pthread_rwlock_unlock(&pIntRWSem->RWLock);
    914236    if (rc)
    915237    {
    916         AssertMsgFailed(("Failed to unlock mutex sem %p, rc=%d.\n", MutexSem, rc)); NOREF(rc);
     238        AssertMsgFailed(("Failed read unlock read-write sem %p, rc=%d.\n", RWSem, rc));
    917239        return RTErrConvertFromErrno(rc);
    918240    }
     
    922244
    923245
    924 
    925 
    926 
    927 /**
    928  * Validate a read-write semaphore handle passed to one of the interface.
    929  *
    930  * @returns true if valid.
    931  * @returns false if invalid.
    932  * @param   pIntRWSem   Pointer to the read-write semaphore to validate.
    933  */
    934 inline bool rtsemRWValid(struct RTSEMRWINTERNAL *pIntRWSem)
    935 {
    936     if ((uintptr_t)pIntRWSem < 0x10000)
    937         return false;
    938 
    939     if (pIntRWSem->uCheck != (unsigned)~0)
    940         return false;
    941 
    942     return true;
    943 }
    944 
    945 
    946 RTDECL(int)   RTSemRWCreate(PRTSEMRW pRWSem)
    947 {
    948     int rc;
    949 
    950     /*
    951      * Allocate handle.
    952      */
    953     struct RTSEMRWINTERNAL *pIntRWSem = (struct RTSEMRWINTERNAL *)RTMemAlloc(sizeof(struct RTSEMRWINTERNAL));
    954     if (pIntRWSem)
    955     {
    956         /*
    957          * Create the rwlock.
    958          */
    959         pthread_rwlockattr_t    Attr;
    960         rc = pthread_rwlockattr_init(&Attr);
    961         if (!rc)
    962         {
    963             rc = pthread_rwlock_init(&pIntRWSem->RWLock, &Attr);
    964             if (!rc)
    965             {
    966                 pIntRWSem->uCheck = ~0;
    967                 pIntRWSem->WROwner = (pthread_t)-1;
    968                 *pRWSem = pIntRWSem;
    969                 return VINF_SUCCESS;
    970             }
    971         }
    972 
    973         rc = RTErrConvertFromErrno(rc);
    974         RTMemFree(pIntRWSem);
    975     }
    976     else
    977         rc = VERR_NO_MEMORY;
    978 
    979     return rc;
    980 }
    981 
    982 
    983 RTDECL(int)   RTSemRWDestroy(RTSEMRW RWSem)
    984 {
    985     /*
    986      * Validate input.
    987      */
    988     if (!rtsemRWValid(RWSem))
    989     {
    990         AssertMsgFailed(("Invalid handle %p!\n", RWSem));
    991         return VERR_INVALID_HANDLE;
    992     }
    993 
    994     /*
    995      * Try destroy it.
    996      */
    997     struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
    998     int rc = pthread_rwlock_destroy(&pIntRWSem->RWLock);
    999     if (!rc)
    1000     {
    1001         pIntRWSem->uCheck = 0;
    1002         RTMemFree(pIntRWSem);
    1003         rc = VINF_SUCCESS;
    1004     }
    1005     else
    1006     {
    1007         AssertMsgFailed(("Failed to destroy read-write sem %p, rc=%d.\n", RWSem, rc));
    1008         rc = RTErrConvertFromErrno(rc);
    1009     }
    1010 
    1011     return rc;
    1012 }
    1013 
    1014 
    1015 RTDECL(int)   RTSemRWRequestRead(RTSEMRW RWSem, unsigned cMillies)
     246RTDECL(int)   RTSemRWRequestWrite(RTSEMRW RWSem, unsigned cMillies)
    1016247{
    1017248    /*
     
    1031262    {
    1032263        /* take rwlock */
    1033         int rc = pthread_rwlock_rdlock(&pIntRWSem->RWLock);
     264        int rc = pthread_rwlock_wrlock(&pIntRWSem->RWLock);
    1034265        if (rc)
    1035266        {
    1036             AssertMsgFailed(("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
     267            AssertMsgFailed(("Failed write lock read-write sem %p, rc=%d.\n", RWSem, rc));
    1037268            return RTErrConvertFromErrno(rc);
    1038269        }
     
    1061292
    1062293        /* take rwlock */
    1063         int rc = pthread_rwlock_timedrdlock(&pIntRWSem->RWLock, &ts);
    1064         if (rc)
    1065         {
    1066             AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
    1067             return RTErrConvertFromErrno(rc);
    1068         }
    1069 #endif /* !RT_OS_DARWIN */
    1070     }
    1071 
    1072     return VINF_SUCCESS;
    1073 }
    1074 
    1075 
    1076 RTDECL(int)   RTSemRWRequestReadNoResume(RTSEMRW RWSem, unsigned cMillies)
    1077 {
    1078     /* EINTR isn't returned by the wait functions we're using. */
    1079     return RTSemRWRequestRead(RWSem, cMillies);
    1080 }
    1081 
    1082 
    1083 RTDECL(int)   RTSemRWReleaseRead(RTSEMRW RWSem)
    1084 {
    1085     /*
    1086      * Validate input.
    1087      */
    1088     if (!rtsemRWValid(RWSem))
    1089     {
    1090         AssertMsgFailed(("Invalid handle %p!\n", RWSem));
    1091         return VERR_INVALID_HANDLE;
    1092     }
    1093 
    1094     /*
    1095      * Try unlock it.
    1096      */
    1097     struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
    1098     if (pIntRWSem->WROwner == pthread_self())
    1099     {
    1100         AssertMsgFailed(("Tried to read unlock when write owner - read-write sem %p.\n", RWSem));
    1101         return VERR_NOT_OWNER;
    1102     }
    1103     int rc = pthread_rwlock_unlock(&pIntRWSem->RWLock);
    1104     if (rc)
    1105     {
    1106         AssertMsgFailed(("Failed read unlock read-write sem %p, rc=%d.\n", RWSem, rc));
    1107         return RTErrConvertFromErrno(rc);
    1108     }
    1109 
    1110     return VINF_SUCCESS;
    1111 }
    1112 
    1113 
    1114 RTDECL(int)   RTSemRWRequestWrite(RTSEMRW RWSem, unsigned cMillies)
    1115 {
    1116     /*
    1117      * Validate input.
    1118      */
    1119     if (!rtsemRWValid(RWSem))
    1120     {
    1121         AssertMsgFailed(("Invalid handle %p!\n", RWSem));
    1122         return VERR_INVALID_HANDLE;
    1123     }
    1124 
    1125     /*
    1126      * Try lock it.
    1127      */
    1128     struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
    1129     if (cMillies == RT_INDEFINITE_WAIT)
    1130     {
    1131         /* take rwlock */
    1132         int rc = pthread_rwlock_wrlock(&pIntRWSem->RWLock);
    1133         if (rc)
    1134         {
    1135             AssertMsgFailed(("Failed write lock read-write sem %p, rc=%d.\n", RWSem, rc));
    1136             return RTErrConvertFromErrno(rc);
    1137         }
    1138     }
    1139     else
    1140     {
    1141 #ifdef RT_OS_DARWIN
    1142         AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));
    1143         return VERR_NOT_IMPLEMENTED;
    1144 #else /* !RT_OS_DARWIN */
    1145         /*
    1146          * Get current time and calc end of wait time.
    1147          */
    1148         struct timespec     ts = {0,0};
    1149         clock_gettime(CLOCK_REALTIME, &ts);
    1150         if (cMillies != 0)
    1151         {
    1152             ts.tv_nsec += (cMillies % 1000) * 1000000;
    1153             ts.tv_sec  += cMillies / 1000;
    1154             if (ts.tv_nsec >= 1000000000)
    1155             {
    1156                 ts.tv_nsec -= 1000000000;
    1157                 ts.tv_sec++;
    1158             }
    1159         }
    1160 
    1161         /* take rwlock */
    1162294        int rc = pthread_rwlock_timedwrlock(&pIntRWSem->RWLock, &ts);
    1163295        if (rc)
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