VirtualBox

Changeset 6738 in vbox for trunk/src/VBox/Runtime/r3/linux


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/r3/linux
Files:
2 copied
1 moved

Legend:

Unmodified
Added
Removed
  • 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
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