Changeset 6738 in vbox for trunk/src/VBox/Runtime/r3/linux
- Timestamp:
- Feb 1, 2008 9:45:27 PM (17 years ago)
- 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 1 1 /* $Id$ */ 2 2 /** @file 3 * innotek Portable Runtime - Semaphores, Linux (AMD64 only ATM).3 * innotek Portable Runtime - Event Semaphore, Linux (2.6.x+). 4 4 */ 5 5 … … 46 46 # define FUTEX_WAIT 0 47 47 # define FUTEX_WAKE 1 48 #endif 48 #endif 49 49 50 50 … … 52 52 * Structures and Typedefs * 53 53 *******************************************************************************/ 54 55 54 /** 56 * Linux (single wakup) event semaphore. 55 * Linux (single wakup) event semaphore. 57 56 */ 58 57 struct RTSEMEVENTINTERNAL … … 61 60 intptr_t volatile iMagic; 62 61 /** The futex state variable. 63 * <0 means signaled. 62 * <0 means signaled. 64 63 * 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. 66 65 */ 67 66 int32_t volatile cWaiters; 68 };69 70 71 /**72 * Linux multiple wakup event semaphore.73 */74 struct RTSEMEVENTMULTIINTERNAL75 {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_MUTEX88 /**89 * Posix internal representation of a Mutex semaphore.90 */91 struct RTSEMMUTEXINTERNAL92 {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 RTSEMMUTEXINTERNAL105 {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 RTSEMRWINTERNAL126 {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 67 }; 135 68 … … 175 108 */ 176 109 struct RTSEMEVENTINTERNAL *pIntEventSem = EventSem; 177 AssertReturn(VALID_PTR(pIntEventSem) && pIntEventSem->iMagic == RTSEMEVENT_MAGIC, 110 AssertReturn(VALID_PTR(pIntEventSem) && pIntEventSem->iMagic == RTSEMEVENT_MAGIC, 178 111 VERR_INVALID_HANDLE); 179 112 … … 202 135 */ 203 136 struct RTSEMEVENTINTERNAL *pIntEventSem = EventSem; 204 AssertReturn(VALID_PTR(pIntEventSem) && pIntEventSem->iMagic == RTSEMEVENT_MAGIC, 137 AssertReturn(VALID_PTR(pIntEventSem) && pIntEventSem->iMagic == RTSEMEVENT_MAGIC, 205 138 VERR_INVALID_HANDLE); 206 139 /* … … 217 150 else if (iCur < 0) 218 151 break; /* already signaled */ 219 else 152 else 220 153 { 221 154 /* somebody is waiting, try wake up one of them. */ … … 228 161 AssertMsg(cWoken == 0, ("%ld\n", cWoken)); 229 162 230 /* 163 /* 231 164 * 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 233 166 * 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 235 168 * same time and only one thread waiting. 236 169 * 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 240 173 * brain dead and need fixing of course. 241 174 */ … … 261 194 */ 262 195 struct RTSEMEVENTINTERNAL *pIntEventSem = EventSem; 263 AssertReturn(VALID_PTR(pIntEventSem) && pIntEventSem->iMagic == RTSEMEVENT_MAGIC, 196 AssertReturn(VALID_PTR(pIntEventSem) && pIntEventSem->iMagic == RTSEMEVENT_MAGIC, 264 197 VERR_INVALID_HANDLE); 265 198 … … 287 220 for (unsigned i = 0;; i++) 288 221 { 289 /* 290 * Announce that we're among the waiters. 222 /* 223 * Announce that we're among the waiters. 291 224 */ 292 225 int32_t iNew = ASMAtomicIncS32(&pIntEventSem->cWaiters); … … 304 237 /* Did somebody wake us up from RTSemEventSignal()? */ 305 238 if (rc == 0) 306 return VINF_SUCCESS; 239 return VINF_SUCCESS; 307 240 308 241 /* No, then the kernel woke us up or we failed going to sleep. Adjust the accounting. */ … … 310 243 Assert(iNew >= 0); 311 244 312 /* 245 /* 313 246 * Act on the wakup code. 314 247 */ … … 317 250 Assert(pTimeout); 318 251 return VERR_TIMEOUT; 319 } 252 } 320 253 if (rc == -EWOULDBLOCK) 321 254 /* retry with new value. */; … … 356 289 } 357 290 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_STRICT438 int32_t i = pIntEventMultiSem->iState;439 Assert(i == 0 || i == -1 || i == 1);440 #endif441 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 been488 * 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 == 1493 || 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 else517 {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_MUTEX559 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_MUTEX571 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 else604 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 == Self660 && 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 else680 {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 != Self740 || 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 == Self845 && 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 else898 {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 != Self948 || 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 else1037 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 else1066 {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 else1101 {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 else1195 {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 1 1 /* $Id$ */ 2 2 /** @file 3 * innotek Portable Runtime - Semaphores, Linux (AMD64 only ATM).3 * innotek Portable Runtime - Multiple Release Event Semaphore, Linux (2.6.x+). 4 4 */ 5 5 … … 46 46 # define FUTEX_WAIT 0 47 47 # define FUTEX_WAKE 1 48 #endif 48 #endif 49 49 50 50 … … 52 52 * Structures and Typedefs * 53 53 *******************************************************************************/ 54 55 54 /** 56 * Linux (single wakup) event semaphore.57 */ 58 struct RTSEMEVENT INTERNAL55 * Linux multiple wakup event semaphore. 56 */ 57 struct RTSEMEVENTMULTIINTERNAL 59 58 { 60 59 /** Magic value. */ 61 60 intptr_t volatile iMagic; 62 61 /** The futex state variable. 63 * <0 means signaled.62 * -1 means signaled. 64 63 * 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. 82 65 */ 83 66 int32_t volatile iState; 84 };85 86 87 #ifndef VBOX_REWRITTEN_MUTEX88 /**89 * Posix internal representation of a Mutex semaphore.90 */91 struct RTSEMMUTEXINTERNAL92 {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 RTSEMMUTEXINTERNAL105 {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 RTSEMRWINTERNAL126 {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 67 }; 135 68 … … 149 82 return rc; 150 83 } 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 else220 {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 a233 * non-zero return value.234 * 2) There are two threads signaling the event at the235 * same time and only one thread waiting.236 *237 * At this point we know that nobody is activly waiting on the event but238 * at the same time, we are racing someone updating the state. The current239 * strategy is to spin till the thread racing us is done, this is kind of240 * 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 else249 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 else328 {329 /* this shouldn't happen! */330 AssertMsgFailed(("rc=%ld errno=%d\n", rc, errno));331 return RTErrConvertFromErrno(rc);332 }333 }334 else335 {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 84 361 85 … … 383 107 */ 384 108 struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem = EventMultiSem; 385 AssertReturn(VALID_PTR(pIntEventMultiSem) && pIntEventMultiSem->iMagic == RTSEMEVENTMULTI_MAGIC, 109 AssertReturn(VALID_PTR(pIntEventMultiSem) && pIntEventMultiSem->iMagic == RTSEMEVENTMULTI_MAGIC, 386 110 VERR_INVALID_HANDLE); 387 111 … … 410 134 */ 411 135 struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem = EventMultiSem; 412 AssertReturn(VALID_PTR(pIntEventMultiSem) && pIntEventMultiSem->iMagic == RTSEMEVENTMULTI_MAGIC, 136 AssertReturn(VALID_PTR(pIntEventMultiSem) && pIntEventMultiSem->iMagic == RTSEMEVENTMULTI_MAGIC, 413 137 VERR_INVALID_HANDLE); 414 138 /* … … 433 157 */ 434 158 struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem = EventMultiSem; 435 AssertReturn(VALID_PTR(pIntEventMultiSem) && pIntEventMultiSem->iMagic == RTSEMEVENTMULTI_MAGIC, 159 AssertReturn(VALID_PTR(pIntEventMultiSem) && pIntEventMultiSem->iMagic == RTSEMEVENTMULTI_MAGIC, 436 160 VERR_INVALID_HANDLE); 437 161 #ifdef RT_STRICT 438 162 int32_t i = pIntEventMultiSem->iState; 439 163 Assert(i == 0 || i == -1 || i == 1); 440 #endif 164 #endif 441 165 442 166 /* … … 454 178 */ 455 179 struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem = EventMultiSem; 456 AssertReturn(VALID_PTR(pIntEventMultiSem) && pIntEventMultiSem->iMagic == RTSEMEVENTMULTI_MAGIC, 180 AssertReturn(VALID_PTR(pIntEventMultiSem) && pIntEventMultiSem->iMagic == RTSEMEVENTMULTI_MAGIC, 457 181 VERR_INVALID_HANDLE); 458 182 … … 485 209 { 486 210 /* 487 * Start waiting. We only account for there being or having been 211 * Start waiting. We only account for there being or having been 488 212 * threads waiting on the semaphore to keep things simple. 489 213 */ … … 497 221 return VERR_SEM_DESTROYED; 498 222 if (rc == 0) 499 return VINF_SUCCESS; 500 501 /* 223 return VINF_SUCCESS; 224 225 /* 502 226 * Act on the wakup code. 503 227 */ … … 506 230 Assert(pTimeout); 507 231 return VERR_TIMEOUT; 508 } 232 } 509 233 if (rc == -EWOULDBLOCK) 510 234 /* retry, the value changed. */; … … 540 264 } 541 265 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_MUTEX559 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_MUTEX571 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 else604 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 == Self660 && 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 else680 {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 != Self740 || 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 == Self845 && 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 else898 {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 != Self948 || 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 else1037 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 else1066 {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 else1101 {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 else1195 {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 1 1 /* $Id$ */ 2 2 /** @file 3 * innotek Portable Runtime - Semaphores, Linux (AMD64 only ATM).3 * innotek Portable Runtime - Mutex Semaphore, Linux (2.6.x+). 4 4 */ 5 5 … … 46 46 # define FUTEX_WAIT 0 47 47 # define FUTEX_WAKE 1 48 #endif 48 #endif 49 49 50 50 … … 52 52 * Structures and Typedefs * 53 53 *******************************************************************************/ 54 55 /**56 * Linux (single wakup) event semaphore.57 */58 struct RTSEMEVENTINTERNAL59 {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 RTSEMEVENTMULTIINTERNAL75 {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_MUTEX88 /**89 * Posix internal representation of a Mutex semaphore.90 */91 struct RTSEMMUTEXINTERNAL92 {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 54 /** 102 55 * Linux internal representation of a Mutex semaphore. … … 117 70 volatile uint32_t cNesting; 118 71 }; 119 #endif /* VBOX_REWRITTEN_MUTEX */120 121 122 /**123 * Posix internal representation of a read-write semaphore.124 */125 struct RTSEMRWINTERNAL126 {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 };135 72 136 73 … … 149 86 return rc; 150 87 } 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 else220 {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 a233 * non-zero return value.234 * 2) There are two threads signaling the event at the235 * same time and only one thread waiting.236 *237 * At this point we know that nobody is activly waiting on the event but238 * at the same time, we are racing someone updating the state. The current239 * strategy is to spin till the thread racing us is done, this is kind of240 * 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 else249 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 else328 {329 /* this shouldn't happen! */330 AssertMsgFailed(("rc=%ld errno=%d\n", rc, errno));331 return RTErrConvertFromErrno(rc);332 }333 }334 else335 {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_STRICT438 int32_t i = pIntEventMultiSem->iState;439 Assert(i == 0 || i == -1 || i == 1);440 #endif441 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 been488 * 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 == 1493 || 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 else517 {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 88 545 89 … … 556 100 return false; 557 101 558 #ifdef VBOX_REWRITTEN_MUTEX559 102 if (pIntMutexSem->iMagic != RTSEMMUTEX_MAGIC) 560 103 return false; 561 104 562 #endif /* VBOX_REWRITTEN_MUTEX */563 105 if (pIntMutexSem->cNesting == (uint32_t)~0) 564 106 return false; … … 568 110 569 111 570 #ifndef VBOX_REWRITTEN_MUTEX571 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 else604 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 == Self660 && 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 else680 {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 != Self740 || 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 112 RTDECL(int) RTSemMutexCreate(PRTSEMMUTEX pMutexSem) 776 113 { … … 913 250 * When leaving this loop, iState is set to 2. This means that we gained the 914 251 * 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 will252 * thread might entered this loop at nearly the same time. Therefore we will 916 253 * call futex_wakeup once too often (if _no_ other thread entered this loop). 917 254 * The key problem is the simple futex_wait test for x != y (iState != 2) in … … 994 331 return VINF_SUCCESS; 995 332 } 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.