Changeset 6738 in vbox
- Timestamp:
- Feb 1, 2008 9:45:27 PM (17 years ago)
- Location:
- trunk/src/VBox/Runtime
- Files:
-
- 1 edited
- 5 copied
- 2 moved
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/Makefile.kmk
r6730 r6738 306 306 r3/posix/rand-posix.cpp \ 307 307 r3/posix/RTTimeNow-posix.cpp \ 308 r3/posix/semrw-posix.cpp \ 308 309 r3/posix/system-posix.cpp \ 309 310 r3/posix/thread-posix.cpp \ … … 312 313 r3/posix/utf8-posix.cpp 313 314 ifeq ($(BUILD_TARGET_ARCH),amd64) 314 RuntimeR3_SOURCES.linux += r3/linux/sems-linux.cpp 315 ## @todo This causes VBoxGuestR3Lib to end up with the wrong stuff 316 # when building 64-bit linux. This code won't work on 2.4. 317 RuntimeR3_SOURCES.linux += \ 318 r3/linux/semevent-linux.cpp \ 319 r3/linux/semeventmulti-linux.cpp 320 ifdef RT_NEW_LINUX_MUTEX_CODE 321 RuntimeR3_SOURCES.linux += \ 322 r3/linux/semmutex-linux.cpp 323 else 324 RuntimeR3_SOURCES.linux += \ 325 r3/posix/semmutex-posix.cpp 326 endif 315 327 else 316 RuntimeR3_SOURCES.linux += r3/posix/sems-posix.cpp 328 RuntimeR3_SOURCES.linux += \ 329 r3/posix/semevent-posix.cpp \ 330 r3/posix/semeventmulti-posix.cpp \ 331 r3/posix/semmutex-posix.cpp 317 332 endif 318 333 … … 376 391 r3/posix/process-posix.cpp \ 377 392 r3/posix/rand-posix.cpp \ 378 r3/posix/sems-posix.cpp \ 393 r3/posix/semevent-posix.cpp \ 394 r3/posix/semeventmulti-posix.cpp \ 395 r3/posix/semmutex-posix.cpp \ 396 r3/posix/semrw-posix.cpp \ 379 397 r3/posix/system-posix.cpp \ 380 398 r3/posix/thread-posix.cpp \ … … 405 423 r3/posix/rand-posix.cpp \ 406 424 r3/posix/RTTimeNow-posix.cpp \ 407 r3/posix/sems-posix.cpp \ 425 r3/posix/semevent-posix.cpp \ 426 r3/posix/semeventmulti-posix.cpp \ 427 r3/posix/semmutex-posix.cpp \ 428 r3/posix/semrw-posix.cpp \ 408 429 r3/posix/system-posix.cpp \ 409 430 r3/posix/thread-posix.cpp \ … … 434 455 r3/posix/rand-posix.cpp \ 435 456 r3/posix/RTTimeNow-posix.cpp \ 436 r3/posix/sems-posix.cpp \ 457 r3/posix/semevent-posix.cpp \ 458 r3/posix/semeventmulti-posix.cpp \ 459 r3/posix/semmutex-posix.cpp \ 460 r3/posix/semrw-posix.cpp \ 437 461 r3/posix/system-posix.cpp \ 438 462 r3/posix/thread-posix.cpp \ -
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 -
trunk/src/VBox/Runtime/r3/posix/semevent-posix.cpp
r6734 r6738 1 1 /* $Id$ */ 2 2 /** @file 3 * innotek Portable Runtime - Semaphores, POSIX.3 * innotek Portable Runtime - Event Semaphore, POSIX. 4 4 */ 5 5 … … 56 56 * The POSIX implementation uses a mutex and a condition variable to implement 57 57 * the automatic reset event semaphore semantics. 58 *59 * This must be identical to RTSEMEVENTMULTIINTERNAL!60 58 */ 61 59 struct RTSEMEVENTINTERNAL … … 72 70 }; 73 71 74 /** Posix internal representation of a Mutex Multi semaphore. 75 * This must be identical to RTSEMEVENTINTERNAL! */ 76 struct RTSEMEVENTMULTIINTERNAL 77 { 78 /** pthread condition. */ 79 pthread_cond_t Cond; 80 /** pthread mutex which protects the condition and the event state. */ 81 pthread_mutex_t Mutex; 82 /** The state of the semaphore. 83 * This is operated while owning mutex and using atomic updating. */ 84 volatile uint32_t u32State; 85 /** Number of waiters. */ 86 volatile uint32_t cWaiters; 87 }; 88 89 /** The valus of the u32State variable in a RTSEMEVENTINTERNAL and RTSEMEVENTMULTIINTERNAL. 72 /** The valus of the u32State variable in a RTSEMEVENTINTERNAL. 90 73 * @{ */ 91 74 /** The object isn't initialized. */ … … 96 79 #define EVENT_STATE_NOT_SIGNALED 0x00ff00ff 97 80 /** @} */ 98 99 100 /** Posix internal representation of a Mutex semaphore. */101 struct RTSEMMUTEXINTERNAL102 {103 /** pthread mutex. */104 pthread_mutex_t Mutex;105 /** The owner of the mutex. */106 volatile pthread_t Owner;107 /** Nesting count. */108 volatile uint32_t cNesting;109 };110 111 /** Posix internal representation of a read-write semaphore. */112 struct RTSEMRWINTERNAL113 {114 /** pthread rwlock. */115 pthread_rwlock_t RWLock;116 /** Variable to check if initialized.117 * 0 is uninitialized, ~0 is inititialized. */118 volatile unsigned uCheck;119 /** The write owner of the lock. */120 volatile pthread_t WROwner;121 };122 81 123 82 … … 458 417 } 459 418 460 461 462 463 464 465 /**466 * Validate an event multi semaphore handle passed to one of the interface.467 *468 * @returns true if valid.469 * @returns false if invalid.470 * @param pIntEventMultiSem Pointer to the event semaphore to validate.471 */472 inline bool rtsemEventMultiValid(struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem)473 {474 if ((uintptr_t)pIntEventMultiSem < 0x10000)475 return false;476 477 uint32_t u32 = pIntEventMultiSem->u32State; /* this is volatile, so a explicit read like this is needed. */478 if ( u32 != EVENT_STATE_NOT_SIGNALED479 && u32 != EVENT_STATE_SIGNALED)480 return false;481 482 return true;483 }484 485 486 RTDECL(int) RTSemEventMultiCreate(PRTSEMEVENTMULTI pEventMultiSem)487 {488 /* the code and the structure is identical with other type for this function. */489 return RTSemEventCreate((PRTSEMEVENT)pEventMultiSem);490 }491 492 493 RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI EventMultiSem)494 {495 /* the code and the structure is identical with other type for this function. */496 return RTSemEventDestroy((RTSEMEVENT)EventMultiSem);497 }498 499 500 RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI EventMultiSem)501 {502 /* the code and the structure is identical with other type for this function. */503 return RTSemEventSignal((RTSEMEVENT)EventMultiSem);504 }505 506 507 RTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI EventMultiSem)508 {509 /*510 * Validate input.511 */512 if (!rtsemEventMultiValid(EventMultiSem))513 {514 AssertMsgFailed(("Invalid handle %p!\n", EventMultiSem));515 return VERR_INVALID_HANDLE;516 }517 518 /*519 * Lock the mutex semaphore.520 */521 struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem = EventMultiSem;522 int rc = pthread_mutex_lock(&pIntEventMultiSem->Mutex);523 if (rc)524 {525 AssertMsgFailed(("Failed to lock event multi sem %p, rc=%d.\n", EventMultiSem, rc));526 return RTErrConvertFromErrno(rc);527 }528 529 /*530 * Check the state.531 */532 if (pIntEventMultiSem->u32State == EVENT_STATE_SIGNALED)533 ASMAtomicXchgU32(&pIntEventMultiSem->u32State, EVENT_STATE_NOT_SIGNALED);534 else if (pIntEventMultiSem->u32State != EVENT_STATE_NOT_SIGNALED)535 rc = VERR_SEM_DESTROYED;536 537 /*538 * Release the mutex and return.539 */540 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);541 if (rc)542 {543 AssertMsgFailed(("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc));544 return RTErrConvertFromErrno(rc);545 }546 547 return VINF_SUCCESS;548 549 }550 551 552 static int rtSemEventMultiWait(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies, bool fAutoResume)553 {554 /*555 * Validate input.556 */557 if (!rtsemEventMultiValid(EventMultiSem))558 {559 AssertMsgFailed(("Invalid handle %p!\n", EventMultiSem));560 return VERR_INVALID_HANDLE;561 }562 563 /*564 * Timed or indefinite wait?565 */566 struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem = EventMultiSem;567 if (cMillies == RT_INDEFINITE_WAIT)568 {569 /* take mutex */570 int rc = pthread_mutex_lock(&pIntEventMultiSem->Mutex);571 if (rc)572 {573 AssertMsgFailed(("Failed to lock event multi sem %p, rc=%d.\n", EventMultiSem, rc));574 return RTErrConvertFromErrno(rc);575 }576 ASMAtomicIncU32(&pIntEventMultiSem->cWaiters);577 578 for (;;)579 {580 /* check state. */581 if (pIntEventMultiSem->u32State == EVENT_STATE_SIGNALED)582 {583 ASMAtomicDecU32(&pIntEventMultiSem->cWaiters);584 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);585 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc);586 return VINF_SUCCESS;587 }588 if (pIntEventMultiSem->u32State == EVENT_STATE_UNINITIALIZED)589 {590 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);591 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc);592 return VERR_SEM_DESTROYED;593 }594 595 /* wait */596 rc = pthread_cond_wait(&pIntEventMultiSem->Cond, &pIntEventMultiSem->Mutex);597 if (rc)598 {599 AssertMsgFailed(("Failed to wait on event multi sem %p, rc=%d.\n", EventMultiSem, rc));600 ASMAtomicDecU32(&pIntEventMultiSem->cWaiters);601 int rc2 = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);602 AssertMsg(!rc2, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc2)); NOREF(rc2);603 return RTErrConvertFromErrno(rc);604 }605 }606 }607 else608 {609 /*610 * Get current time and calc end of wait time.611 */612 struct timespec ts = {0,0};613 #ifdef RT_OS_DARWIN614 struct timeval tv = {0,0};615 gettimeofday(&tv, NULL);616 ts.tv_sec = tv.tv_sec;617 ts.tv_nsec = tv.tv_usec * 1000;618 #else619 clock_gettime(CLOCK_REALTIME, &ts);620 #endif621 if (cMillies != 0)622 {623 ts.tv_nsec += (cMillies % 1000) * 1000000;624 ts.tv_sec += cMillies / 1000;625 if (ts.tv_nsec >= 1000000000)626 {627 ts.tv_nsec -= 1000000000;628 ts.tv_sec++;629 }630 }631 632 /* take mutex */633 #ifdef RT_OS_DARWIN634 int rc = pthread_mutex_lock(&pIntEventMultiSem->Mutex);635 #else636 int rc = pthread_mutex_timedlock(&pIntEventMultiSem->Mutex, &ts);637 #endif638 if (rc)639 {640 AssertMsg(rc == ETIMEDOUT, ("Failed to lock event multi sem %p, rc=%d.\n", EventMultiSem, rc));641 return RTErrConvertFromErrno(rc);642 }643 ASMAtomicIncU32(&pIntEventMultiSem->cWaiters);644 645 for (;;)646 {647 /* check state. */648 if (pIntEventMultiSem->u32State == EVENT_STATE_SIGNALED)649 {650 ASMAtomicXchgU32(&pIntEventMultiSem->u32State, EVENT_STATE_NOT_SIGNALED);651 ASMAtomicDecU32(&pIntEventMultiSem->cWaiters);652 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);653 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc);654 return VINF_SUCCESS;655 }656 if (pIntEventMultiSem->u32State == EVENT_STATE_UNINITIALIZED)657 {658 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);659 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc);660 return VERR_SEM_DESTROYED;661 }662 663 /* wait */664 rc = pthread_cond_timedwait(&pIntEventMultiSem->Cond, &pIntEventMultiSem->Mutex, &ts);665 if (rc && (rc != EINTR || !fAutoResume)) /* according to SuS this function shall not return EINTR, but linux man page says differently. */666 {667 AssertMsg(rc == ETIMEDOUT, ("Failed to wait on event multi sem %p, rc=%d.\n", EventMultiSem, rc));668 ASMAtomicDecU32(&pIntEventMultiSem->cWaiters);669 int rc2 = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);670 AssertMsg(!rc2, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc2)); NOREF(rc2);671 return RTErrConvertFromErrno(rc);672 }673 }674 }675 }676 677 678 RTDECL(int) RTSemEventMultiWait(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies)679 {680 int rc = rtSemEventMultiWait(EventMultiSem, cMillies, true);681 Assert(rc != VERR_INTERRUPTED);682 return rc;683 }684 685 686 RTDECL(int) RTSemEventMultiWaitNoResume(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies)687 {688 return rtSemEventMultiWait(EventMultiSem, cMillies, false);689 }690 691 692 693 694 695 /**696 * Validate a Mutex semaphore handle passed to one of the interface.697 *698 * @returns true if valid.699 * @returns false if invalid.700 * @param pIntMutexSem Pointer to the mutex semaphore to validate.701 */702 inline bool rtsemMutexValid(struct RTSEMMUTEXINTERNAL *pIntMutexSem)703 {704 if ((uintptr_t)pIntMutexSem < 0x10000)705 return false;706 707 if (pIntMutexSem->cNesting == (uint32_t)~0)708 return false;709 710 return true;711 }712 713 714 RTDECL(int) RTSemMutexCreate(PRTSEMMUTEX pMutexSem)715 {716 int rc;717 718 /*719 * Allocate semaphore handle.720 */721 struct RTSEMMUTEXINTERNAL *pIntMutexSem = (struct RTSEMMUTEXINTERNAL *)RTMemAlloc(sizeof(struct RTSEMMUTEXINTERNAL));722 if (pIntMutexSem)723 {724 /*725 * Create the semaphore.726 */727 pthread_mutexattr_t MutexAttr;728 rc = pthread_mutexattr_init(&MutexAttr);729 if (!rc)730 {731 rc = pthread_mutex_init(&pIntMutexSem->Mutex, &MutexAttr);732 if (!rc)733 {734 pthread_mutexattr_destroy(&MutexAttr);735 736 pIntMutexSem->Owner = (pthread_t)-1;737 pIntMutexSem->cNesting = 0;738 739 *pMutexSem = pIntMutexSem;740 return VINF_SUCCESS;741 }742 pthread_mutexattr_destroy(&MutexAttr);743 }744 RTMemFree(pIntMutexSem);745 }746 else747 rc = VERR_NO_MEMORY;748 749 return rc;750 }751 752 753 RTDECL(int) RTSemMutexDestroy(RTSEMMUTEX MutexSem)754 {755 /*756 * Validate input.757 */758 if (!rtsemMutexValid(MutexSem))759 {760 AssertMsgFailed(("Invalid handle %p!\n", MutexSem));761 return VERR_INVALID_HANDLE;762 }763 764 /*765 * Try destroy it.766 */767 struct RTSEMMUTEXINTERNAL *pIntMutexSem = MutexSem;768 int rc = pthread_mutex_destroy(&pIntMutexSem->Mutex);769 if (rc)770 {771 AssertMsgFailed(("Failed to destroy mutex sem %p, rc=%d.\n", MutexSem, rc));772 return RTErrConvertFromErrno(rc);773 }774 775 /*776 * Free the memory and be gone.777 */778 pIntMutexSem->Owner = (pthread_t)-1;779 pIntMutexSem->cNesting = ~0;780 RTMemTmpFree(pIntMutexSem);781 782 return VINF_SUCCESS;783 }784 785 786 RTDECL(int) RTSemMutexRequest(RTSEMMUTEX MutexSem, unsigned cMillies)787 {788 /*789 * Validate input.790 */791 if (!rtsemMutexValid(MutexSem))792 {793 AssertMsgFailed(("Invalid handle %p!\n", MutexSem));794 return VERR_INVALID_HANDLE;795 }796 797 /*798 * Check if nested request.799 */800 pthread_t Self = pthread_self();801 struct RTSEMMUTEXINTERNAL *pIntMutexSem = MutexSem;802 if ( pIntMutexSem->Owner == Self803 && pIntMutexSem->cNesting > 0)804 {805 pIntMutexSem->cNesting++;806 return VINF_SUCCESS;807 }808 809 /*810 * Lock it.811 */812 if (cMillies == RT_INDEFINITE_WAIT)813 {814 /* take mutex */815 int rc = pthread_mutex_lock(&pIntMutexSem->Mutex);816 if (rc)817 {818 AssertMsgFailed(("Failed to lock mutex sem %p, rc=%d.\n", MutexSem, rc)); NOREF(rc);819 return RTErrConvertFromErrno(rc);820 }821 }822 else823 {824 #ifdef RT_OS_DARWIN825 AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));826 return VERR_NOT_IMPLEMENTED;827 #else /* !RT_OS_DARWIN */828 /*829 * Get current time and calc end of wait time.830 */831 struct timespec ts = {0,0};832 clock_gettime(CLOCK_REALTIME, &ts);833 if (cMillies != 0)834 {835 ts.tv_nsec += (cMillies % 1000) * 1000000;836 ts.tv_sec += cMillies / 1000;837 if (ts.tv_nsec >= 1000000000)838 {839 ts.tv_nsec -= 1000000000;840 ts.tv_sec++;841 }842 }843 844 /* take mutex */845 int rc = pthread_mutex_timedlock(&pIntMutexSem->Mutex, &ts);846 if (rc)847 {848 AssertMsg(rc == ETIMEDOUT, ("Failed to lock mutex sem %p, rc=%d.\n", MutexSem, rc)); NOREF(rc);849 return RTErrConvertFromErrno(rc);850 }851 #endif /* !RT_OS_DARWIN */852 }853 854 /*855 * Set the owner and nesting.856 */857 pIntMutexSem->Owner = Self;858 ASMAtomicXchgU32(&pIntMutexSem->cNesting, 1);859 860 return VINF_SUCCESS;861 }862 863 864 RTDECL(int) RTSemMutexRequestNoResume(RTSEMMUTEX MutexSem, unsigned cMillies)865 {866 /* EINTR isn't returned by the wait functions we're using. */867 return RTSemMutexRequest(MutexSem, cMillies);868 }869 870 871 RTDECL(int) RTSemMutexRelease(RTSEMMUTEX MutexSem)872 {873 /*874 * Validate input.875 */876 if (!rtsemMutexValid(MutexSem))877 {878 AssertMsgFailed(("Invalid handle %p!\n", MutexSem));879 return VERR_INVALID_HANDLE;880 }881 882 /*883 * Check if nested.884 */885 pthread_t Self = pthread_self();886 struct RTSEMMUTEXINTERNAL *pIntMutexSem = MutexSem;887 if ( pIntMutexSem->Owner != Self888 || pIntMutexSem->cNesting == (uint32_t)~0)889 {890 AssertMsgFailed(("Not owner of mutex %p!! Self=%08x Owner=%08x cNesting=%d\n",891 pIntMutexSem, Self, pIntMutexSem->Owner, pIntMutexSem->cNesting));892 return VERR_NOT_OWNER;893 }894 895 /*896 * If nested we'll just pop a nesting.897 */898 if (pIntMutexSem->cNesting > 1)899 {900 pIntMutexSem->cNesting--;901 return VINF_SUCCESS;902 }903 904 /*905 * Clear the state. (cNesting == 1)906 */907 pIntMutexSem->Owner = (pthread_t)-1;908 ASMAtomicXchgU32(&pIntMutexSem->cNesting, 0);909 910 /*911 * Unlock mutex semaphore.912 */913 int rc = pthread_mutex_unlock(&pIntMutexSem->Mutex);914 if (rc)915 {916 AssertMsgFailed(("Failed to unlock mutex sem %p, rc=%d.\n", MutexSem, rc)); NOREF(rc);917 return RTErrConvertFromErrno(rc);918 }919 920 return VINF_SUCCESS;921 }922 923 924 925 926 927 /**928 * Validate a read-write semaphore handle passed to one of the interface.929 *930 * @returns true if valid.931 * @returns false if invalid.932 * @param pIntRWSem Pointer to the read-write semaphore to validate.933 */934 inline bool rtsemRWValid(struct RTSEMRWINTERNAL *pIntRWSem)935 {936 if ((uintptr_t)pIntRWSem < 0x10000)937 return false;938 939 if (pIntRWSem->uCheck != (unsigned)~0)940 return false;941 942 return true;943 }944 945 946 RTDECL(int) RTSemRWCreate(PRTSEMRW pRWSem)947 {948 int rc;949 950 /*951 * Allocate handle.952 */953 struct RTSEMRWINTERNAL *pIntRWSem = (struct RTSEMRWINTERNAL *)RTMemAlloc(sizeof(struct RTSEMRWINTERNAL));954 if (pIntRWSem)955 {956 /*957 * Create the rwlock.958 */959 pthread_rwlockattr_t Attr;960 rc = pthread_rwlockattr_init(&Attr);961 if (!rc)962 {963 rc = pthread_rwlock_init(&pIntRWSem->RWLock, &Attr);964 if (!rc)965 {966 pIntRWSem->uCheck = ~0;967 pIntRWSem->WROwner = (pthread_t)-1;968 *pRWSem = pIntRWSem;969 return VINF_SUCCESS;970 }971 }972 973 rc = RTErrConvertFromErrno(rc);974 RTMemFree(pIntRWSem);975 }976 else977 rc = VERR_NO_MEMORY;978 979 return rc;980 }981 982 983 RTDECL(int) RTSemRWDestroy(RTSEMRW RWSem)984 {985 /*986 * Validate input.987 */988 if (!rtsemRWValid(RWSem))989 {990 AssertMsgFailed(("Invalid handle %p!\n", RWSem));991 return VERR_INVALID_HANDLE;992 }993 994 /*995 * Try destroy it.996 */997 struct RTSEMRWINTERNAL *pIntRWSem = RWSem;998 int rc = pthread_rwlock_destroy(&pIntRWSem->RWLock);999 if (!rc)1000 {1001 pIntRWSem->uCheck = 0;1002 RTMemFree(pIntRWSem);1003 rc = VINF_SUCCESS;1004 }1005 else1006 {1007 AssertMsgFailed(("Failed to destroy read-write sem %p, rc=%d.\n", RWSem, rc));1008 rc = RTErrConvertFromErrno(rc);1009 }1010 1011 return rc;1012 }1013 1014 1015 RTDECL(int) RTSemRWRequestRead(RTSEMRW RWSem, unsigned cMillies)1016 {1017 /*1018 * Validate input.1019 */1020 if (!rtsemRWValid(RWSem))1021 {1022 AssertMsgFailed(("Invalid handle %p!\n", RWSem));1023 return VERR_INVALID_HANDLE;1024 }1025 1026 /*1027 * Try lock it.1028 */1029 struct RTSEMRWINTERNAL *pIntRWSem = RWSem;1030 if (cMillies == RT_INDEFINITE_WAIT)1031 {1032 /* take rwlock */1033 int rc = pthread_rwlock_rdlock(&pIntRWSem->RWLock);1034 if (rc)1035 {1036 AssertMsgFailed(("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));1037 return RTErrConvertFromErrno(rc);1038 }1039 }1040 else1041 {1042 #ifdef RT_OS_DARWIN1043 AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));1044 return VERR_NOT_IMPLEMENTED;1045 #else /* !RT_OS_DARWIN */1046 /*1047 * Get current time and calc end of wait time.1048 */1049 struct timespec ts = {0,0};1050 clock_gettime(CLOCK_REALTIME, &ts);1051 if (cMillies != 0)1052 {1053 ts.tv_nsec += (cMillies % 1000) * 1000000;1054 ts.tv_sec += cMillies / 1000;1055 if (ts.tv_nsec >= 1000000000)1056 {1057 ts.tv_nsec -= 1000000000;1058 ts.tv_sec++;1059 }1060 }1061 1062 /* take rwlock */1063 int rc = pthread_rwlock_timedrdlock(&pIntRWSem->RWLock, &ts);1064 if (rc)1065 {1066 AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));1067 return RTErrConvertFromErrno(rc);1068 }1069 #endif /* !RT_OS_DARWIN */1070 }1071 1072 return VINF_SUCCESS;1073 }1074 1075 1076 RTDECL(int) RTSemRWRequestReadNoResume(RTSEMRW RWSem, unsigned cMillies)1077 {1078 /* EINTR isn't returned by the wait functions we're using. */1079 return RTSemRWRequestRead(RWSem, cMillies);1080 }1081 1082 1083 RTDECL(int) RTSemRWReleaseRead(RTSEMRW RWSem)1084 {1085 /*1086 * Validate input.1087 */1088 if (!rtsemRWValid(RWSem))1089 {1090 AssertMsgFailed(("Invalid handle %p!\n", RWSem));1091 return VERR_INVALID_HANDLE;1092 }1093 1094 /*1095 * Try unlock it.1096 */1097 struct RTSEMRWINTERNAL *pIntRWSem = RWSem;1098 if (pIntRWSem->WROwner == pthread_self())1099 {1100 AssertMsgFailed(("Tried to read unlock when write owner - read-write sem %p.\n", RWSem));1101 return VERR_NOT_OWNER;1102 }1103 int rc = pthread_rwlock_unlock(&pIntRWSem->RWLock);1104 if (rc)1105 {1106 AssertMsgFailed(("Failed read unlock read-write sem %p, rc=%d.\n", RWSem, rc));1107 return RTErrConvertFromErrno(rc);1108 }1109 1110 return VINF_SUCCESS;1111 }1112 1113 1114 RTDECL(int) RTSemRWRequestWrite(RTSEMRW RWSem, unsigned cMillies)1115 {1116 /*1117 * Validate input.1118 */1119 if (!rtsemRWValid(RWSem))1120 {1121 AssertMsgFailed(("Invalid handle %p!\n", RWSem));1122 return VERR_INVALID_HANDLE;1123 }1124 1125 /*1126 * Try lock it.1127 */1128 struct RTSEMRWINTERNAL *pIntRWSem = RWSem;1129 if (cMillies == RT_INDEFINITE_WAIT)1130 {1131 /* take rwlock */1132 int rc = pthread_rwlock_wrlock(&pIntRWSem->RWLock);1133 if (rc)1134 {1135 AssertMsgFailed(("Failed write lock read-write sem %p, rc=%d.\n", RWSem, rc));1136 return RTErrConvertFromErrno(rc);1137 }1138 }1139 else1140 {1141 #ifdef RT_OS_DARWIN1142 AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));1143 return VERR_NOT_IMPLEMENTED;1144 #else /* !RT_OS_DARWIN */1145 /*1146 * Get current time and calc end of wait time.1147 */1148 struct timespec ts = {0,0};1149 clock_gettime(CLOCK_REALTIME, &ts);1150 if (cMillies != 0)1151 {1152 ts.tv_nsec += (cMillies % 1000) * 1000000;1153 ts.tv_sec += cMillies / 1000;1154 if (ts.tv_nsec >= 1000000000)1155 {1156 ts.tv_nsec -= 1000000000;1157 ts.tv_sec++;1158 }1159 }1160 1161 /* take rwlock */1162 int rc = pthread_rwlock_timedwrlock(&pIntRWSem->RWLock, &ts);1163 if (rc)1164 {1165 AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));1166 return RTErrConvertFromErrno(rc);1167 }1168 #endif /* !RT_OS_DARWIN */1169 }1170 1171 #ifdef RT_OS_SOLARIS1172 ASMAtomicXchgSize(&pIntRWSem->WROwner, pthread_self());1173 #else1174 ASMAtomicXchgPtr((void * volatile *)&pIntRWSem->WROwner, (void *)pthread_self());1175 #endif1176 1177 return VINF_SUCCESS;1178 }1179 1180 1181 RTDECL(int) RTSemRWRequestWriteNoResume(RTSEMRW RWSem, unsigned cMillies)1182 {1183 /* EINTR isn't returned by the wait functions we're using. */1184 return RTSemRWRequestWrite(RWSem, cMillies);1185 }1186 1187 1188 RTDECL(int) RTSemRWReleaseWrite(RTSEMRW RWSem)1189 {1190 /*1191 * Validate input.1192 */1193 if (!rtsemRWValid(RWSem))1194 {1195 AssertMsgFailed(("Invalid handle %p!\n", RWSem));1196 return VERR_INVALID_HANDLE;1197 }1198 1199 /*1200 * Try unlock it.1201 */1202 pthread_t Self = pthread_self();1203 struct RTSEMRWINTERNAL *pIntRWSem = RWSem;1204 if (pIntRWSem->WROwner != Self)1205 {1206 AssertMsgFailed(("Not Write owner!\n"));1207 return VERR_NOT_OWNER;1208 }1209 1210 /*1211 * Try unlock it.1212 */1213 #ifdef RT_OS_SOLARIS1214 ASMAtomicXchgSize(&pIntRWSem->WROwner, (pthread_t)-1);1215 #else1216 AssertMsg(sizeof(pthread_t) == sizeof(void *), ("pthread_t is not the size of a pointer but %d bytes\n", sizeof(pthread_t)));1217 ASMAtomicXchgPtr((void * volatile *)&pIntRWSem->WROwner, (void *)(pthread_t)-1);1218 #endif1219 int rc = pthread_rwlock_unlock(&pIntRWSem->RWLock);1220 if (rc)1221 {1222 AssertMsgFailed(("Failed write unlock read-write sem %p, rc=%d.\n", RWSem, rc));1223 return RTErrConvertFromErrno(rc);1224 }1225 1226 return VINF_SUCCESS;1227 }1228 -
trunk/src/VBox/Runtime/r3/posix/semeventmulti-posix.cpp
r6734 r6738 1 1 /* $Id$ */ 2 2 /** @file 3 * innotek Portable Runtime - Semaphores, POSIX.3 * innotek Portable Runtime - Multiple Release Event Semaphore, POSIX. 4 4 */ 5 5 … … 39 39 #include <sys/time.h> 40 40 41 #ifdef RT_OS_DARWIN42 # define pthread_yield() pthread_yield_np()43 #endif44 45 #ifdef RT_OS_SOLARIS46 # include <sched.h>47 # define pthread_yield() sched_yield()48 #endif49 50 41 51 42 /******************************************************************************* 52 43 * Structures and Typedefs * 53 44 *******************************************************************************/ 54 55 /** Internal representation of the POSIX implementation of an Event semaphore. 45 /** Posix internal representation of a Mutex Multi semaphore. 56 46 * The POSIX implementation uses a mutex and a condition variable to implement 57 * the automatic reset event semaphore semantics. 58 * 59 * This must be identical to RTSEMEVENTMULTIINTERNAL! 60 */ 61 struct RTSEMEVENTINTERNAL 47 * the automatic reset event semaphore semantics. */ 48 struct RTSEMEVENTMULTIINTERNAL 62 49 { 63 50 /** pthread condition. */ … … 72 59 }; 73 60 74 /** Posix internal representation of a Mutex Multi semaphore. 75 * This must be identical to RTSEMEVENTINTERNAL! */ 76 struct RTSEMEVENTMULTIINTERNAL 77 { 78 /** pthread condition. */ 79 pthread_cond_t Cond; 80 /** pthread mutex which protects the condition and the event state. */ 81 pthread_mutex_t Mutex; 82 /** The state of the semaphore. 83 * This is operated while owning mutex and using atomic updating. */ 84 volatile uint32_t u32State; 85 /** Number of waiters. */ 86 volatile uint32_t cWaiters; 87 }; 88 89 /** The valus of the u32State variable in a RTSEMEVENTINTERNAL and RTSEMEVENTMULTIINTERNAL. 61 /** The valus of the u32State variable in RTSEMEVENTMULTIINTERNAL. 90 62 * @{ */ 91 63 /** The object isn't initialized. */ 92 #define EVENT _STATE_UNINITIALIZED 064 #define EVENTMULTI_STATE_UNINITIALIZED 0 93 65 /** The semaphore is is signaled. */ 94 #define EVENT _STATE_SIGNALED 0xff00ff0066 #define EVENTMULTI_STATE_SIGNALED 0xff00ff00 95 67 /** The semaphore is not signaled. */ 96 #define EVENT _STATE_NOT_SIGNALED 0x00ff00ff68 #define EVENTMULTI_STATE_NOT_SIGNALED 0x00ff00ff 97 69 /** @} */ 98 70 99 71 100 /** Posix internal representation of a Mutex semaphore. */101 struct RTSEMMUTEXINTERNAL102 {103 /** pthread mutex. */104 pthread_mutex_t Mutex;105 /** The owner of the mutex. */106 volatile pthread_t Owner;107 /** Nesting count. */108 volatile uint32_t cNesting;109 };110 111 /** Posix internal representation of a read-write semaphore. */112 struct RTSEMRWINTERNAL113 {114 /** pthread rwlock. */115 pthread_rwlock_t RWLock;116 /** Variable to check if initialized.117 * 0 is uninitialized, ~0 is inititialized. */118 volatile unsigned uCheck;119 /** The write owner of the lock. */120 volatile pthread_t WROwner;121 };122 123 72 124 73 /** 125 * Validate an Eventsemaphore handle passed to one of the interface.74 * Validate an event multi semaphore handle passed to one of the interface. 126 75 * 127 76 * @returns true if valid. 128 77 * @returns false if invalid. 129 * @param p IntEventSemPointer to the event semaphore to validate.78 * @param pThis Pointer to the event semaphore to validate. 130 79 */ 131 inline bool rtsemEvent Valid(struct RTSEMEVENTINTERNAL *pIntEventSem)132 { 133 if ((uintptr_t)p IntEventSem< 0x10000)80 inline bool rtsemEventMultiValid(struct RTSEMEVENTMULTIINTERNAL *pThis) 81 { 82 if ((uintptr_t)pThis < 0x10000) 134 83 return false; 135 84 136 uint32_t u32 = p IntEventSem->u32State; /* this is volatile, so a explicit read like this is needed. */137 if ( u32 != EVENT _STATE_NOT_SIGNALED138 && u32 != EVENT _STATE_SIGNALED)85 uint32_t u32 = pThis->u32State; /* this is volatile, so a explicit read like this is needed. */ 86 if ( u32 != EVENTMULTI_STATE_NOT_SIGNALED 87 && u32 != EVENTMULTI_STATE_SIGNALED) 139 88 return false; 140 89 … … 143 92 144 93 145 RTDECL(int) RTSemEvent Create(PRTSEMEVENT pEventSem)94 RTDECL(int) RTSemEventMultiCreate(PRTSEMEVENTMULTI pEventMultiSem) 146 95 { 147 96 int rc; … … 150 99 * Allocate semaphore handle. 151 100 */ 152 struct RTSEMEVENT INTERNAL *pIntEventSem = (struct RTSEMEVENTINTERNAL *)RTMemAlloc(sizeof(struct RTSEMEVENTINTERNAL));153 if (p IntEventSem)101 struct RTSEMEVENTMULTIINTERNAL *pThis = (struct RTSEMEVENTMULTIINTERNAL *)RTMemAlloc(sizeof(struct RTSEMEVENTMULTIINTERNAL)); 102 if (pThis) 154 103 { 155 104 /* … … 160 109 if (!rc) 161 110 { 162 rc = pthread_cond_init(&p IntEventSem->Cond, &CondAttr);111 rc = pthread_cond_init(&pThis->Cond, &CondAttr); 163 112 if (!rc) 164 113 { … … 170 119 if (!rc) 171 120 { 172 rc = pthread_mutex_init(&p IntEventSem->Mutex, &MutexAttr);121 rc = pthread_mutex_init(&pThis->Mutex, &MutexAttr); 173 122 if (!rc) 174 123 { … … 176 125 pthread_condattr_destroy(&CondAttr); 177 126 178 ASMAtomicXchgU32(&p IntEventSem->u32State, EVENT_STATE_NOT_SIGNALED);179 ASMAtomicXchgU32(&p IntEventSem->cWaiters, 0);180 181 *pEvent Sem = pIntEventSem;127 ASMAtomicXchgU32(&pThis->u32State, EVENTMULTI_STATE_NOT_SIGNALED); 128 ASMAtomicXchgU32(&pThis->cWaiters, 0); 129 130 *pEventMultiSem = pThis; 182 131 return VINF_SUCCESS; 183 132 } 133 184 134 pthread_mutexattr_destroy(&MutexAttr); 185 135 } 186 pthread_cond_destroy(&p IntEventSem->Cond);136 pthread_cond_destroy(&pThis->Cond); 187 137 } 188 138 pthread_condattr_destroy(&CondAttr); … … 190 140 191 141 rc = RTErrConvertFromErrno(rc); 192 RTMemFree(p IntEventSem);142 RTMemFree(pThis); 193 143 } 194 144 else … … 196 146 197 147 return rc; 198 } 199 200 201 RTDECL(int) RTSemEventDestroy(RTSEMEVENT EventSem) 148 149 } 150 151 152 RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI EventMultiSem) 202 153 { 203 154 /* 204 155 * Validate handle. 205 156 */ 206 if (!rtsemEvent Valid(EventSem))207 { 208 AssertMsgFailed(("Invalid handle %p!\n", Event Sem));157 if (!rtsemEventMultiValid(EventMultiSem)) 158 { 159 AssertMsgFailed(("Invalid handle %p!\n", EventMultiSem)); 209 160 return VERR_INVALID_HANDLE; 210 161 } … … 212 163 /* 213 164 * Abort all waiters forcing them to return failure. 214 * 215 */ 216 struct RTSEMEVENTINTERNAL *pIntEventSem = EventSem; 165 */ 166 struct RTSEMEVENTMULTIINTERNAL *pThis = EventMultiSem; 217 167 int rc; 218 168 for (int i = 30; i > 0; i--) 219 169 { 220 ASMAtomicXchgU32(&p IntEventSem->u32State, EVENT_STATE_UNINITIALIZED);221 rc = pthread_cond_destroy(&p IntEventSem->Cond);170 ASMAtomicXchgU32(&pThis->u32State, EVENTMULTI_STATE_UNINITIALIZED); 171 rc = pthread_cond_destroy(&pThis->Cond); 222 172 if (rc != EBUSY) 223 173 break; 224 pthread_cond_broadcast(&p IntEventSem->Cond);174 pthread_cond_broadcast(&pThis->Cond); 225 175 usleep(1000); 226 176 } while (rc == EBUSY); 227 177 if (rc) 228 178 { 229 AssertMsgFailed(("Failed to destroy event sem %p, rc=%d.\n", Event Sem, rc));179 AssertMsgFailed(("Failed to destroy event sem %p, rc=%d.\n", EventMultiSem, rc)); 230 180 return RTErrConvertFromErrno(rc); 231 181 } … … 237 187 for (int i = 30; i > 0; i--) 238 188 { 239 rc = pthread_mutex_destroy(&p IntEventSem->Mutex);189 rc = pthread_mutex_destroy(&pThis->Mutex); 240 190 if (rc != EBUSY) 241 191 break; … … 244 194 if (rc) 245 195 { 246 AssertMsgFailed(("Failed to destroy event sem %p, rc=%d. (mutex)\n", Event Sem, rc));196 AssertMsgFailed(("Failed to destroy event sem %p, rc=%d. (mutex)\n", EventMultiSem, rc)); 247 197 return RTErrConvertFromErrno(rc); 248 198 } … … 251 201 * Free the semaphore memory and be gone. 252 202 */ 253 RTMemFree(p IntEventSem);203 RTMemFree(pThis); 254 204 return VINF_SUCCESS; 255 205 } 256 206 257 207 258 RTDECL(int) RTSemEvent Signal(RTSEMEVENT EventSem)208 RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI EventMultiSem) 259 209 { 260 210 /* 261 211 * Validate input. 262 212 */ 263 if (!rtsemEvent Valid(EventSem))264 { 265 AssertMsgFailed(("Invalid handle %p!\n", Event Sem));213 if (!rtsemEventMultiValid(EventMultiSem)) 214 { 215 AssertMsgFailed(("Invalid handle %p!\n", EventMultiSem)); 266 216 return VERR_INVALID_HANDLE; 267 217 } … … 270 220 * Lock the mutex semaphore. 271 221 */ 272 struct RTSEMEVENT INTERNAL *pIntEventSem = EventSem;273 int rc = pthread_mutex_lock(&p IntEventSem->Mutex);274 if (rc) 275 { 276 AssertMsgFailed(("Failed to lock event sem %p, rc=%d.\n", Event Sem, rc));222 struct RTSEMEVENTMULTIINTERNAL *pThis = EventMultiSem; 223 int rc = pthread_mutex_lock(&pThis->Mutex); 224 if (rc) 225 { 226 AssertMsgFailed(("Failed to lock event sem %p, rc=%d.\n", EventMultiSem, rc)); 277 227 return RTErrConvertFromErrno(rc); 278 228 } … … 281 231 * Check the state. 282 232 */ 283 if (p IntEventSem->u32State == EVENT_STATE_NOT_SIGNALED)284 { 285 ASMAtomicXchgU32(&p IntEventSem->u32State, EVENT_STATE_SIGNALED);286 rc = pthread_cond_signal(&p IntEventSem->Cond);287 AssertMsg(!rc, ("Failed to signal event sem %p, rc=%d.\n", Event Sem, rc));288 } 289 else if (p IntEventSem->u32State == EVENT_STATE_SIGNALED)290 { 291 rc = pthread_cond_signal(&p IntEventSem->Cond); /* give'm another kick... */292 AssertMsg(!rc, ("Failed to signal event sem %p, rc=%d. (2)\n", Event Sem, rc));233 if (pThis->u32State == EVENTMULTI_STATE_NOT_SIGNALED) 234 { 235 ASMAtomicXchgU32(&pThis->u32State, EVENTMULTI_STATE_SIGNALED); 236 rc = pthread_cond_signal(&pThis->Cond); 237 AssertMsg(!rc, ("Failed to signal event sem %p, rc=%d.\n", EventMultiSem, rc)); 238 } 239 else if (pThis->u32State == EVENTMULTI_STATE_SIGNALED) 240 { 241 rc = pthread_cond_signal(&pThis->Cond); /* give'm another kick... */ 242 AssertMsg(!rc, ("Failed to signal event sem %p, rc=%d. (2)\n", EventMultiSem, rc)); 293 243 } 294 244 else … … 298 248 * Release the mutex and return. 299 249 */ 300 int rc2 = pthread_mutex_unlock(&p IntEventSem->Mutex);301 AssertMsg(!rc2, ("Failed to unlock event sem %p, rc=%d.\n", Event Sem, rc));250 int rc2 = pthread_mutex_unlock(&pThis->Mutex); 251 AssertMsg(!rc2, ("Failed to unlock event sem %p, rc=%d.\n", EventMultiSem, rc)); 302 252 if (rc) 303 253 return RTErrConvertFromErrno(rc); … … 309 259 310 260 311 static int rtSemEventWait(RTSEMEVENT EventSem, unsigned cMillies, bool fAutoResume)261 RTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI EventMultiSem) 312 262 { 313 263 /* 314 264 * Validate input. 315 265 */ 316 if (!rtsemEvent Valid(EventSem))317 { 318 AssertMsgFailed(("Invalid handle %p!\n", Event Sem));266 if (!rtsemEventMultiValid(EventMultiSem)) 267 { 268 AssertMsgFailed(("Invalid handle %p!\n", EventMultiSem)); 319 269 return VERR_INVALID_HANDLE; 320 270 } 321 271 322 272 /* 273 * Lock the mutex semaphore. 274 */ 275 struct RTSEMEVENTMULTIINTERNAL *pThis = EventMultiSem; 276 int rc = pthread_mutex_lock(&pThis->Mutex); 277 if (rc) 278 { 279 AssertMsgFailed(("Failed to lock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); 280 return RTErrConvertFromErrno(rc); 281 } 282 283 /* 284 * Check the state. 285 */ 286 if (pThis->u32State == EVENTMULTI_STATE_SIGNALED) 287 ASMAtomicXchgU32(&pThis->u32State, EVENTMULTI_STATE_NOT_SIGNALED); 288 else if (pThis->u32State != EVENTMULTI_STATE_NOT_SIGNALED) 289 rc = VERR_SEM_DESTROYED; 290 291 /* 292 * Release the mutex and return. 293 */ 294 rc = pthread_mutex_unlock(&pThis->Mutex); 295 if (rc) 296 { 297 AssertMsgFailed(("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); 298 return RTErrConvertFromErrno(rc); 299 } 300 301 return VINF_SUCCESS; 302 303 } 304 305 306 static int rtSemEventMultiWait(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies, bool fAutoResume) 307 { 308 /* 309 * Validate input. 310 */ 311 if (!rtsemEventMultiValid(EventMultiSem)) 312 { 313 AssertMsgFailed(("Invalid handle %p!\n", EventMultiSem)); 314 return VERR_INVALID_HANDLE; 315 } 316 317 /* 323 318 * Timed or indefinite wait? 324 319 */ 325 struct RTSEMEVENT INTERNAL *pIntEventSem = EventSem;320 struct RTSEMEVENTMULTIINTERNAL *pThis = EventMultiSem; 326 321 if (cMillies == RT_INDEFINITE_WAIT) 327 322 { 328 /* for fairness, yield before going to sleep. */ 329 if ( ASMAtomicIncU32(&pIntEventSem->cWaiters) > 1 330 && pIntEventSem->u32State == EVENT_STATE_SIGNALED) 331 pthread_yield(); 332 333 /* take mutex */ 334 int rc = pthread_mutex_lock(&pIntEventSem->Mutex); 323 /* take mutex */ 324 int rc = pthread_mutex_lock(&pThis->Mutex); 335 325 if (rc) 336 326 { 337 ASMAtomicDecU32(&pIntEventSem->cWaiters); 338 AssertMsgFailed(("Failed to lock event sem %p, rc=%d.\n", EventSem, rc)); 327 AssertMsgFailed(("Failed to lock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); 339 328 return RTErrConvertFromErrno(rc); 340 329 } 330 ASMAtomicIncU32(&pThis->cWaiters); 341 331 342 332 for (;;) 343 333 { 344 334 /* check state. */ 345 if (pIntEventSem->u32State == EVENT_STATE_SIGNALED) 346 { 347 ASMAtomicXchgU32(&pIntEventSem->u32State, EVENT_STATE_NOT_SIGNALED); 348 ASMAtomicDecU32(&pIntEventSem->cWaiters); 349 rc = pthread_mutex_unlock(&pIntEventSem->Mutex); 350 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc)); NOREF(rc); 335 if (pThis->u32State == EVENTMULTI_STATE_SIGNALED) 336 { 337 ASMAtomicDecU32(&pThis->cWaiters); 338 rc = pthread_mutex_unlock(&pThis->Mutex); 339 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc); 351 340 return VINF_SUCCESS; 352 341 } 353 if (p IntEventSem->u32State == EVENT_STATE_UNINITIALIZED)354 { 355 rc = pthread_mutex_unlock(&p IntEventSem->Mutex);356 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc)); NOREF(rc);342 if (pThis->u32State == EVENTMULTI_STATE_UNINITIALIZED) 343 { 344 rc = pthread_mutex_unlock(&pThis->Mutex); 345 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc); 357 346 return VERR_SEM_DESTROYED; 358 347 } 359 348 360 349 /* wait */ 361 rc = pthread_cond_wait(&p IntEventSem->Cond, &pIntEventSem->Mutex);350 rc = pthread_cond_wait(&pThis->Cond, &pThis->Mutex); 362 351 if (rc) 363 352 { 364 AssertMsgFailed(("Failed to wait on event sem %p, rc=%d.\n", EventSem, rc));365 ASMAtomicDecU32(&p IntEventSem->cWaiters);366 int rc2 = pthread_mutex_unlock(&p IntEventSem->Mutex);367 AssertMsg(!rc2, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc2)); NOREF(rc2);353 AssertMsgFailed(("Failed to wait on event multi sem %p, rc=%d.\n", EventMultiSem, rc)); 354 ASMAtomicDecU32(&pThis->cWaiters); 355 int rc2 = pthread_mutex_unlock(&pThis->Mutex); 356 AssertMsg(!rc2, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc2)); NOREF(rc2); 368 357 return RTErrConvertFromErrno(rc); 369 358 } … … 395 384 } 396 385 397 /* for fairness, yield before going to sleep. */398 if (ASMAtomicIncU32(&pIntEventSem->cWaiters) > 1)399 pthread_yield();400 401 386 /* take mutex */ 402 387 #ifdef RT_OS_DARWIN 403 int rc = pthread_mutex_lock(&p IntEventSem->Mutex);388 int rc = pthread_mutex_lock(&pThis->Mutex); 404 389 #else 405 int rc = pthread_mutex_timedlock(&p IntEventSem->Mutex, &ts);390 int rc = pthread_mutex_timedlock(&pThis->Mutex, &ts); 406 391 #endif 407 392 if (rc) 408 393 { 409 ASMAtomicDecU32(&pIntEventSem->cWaiters); 410 AssertMsg(rc == ETIMEDOUT, ("Failed to lock event sem %p, rc=%d.\n", EventSem, rc)); 394 AssertMsg(rc == ETIMEDOUT, ("Failed to lock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); 411 395 return RTErrConvertFromErrno(rc); 412 396 } 397 ASMAtomicIncU32(&pThis->cWaiters); 413 398 414 399 for (;;) 415 400 { 416 401 /* check state. */ 417 if (pIntEventSem->u32State == EVENT_STATE_SIGNALED) 418 { 419 ASMAtomicXchgU32(&pIntEventSem->u32State, EVENT_STATE_NOT_SIGNALED); 420 ASMAtomicDecU32(&pIntEventSem->cWaiters); 421 rc = pthread_mutex_unlock(&pIntEventSem->Mutex); 422 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc)); NOREF(rc); 423 return VINF_SUCCESS; 424 } 425 if (pIntEventSem->u32State == EVENT_STATE_UNINITIALIZED) 426 { 427 rc = pthread_mutex_unlock(&pIntEventSem->Mutex); 428 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc)); NOREF(rc); 429 return VERR_SEM_DESTROYED; 430 } 431 432 /* wait */ 433 rc = pthread_cond_timedwait(&pIntEventSem->Cond, &pIntEventSem->Mutex, &ts); 434 if (rc && (rc != EINTR || !fAutoResume)) /* according to SuS this function shall not return EINTR, but linux man page says differently. */ 435 { 436 AssertMsg(rc == ETIMEDOUT, ("Failed to wait on event sem %p, rc=%d.\n", EventSem, rc)); 437 ASMAtomicDecU32(&pIntEventSem->cWaiters); 438 int rc2 = pthread_mutex_unlock(&pIntEventSem->Mutex); 439 AssertMsg(!rc2, ("Failed to unlock event sem %p, rc2=%d.\n", EventSem, rc2)); NOREF(rc2); 440 return RTErrConvertFromErrno(rc); 441 } 442 } /* for (;;) */ 443 } 444 } 445 446 447 RTDECL(int) RTSemEventWait(RTSEMEVENT EventSem, unsigned cMillies) 448 { 449 int rc = rtSemEventWait(EventSem, cMillies, true); 450 Assert(rc != VERR_INTERRUPTED); 451 return rc; 452 } 453 454 455 RTDECL(int) RTSemEventWaitNoResume(RTSEMEVENT EventSem, unsigned cMillies) 456 { 457 return rtSemEventWait(EventSem, cMillies, false); 458 } 459 460 461 462 463 464 465 /** 466 * Validate an event multi semaphore handle passed to one of the interface. 467 * 468 * @returns true if valid. 469 * @returns false if invalid. 470 * @param pIntEventMultiSem Pointer to the event semaphore to validate. 471 */ 472 inline bool rtsemEventMultiValid(struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem) 473 { 474 if ((uintptr_t)pIntEventMultiSem < 0x10000) 475 return false; 476 477 uint32_t u32 = pIntEventMultiSem->u32State; /* this is volatile, so a explicit read like this is needed. */ 478 if ( u32 != EVENT_STATE_NOT_SIGNALED 479 && u32 != EVENT_STATE_SIGNALED) 480 return false; 481 482 return true; 483 } 484 485 486 RTDECL(int) RTSemEventMultiCreate(PRTSEMEVENTMULTI pEventMultiSem) 487 { 488 /* the code and the structure is identical with other type for this function. */ 489 return RTSemEventCreate((PRTSEMEVENT)pEventMultiSem); 490 } 491 492 493 RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI EventMultiSem) 494 { 495 /* the code and the structure is identical with other type for this function. */ 496 return RTSemEventDestroy((RTSEMEVENT)EventMultiSem); 497 } 498 499 500 RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI EventMultiSem) 501 { 502 /* the code and the structure is identical with other type for this function. */ 503 return RTSemEventSignal((RTSEMEVENT)EventMultiSem); 504 } 505 506 507 RTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI EventMultiSem) 508 { 509 /* 510 * Validate input. 511 */ 512 if (!rtsemEventMultiValid(EventMultiSem)) 513 { 514 AssertMsgFailed(("Invalid handle %p!\n", EventMultiSem)); 515 return VERR_INVALID_HANDLE; 516 } 517 518 /* 519 * Lock the mutex semaphore. 520 */ 521 struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem = EventMultiSem; 522 int rc = pthread_mutex_lock(&pIntEventMultiSem->Mutex); 523 if (rc) 524 { 525 AssertMsgFailed(("Failed to lock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); 526 return RTErrConvertFromErrno(rc); 527 } 528 529 /* 530 * Check the state. 531 */ 532 if (pIntEventMultiSem->u32State == EVENT_STATE_SIGNALED) 533 ASMAtomicXchgU32(&pIntEventMultiSem->u32State, EVENT_STATE_NOT_SIGNALED); 534 else if (pIntEventMultiSem->u32State != EVENT_STATE_NOT_SIGNALED) 535 rc = VERR_SEM_DESTROYED; 536 537 /* 538 * Release the mutex and return. 539 */ 540 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex); 541 if (rc) 542 { 543 AssertMsgFailed(("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); 544 return RTErrConvertFromErrno(rc); 545 } 546 547 return VINF_SUCCESS; 548 549 } 550 551 552 static int rtSemEventMultiWait(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies, bool fAutoResume) 553 { 554 /* 555 * Validate input. 556 */ 557 if (!rtsemEventMultiValid(EventMultiSem)) 558 { 559 AssertMsgFailed(("Invalid handle %p!\n", EventMultiSem)); 560 return VERR_INVALID_HANDLE; 561 } 562 563 /* 564 * Timed or indefinite wait? 565 */ 566 struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem = EventMultiSem; 567 if (cMillies == RT_INDEFINITE_WAIT) 568 { 569 /* take mutex */ 570 int rc = pthread_mutex_lock(&pIntEventMultiSem->Mutex); 571 if (rc) 572 { 573 AssertMsgFailed(("Failed to lock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); 574 return RTErrConvertFromErrno(rc); 575 } 576 ASMAtomicIncU32(&pIntEventMultiSem->cWaiters); 577 578 for (;;) 579 { 580 /* check state. */ 581 if (pIntEventMultiSem->u32State == EVENT_STATE_SIGNALED) 582 { 583 ASMAtomicDecU32(&pIntEventMultiSem->cWaiters); 584 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex); 402 if (pThis->u32State == EVENTMULTI_STATE_SIGNALED) 403 { 404 ASMAtomicXchgU32(&pThis->u32State, EVENTMULTI_STATE_NOT_SIGNALED); 405 ASMAtomicDecU32(&pThis->cWaiters); 406 rc = pthread_mutex_unlock(&pThis->Mutex); 585 407 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc); 586 408 return VINF_SUCCESS; 587 409 } 588 if (p IntEventMultiSem->u32State == EVENT_STATE_UNINITIALIZED)589 { 590 rc = pthread_mutex_unlock(&p IntEventMultiSem->Mutex);410 if (pThis->u32State == EVENTMULTI_STATE_UNINITIALIZED) 411 { 412 rc = pthread_mutex_unlock(&pThis->Mutex); 591 413 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc); 592 414 return VERR_SEM_DESTROYED; … … 594 416 595 417 /* wait */ 596 rc = pthread_cond_wait(&pIntEventMultiSem->Cond, &pIntEventMultiSem->Mutex); 597 if (rc) 598 { 599 AssertMsgFailed(("Failed to wait on event multi sem %p, rc=%d.\n", EventMultiSem, rc)); 600 ASMAtomicDecU32(&pIntEventMultiSem->cWaiters); 601 int rc2 = pthread_mutex_unlock(&pIntEventMultiSem->Mutex); 602 AssertMsg(!rc2, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc2)); NOREF(rc2); 603 return RTErrConvertFromErrno(rc); 604 } 605 } 606 } 607 else 608 { 609 /* 610 * Get current time and calc end of wait time. 611 */ 612 struct timespec ts = {0,0}; 613 #ifdef RT_OS_DARWIN 614 struct timeval tv = {0,0}; 615 gettimeofday(&tv, NULL); 616 ts.tv_sec = tv.tv_sec; 617 ts.tv_nsec = tv.tv_usec * 1000; 618 #else 619 clock_gettime(CLOCK_REALTIME, &ts); 620 #endif 621 if (cMillies != 0) 622 { 623 ts.tv_nsec += (cMillies % 1000) * 1000000; 624 ts.tv_sec += cMillies / 1000; 625 if (ts.tv_nsec >= 1000000000) 626 { 627 ts.tv_nsec -= 1000000000; 628 ts.tv_sec++; 629 } 630 } 631 632 /* take mutex */ 633 #ifdef RT_OS_DARWIN 634 int rc = pthread_mutex_lock(&pIntEventMultiSem->Mutex); 635 #else 636 int rc = pthread_mutex_timedlock(&pIntEventMultiSem->Mutex, &ts); 637 #endif 638 if (rc) 639 { 640 AssertMsg(rc == ETIMEDOUT, ("Failed to lock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); 641 return RTErrConvertFromErrno(rc); 642 } 643 ASMAtomicIncU32(&pIntEventMultiSem->cWaiters); 644 645 for (;;) 646 { 647 /* check state. */ 648 if (pIntEventMultiSem->u32State == EVENT_STATE_SIGNALED) 649 { 650 ASMAtomicXchgU32(&pIntEventMultiSem->u32State, EVENT_STATE_NOT_SIGNALED); 651 ASMAtomicDecU32(&pIntEventMultiSem->cWaiters); 652 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex); 653 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc); 654 return VINF_SUCCESS; 655 } 656 if (pIntEventMultiSem->u32State == EVENT_STATE_UNINITIALIZED) 657 { 658 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex); 659 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc); 660 return VERR_SEM_DESTROYED; 661 } 662 663 /* wait */ 664 rc = pthread_cond_timedwait(&pIntEventMultiSem->Cond, &pIntEventMultiSem->Mutex, &ts); 418 rc = pthread_cond_timedwait(&pThis->Cond, &pThis->Mutex, &ts); 665 419 if (rc && (rc != EINTR || !fAutoResume)) /* according to SuS this function shall not return EINTR, but linux man page says differently. */ 666 420 { 667 421 AssertMsg(rc == ETIMEDOUT, ("Failed to wait on event multi sem %p, rc=%d.\n", EventMultiSem, rc)); 668 ASMAtomicDecU32(&p IntEventMultiSem->cWaiters);669 int rc2 = pthread_mutex_unlock(&p IntEventMultiSem->Mutex);422 ASMAtomicDecU32(&pThis->cWaiters); 423 int rc2 = pthread_mutex_unlock(&pThis->Mutex); 670 424 AssertMsg(!rc2, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc2)); NOREF(rc2); 671 425 return RTErrConvertFromErrno(rc); … … 689 443 } 690 444 691 692 693 694 695 /**696 * Validate a Mutex semaphore handle passed to one of the interface.697 *698 * @returns true if valid.699 * @returns false if invalid.700 * @param pIntMutexSem Pointer to the mutex semaphore to validate.701 */702 inline bool rtsemMutexValid(struct RTSEMMUTEXINTERNAL *pIntMutexSem)703 {704 if ((uintptr_t)pIntMutexSem < 0x10000)705 return false;706 707 if (pIntMutexSem->cNesting == (uint32_t)~0)708 return false;709 710 return true;711 }712 713 714 RTDECL(int) RTSemMutexCreate(PRTSEMMUTEX pMutexSem)715 {716 int rc;717 718 /*719 * Allocate semaphore handle.720 */721 struct RTSEMMUTEXINTERNAL *pIntMutexSem = (struct RTSEMMUTEXINTERNAL *)RTMemAlloc(sizeof(struct RTSEMMUTEXINTERNAL));722 if (pIntMutexSem)723 {724 /*725 * Create the semaphore.726 */727 pthread_mutexattr_t MutexAttr;728 rc = pthread_mutexattr_init(&MutexAttr);729 if (!rc)730 {731 rc = pthread_mutex_init(&pIntMutexSem->Mutex, &MutexAttr);732 if (!rc)733 {734 pthread_mutexattr_destroy(&MutexAttr);735 736 pIntMutexSem->Owner = (pthread_t)-1;737 pIntMutexSem->cNesting = 0;738 739 *pMutexSem = pIntMutexSem;740 return VINF_SUCCESS;741 }742 pthread_mutexattr_destroy(&MutexAttr);743 }744 RTMemFree(pIntMutexSem);745 }746 else747 rc = VERR_NO_MEMORY;748 749 return rc;750 }751 752 753 RTDECL(int) RTSemMutexDestroy(RTSEMMUTEX MutexSem)754 {755 /*756 * Validate input.757 */758 if (!rtsemMutexValid(MutexSem))759 {760 AssertMsgFailed(("Invalid handle %p!\n", MutexSem));761 return VERR_INVALID_HANDLE;762 }763 764 /*765 * Try destroy it.766 */767 struct RTSEMMUTEXINTERNAL *pIntMutexSem = MutexSem;768 int rc = pthread_mutex_destroy(&pIntMutexSem->Mutex);769 if (rc)770 {771 AssertMsgFailed(("Failed to destroy mutex sem %p, rc=%d.\n", MutexSem, rc));772 return RTErrConvertFromErrno(rc);773 }774 775 /*776 * Free the memory and be gone.777 */778 pIntMutexSem->Owner = (pthread_t)-1;779 pIntMutexSem->cNesting = ~0;780 RTMemTmpFree(pIntMutexSem);781 782 return VINF_SUCCESS;783 }784 785 786 RTDECL(int) RTSemMutexRequest(RTSEMMUTEX MutexSem, unsigned cMillies)787 {788 /*789 * Validate input.790 */791 if (!rtsemMutexValid(MutexSem))792 {793 AssertMsgFailed(("Invalid handle %p!\n", MutexSem));794 return VERR_INVALID_HANDLE;795 }796 797 /*798 * Check if nested request.799 */800 pthread_t Self = pthread_self();801 struct RTSEMMUTEXINTERNAL *pIntMutexSem = MutexSem;802 if ( pIntMutexSem->Owner == Self803 && pIntMutexSem->cNesting > 0)804 {805 pIntMutexSem->cNesting++;806 return VINF_SUCCESS;807 }808 809 /*810 * Lock it.811 */812 if (cMillies == RT_INDEFINITE_WAIT)813 {814 /* take mutex */815 int rc = pthread_mutex_lock(&pIntMutexSem->Mutex);816 if (rc)817 {818 AssertMsgFailed(("Failed to lock mutex sem %p, rc=%d.\n", MutexSem, rc)); NOREF(rc);819 return RTErrConvertFromErrno(rc);820 }821 }822 else823 {824 #ifdef RT_OS_DARWIN825 AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));826 return VERR_NOT_IMPLEMENTED;827 #else /* !RT_OS_DARWIN */828 /*829 * Get current time and calc end of wait time.830 */831 struct timespec ts = {0,0};832 clock_gettime(CLOCK_REALTIME, &ts);833 if (cMillies != 0)834 {835 ts.tv_nsec += (cMillies % 1000) * 1000000;836 ts.tv_sec += cMillies / 1000;837 if (ts.tv_nsec >= 1000000000)838 {839 ts.tv_nsec -= 1000000000;840 ts.tv_sec++;841 }842 }843 844 /* take mutex */845 int rc = pthread_mutex_timedlock(&pIntMutexSem->Mutex, &ts);846 if (rc)847 {848 AssertMsg(rc == ETIMEDOUT, ("Failed to lock mutex sem %p, rc=%d.\n", MutexSem, rc)); NOREF(rc);849 return RTErrConvertFromErrno(rc);850 }851 #endif /* !RT_OS_DARWIN */852 }853 854 /*855 * Set the owner and nesting.856 */857 pIntMutexSem->Owner = Self;858 ASMAtomicXchgU32(&pIntMutexSem->cNesting, 1);859 860 return VINF_SUCCESS;861 }862 863 864 RTDECL(int) RTSemMutexRequestNoResume(RTSEMMUTEX MutexSem, unsigned cMillies)865 {866 /* EINTR isn't returned by the wait functions we're using. */867 return RTSemMutexRequest(MutexSem, cMillies);868 }869 870 871 RTDECL(int) RTSemMutexRelease(RTSEMMUTEX MutexSem)872 {873 /*874 * Validate input.875 */876 if (!rtsemMutexValid(MutexSem))877 {878 AssertMsgFailed(("Invalid handle %p!\n", MutexSem));879 return VERR_INVALID_HANDLE;880 }881 882 /*883 * Check if nested.884 */885 pthread_t Self = pthread_self();886 struct RTSEMMUTEXINTERNAL *pIntMutexSem = MutexSem;887 if ( pIntMutexSem->Owner != Self888 || pIntMutexSem->cNesting == (uint32_t)~0)889 {890 AssertMsgFailed(("Not owner of mutex %p!! Self=%08x Owner=%08x cNesting=%d\n",891 pIntMutexSem, Self, pIntMutexSem->Owner, pIntMutexSem->cNesting));892 return VERR_NOT_OWNER;893 }894 895 /*896 * If nested we'll just pop a nesting.897 */898 if (pIntMutexSem->cNesting > 1)899 {900 pIntMutexSem->cNesting--;901 return VINF_SUCCESS;902 }903 904 /*905 * Clear the state. (cNesting == 1)906 */907 pIntMutexSem->Owner = (pthread_t)-1;908 ASMAtomicXchgU32(&pIntMutexSem->cNesting, 0);909 910 /*911 * Unlock mutex semaphore.912 */913 int rc = pthread_mutex_unlock(&pIntMutexSem->Mutex);914 if (rc)915 {916 AssertMsgFailed(("Failed to unlock mutex sem %p, rc=%d.\n", MutexSem, rc)); NOREF(rc);917 return RTErrConvertFromErrno(rc);918 }919 920 return VINF_SUCCESS;921 }922 923 924 925 926 927 /**928 * Validate a read-write semaphore handle passed to one of the interface.929 *930 * @returns true if valid.931 * @returns false if invalid.932 * @param pIntRWSem Pointer to the read-write semaphore to validate.933 */934 inline bool rtsemRWValid(struct RTSEMRWINTERNAL *pIntRWSem)935 {936 if ((uintptr_t)pIntRWSem < 0x10000)937 return false;938 939 if (pIntRWSem->uCheck != (unsigned)~0)940 return false;941 942 return true;943 }944 945 946 RTDECL(int) RTSemRWCreate(PRTSEMRW pRWSem)947 {948 int rc;949 950 /*951 * Allocate handle.952 */953 struct RTSEMRWINTERNAL *pIntRWSem = (struct RTSEMRWINTERNAL *)RTMemAlloc(sizeof(struct RTSEMRWINTERNAL));954 if (pIntRWSem)955 {956 /*957 * Create the rwlock.958 */959 pthread_rwlockattr_t Attr;960 rc = pthread_rwlockattr_init(&Attr);961 if (!rc)962 {963 rc = pthread_rwlock_init(&pIntRWSem->RWLock, &Attr);964 if (!rc)965 {966 pIntRWSem->uCheck = ~0;967 pIntRWSem->WROwner = (pthread_t)-1;968 *pRWSem = pIntRWSem;969 return VINF_SUCCESS;970 }971 }972 973 rc = RTErrConvertFromErrno(rc);974 RTMemFree(pIntRWSem);975 }976 else977 rc = VERR_NO_MEMORY;978 979 return rc;980 }981 982 983 RTDECL(int) RTSemRWDestroy(RTSEMRW RWSem)984 {985 /*986 * Validate input.987 */988 if (!rtsemRWValid(RWSem))989 {990 AssertMsgFailed(("Invalid handle %p!\n", RWSem));991 return VERR_INVALID_HANDLE;992 }993 994 /*995 * Try destroy it.996 */997 struct RTSEMRWINTERNAL *pIntRWSem = RWSem;998 int rc = pthread_rwlock_destroy(&pIntRWSem->RWLock);999 if (!rc)1000 {1001 pIntRWSem->uCheck = 0;1002 RTMemFree(pIntRWSem);1003 rc = VINF_SUCCESS;1004 }1005 else1006 {1007 AssertMsgFailed(("Failed to destroy read-write sem %p, rc=%d.\n", RWSem, rc));1008 rc = RTErrConvertFromErrno(rc);1009 }1010 1011 return rc;1012 }1013 1014 1015 RTDECL(int) RTSemRWRequestRead(RTSEMRW RWSem, unsigned cMillies)1016 {1017 /*1018 * Validate input.1019 */1020 if (!rtsemRWValid(RWSem))1021 {1022 AssertMsgFailed(("Invalid handle %p!\n", RWSem));1023 return VERR_INVALID_HANDLE;1024 }1025 1026 /*1027 * Try lock it.1028 */1029 struct RTSEMRWINTERNAL *pIntRWSem = RWSem;1030 if (cMillies == RT_INDEFINITE_WAIT)1031 {1032 /* take rwlock */1033 int rc = pthread_rwlock_rdlock(&pIntRWSem->RWLock);1034 if (rc)1035 {1036 AssertMsgFailed(("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));1037 return RTErrConvertFromErrno(rc);1038 }1039 }1040 else1041 {1042 #ifdef RT_OS_DARWIN1043 AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));1044 return VERR_NOT_IMPLEMENTED;1045 #else /* !RT_OS_DARWIN */1046 /*1047 * Get current time and calc end of wait time.1048 */1049 struct timespec ts = {0,0};1050 clock_gettime(CLOCK_REALTIME, &ts);1051 if (cMillies != 0)1052 {1053 ts.tv_nsec += (cMillies % 1000) * 1000000;1054 ts.tv_sec += cMillies / 1000;1055 if (ts.tv_nsec >= 1000000000)1056 {1057 ts.tv_nsec -= 1000000000;1058 ts.tv_sec++;1059 }1060 }1061 1062 /* take rwlock */1063 int rc = pthread_rwlock_timedrdlock(&pIntRWSem->RWLock, &ts);1064 if (rc)1065 {1066 AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));1067 return RTErrConvertFromErrno(rc);1068 }1069 #endif /* !RT_OS_DARWIN */1070 }1071 1072 return VINF_SUCCESS;1073 }1074 1075 1076 RTDECL(int) RTSemRWRequestReadNoResume(RTSEMRW RWSem, unsigned cMillies)1077 {1078 /* EINTR isn't returned by the wait functions we're using. */1079 return RTSemRWRequestRead(RWSem, cMillies);1080 }1081 1082 1083 RTDECL(int) RTSemRWReleaseRead(RTSEMRW RWSem)1084 {1085 /*1086 * Validate input.1087 */1088 if (!rtsemRWValid(RWSem))1089 {1090 AssertMsgFailed(("Invalid handle %p!\n", RWSem));1091 return VERR_INVALID_HANDLE;1092 }1093 1094 /*1095 * Try unlock it.1096 */1097 struct RTSEMRWINTERNAL *pIntRWSem = RWSem;1098 if (pIntRWSem->WROwner == pthread_self())1099 {1100 AssertMsgFailed(("Tried to read unlock when write owner - read-write sem %p.\n", RWSem));1101 return VERR_NOT_OWNER;1102 }1103 int rc = pthread_rwlock_unlock(&pIntRWSem->RWLock);1104 if (rc)1105 {1106 AssertMsgFailed(("Failed read unlock read-write sem %p, rc=%d.\n", RWSem, rc));1107 return RTErrConvertFromErrno(rc);1108 }1109 1110 return VINF_SUCCESS;1111 }1112 1113 1114 RTDECL(int) RTSemRWRequestWrite(RTSEMRW RWSem, unsigned cMillies)1115 {1116 /*1117 * Validate input.1118 */1119 if (!rtsemRWValid(RWSem))1120 {1121 AssertMsgFailed(("Invalid handle %p!\n", RWSem));1122 return VERR_INVALID_HANDLE;1123 }1124 1125 /*1126 * Try lock it.1127 */1128 struct RTSEMRWINTERNAL *pIntRWSem = RWSem;1129 if (cMillies == RT_INDEFINITE_WAIT)1130 {1131 /* take rwlock */1132 int rc = pthread_rwlock_wrlock(&pIntRWSem->RWLock);1133 if (rc)1134 {1135 AssertMsgFailed(("Failed write lock read-write sem %p, rc=%d.\n", RWSem, rc));1136 return RTErrConvertFromErrno(rc);1137 }1138 }1139 else1140 {1141 #ifdef RT_OS_DARWIN1142 AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));1143 return VERR_NOT_IMPLEMENTED;1144 #else /* !RT_OS_DARWIN */1145 /*1146 * Get current time and calc end of wait time.1147 */1148 struct timespec ts = {0,0};1149 clock_gettime(CLOCK_REALTIME, &ts);1150 if (cMillies != 0)1151 {1152 ts.tv_nsec += (cMillies % 1000) * 1000000;1153 ts.tv_sec += cMillies / 1000;1154 if (ts.tv_nsec >= 1000000000)1155 {1156 ts.tv_nsec -= 1000000000;1157 ts.tv_sec++;1158 }1159 }1160 1161 /* take rwlock */1162 int rc = pthread_rwlock_timedwrlock(&pIntRWSem->RWLock, &ts);1163 if (rc)1164 {1165 AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));1166 return RTErrConvertFromErrno(rc);1167 }1168 #endif /* !RT_OS_DARWIN */1169 }1170 1171 #ifdef RT_OS_SOLARIS1172 ASMAtomicXchgSize(&pIntRWSem->WROwner, pthread_self());1173 #else1174 ASMAtomicXchgPtr((void * volatile *)&pIntRWSem->WROwner, (void *)pthread_self());1175 #endif1176 1177 return VINF_SUCCESS;1178 }1179 1180 1181 RTDECL(int) RTSemRWRequestWriteNoResume(RTSEMRW RWSem, unsigned cMillies)1182 {1183 /* EINTR isn't returned by the wait functions we're using. */1184 return RTSemRWRequestWrite(RWSem, cMillies);1185 }1186 1187 1188 RTDECL(int) RTSemRWReleaseWrite(RTSEMRW RWSem)1189 {1190 /*1191 * Validate input.1192 */1193 if (!rtsemRWValid(RWSem))1194 {1195 AssertMsgFailed(("Invalid handle %p!\n", RWSem));1196 return VERR_INVALID_HANDLE;1197 }1198 1199 /*1200 * Try unlock it.1201 */1202 pthread_t Self = pthread_self();1203 struct RTSEMRWINTERNAL *pIntRWSem = RWSem;1204 if (pIntRWSem->WROwner != Self)1205 {1206 AssertMsgFailed(("Not Write owner!\n"));1207 return VERR_NOT_OWNER;1208 }1209 1210 /*1211 * Try unlock it.1212 */1213 #ifdef RT_OS_SOLARIS1214 ASMAtomicXchgSize(&pIntRWSem->WROwner, (pthread_t)-1);1215 #else1216 AssertMsg(sizeof(pthread_t) == sizeof(void *), ("pthread_t is not the size of a pointer but %d bytes\n", sizeof(pthread_t)));1217 ASMAtomicXchgPtr((void * volatile *)&pIntRWSem->WROwner, (void *)(pthread_t)-1);1218 #endif1219 int rc = pthread_rwlock_unlock(&pIntRWSem->RWLock);1220 if (rc)1221 {1222 AssertMsgFailed(("Failed write unlock read-write sem %p, rc=%d.\n", RWSem, rc));1223 return RTErrConvertFromErrno(rc);1224 }1225 1226 return VINF_SUCCESS;1227 }1228 -
trunk/src/VBox/Runtime/r3/posix/semmutex-posix.cpp
r6734 r6738 1 1 /* $Id$ */ 2 2 /** @file 3 * innotek Portable Runtime - Semaphores, POSIX.3 * innotek Portable Runtime - Mutex Semaphore, POSIX. 4 4 */ 5 5 … … 39 39 #include <sys/time.h> 40 40 41 #ifdef RT_OS_DARWIN42 # define pthread_yield() pthread_yield_np()43 #endif44 45 #ifdef RT_OS_SOLARIS46 # include <sched.h>47 # define pthread_yield() sched_yield()48 #endif49 50 41 51 42 /******************************************************************************* 52 43 * Structures and Typedefs * 53 44 *******************************************************************************/ 54 55 /** Internal representation of the POSIX implementation of an Event semaphore.56 * The POSIX implementation uses a mutex and a condition variable to implement57 * the automatic reset event semaphore semantics.58 *59 * This must be identical to RTSEMEVENTMULTIINTERNAL!60 */61 struct RTSEMEVENTINTERNAL62 {63 /** pthread condition. */64 pthread_cond_t Cond;65 /** pthread mutex which protects the condition and the event state. */66 pthread_mutex_t Mutex;67 /** The state of the semaphore.68 * This is operated while owning mutex and using atomic updating. */69 volatile uint32_t u32State;70 /** Number of waiters. */71 volatile uint32_t cWaiters;72 };73 74 /** Posix internal representation of a Mutex Multi semaphore.75 * This must be identical to RTSEMEVENTINTERNAL! */76 struct RTSEMEVENTMULTIINTERNAL77 {78 /** pthread condition. */79 pthread_cond_t Cond;80 /** pthread mutex which protects the condition and the event state. */81 pthread_mutex_t Mutex;82 /** The state of the semaphore.83 * This is operated while owning mutex and using atomic updating. */84 volatile uint32_t u32State;85 /** Number of waiters. */86 volatile uint32_t cWaiters;87 };88 89 /** The valus of the u32State variable in a RTSEMEVENTINTERNAL and RTSEMEVENTMULTIINTERNAL.90 * @{ */91 /** The object isn't initialized. */92 #define EVENT_STATE_UNINITIALIZED 093 /** The semaphore is is signaled. */94 #define EVENT_STATE_SIGNALED 0xff00ff0095 /** The semaphore is not signaled. */96 #define EVENT_STATE_NOT_SIGNALED 0x00ff00ff97 /** @} */98 99 100 45 /** Posix internal representation of a Mutex semaphore. */ 101 46 struct RTSEMMUTEXINTERNAL … … 108 53 volatile uint32_t cNesting; 109 54 }; 110 111 /** Posix internal representation of a read-write semaphore. */112 struct RTSEMRWINTERNAL113 {114 /** pthread rwlock. */115 pthread_rwlock_t RWLock;116 /** Variable to check if initialized.117 * 0 is uninitialized, ~0 is inititialized. */118 volatile unsigned uCheck;119 /** The write owner of the lock. */120 volatile pthread_t WROwner;121 };122 123 124 /**125 * Validate an Event semaphore handle passed to one of the interface.126 *127 * @returns true if valid.128 * @returns false if invalid.129 * @param pIntEventSem Pointer to the event semaphore to validate.130 */131 inline bool rtsemEventValid(struct RTSEMEVENTINTERNAL *pIntEventSem)132 {133 if ((uintptr_t)pIntEventSem < 0x10000)134 return false;135 136 uint32_t u32 = pIntEventSem->u32State; /* this is volatile, so a explicit read like this is needed. */137 if ( u32 != EVENT_STATE_NOT_SIGNALED138 && u32 != EVENT_STATE_SIGNALED)139 return false;140 141 return true;142 }143 144 145 RTDECL(int) RTSemEventCreate(PRTSEMEVENT pEventSem)146 {147 int rc;148 149 /*150 * Allocate semaphore handle.151 */152 struct RTSEMEVENTINTERNAL *pIntEventSem = (struct RTSEMEVENTINTERNAL *)RTMemAlloc(sizeof(struct RTSEMEVENTINTERNAL));153 if (pIntEventSem)154 {155 /*156 * Create the condition variable.157 */158 pthread_condattr_t CondAttr;159 rc = pthread_condattr_init(&CondAttr);160 if (!rc)161 {162 rc = pthread_cond_init(&pIntEventSem->Cond, &CondAttr);163 if (!rc)164 {165 /*166 * Create the semaphore.167 */168 pthread_mutexattr_t MutexAttr;169 rc = pthread_mutexattr_init(&MutexAttr);170 if (!rc)171 {172 rc = pthread_mutex_init(&pIntEventSem->Mutex, &MutexAttr);173 if (!rc)174 {175 pthread_mutexattr_destroy(&MutexAttr);176 pthread_condattr_destroy(&CondAttr);177 178 ASMAtomicXchgU32(&pIntEventSem->u32State, EVENT_STATE_NOT_SIGNALED);179 ASMAtomicXchgU32(&pIntEventSem->cWaiters, 0);180 181 *pEventSem = pIntEventSem;182 return VINF_SUCCESS;183 }184 pthread_mutexattr_destroy(&MutexAttr);185 }186 pthread_cond_destroy(&pIntEventSem->Cond);187 }188 pthread_condattr_destroy(&CondAttr);189 }190 191 rc = RTErrConvertFromErrno(rc);192 RTMemFree(pIntEventSem);193 }194 else195 rc = VERR_NO_MEMORY;196 197 return rc;198 }199 200 201 RTDECL(int) RTSemEventDestroy(RTSEMEVENT EventSem)202 {203 /*204 * Validate handle.205 */206 if (!rtsemEventValid(EventSem))207 {208 AssertMsgFailed(("Invalid handle %p!\n", EventSem));209 return VERR_INVALID_HANDLE;210 }211 212 /*213 * Abort all waiters forcing them to return failure.214 *215 */216 struct RTSEMEVENTINTERNAL *pIntEventSem = EventSem;217 int rc;218 for (int i = 30; i > 0; i--)219 {220 ASMAtomicXchgU32(&pIntEventSem->u32State, EVENT_STATE_UNINITIALIZED);221 rc = pthread_cond_destroy(&pIntEventSem->Cond);222 if (rc != EBUSY)223 break;224 pthread_cond_broadcast(&pIntEventSem->Cond);225 usleep(1000);226 } while (rc == EBUSY);227 if (rc)228 {229 AssertMsgFailed(("Failed to destroy event sem %p, rc=%d.\n", EventSem, rc));230 return RTErrConvertFromErrno(rc);231 }232 233 /*234 * Destroy the semaphore235 * If it's busy we'll wait a bit to give the threads a chance to be scheduled.236 */237 for (int i = 30; i > 0; i--)238 {239 rc = pthread_mutex_destroy(&pIntEventSem->Mutex);240 if (rc != EBUSY)241 break;242 usleep(1000);243 }244 if (rc)245 {246 AssertMsgFailed(("Failed to destroy event sem %p, rc=%d. (mutex)\n", EventSem, rc));247 return RTErrConvertFromErrno(rc);248 }249 250 /*251 * Free the semaphore memory and be gone.252 */253 RTMemFree(pIntEventSem);254 return VINF_SUCCESS;255 }256 257 258 RTDECL(int) RTSemEventSignal(RTSEMEVENT EventSem)259 {260 /*261 * Validate input.262 */263 if (!rtsemEventValid(EventSem))264 {265 AssertMsgFailed(("Invalid handle %p!\n", EventSem));266 return VERR_INVALID_HANDLE;267 }268 269 /*270 * Lock the mutex semaphore.271 */272 struct RTSEMEVENTINTERNAL *pIntEventSem = EventSem;273 int rc = pthread_mutex_lock(&pIntEventSem->Mutex);274 if (rc)275 {276 AssertMsgFailed(("Failed to lock event sem %p, rc=%d.\n", EventSem, rc));277 return RTErrConvertFromErrno(rc);278 }279 280 /*281 * Check the state.282 */283 if (pIntEventSem->u32State == EVENT_STATE_NOT_SIGNALED)284 {285 ASMAtomicXchgU32(&pIntEventSem->u32State, EVENT_STATE_SIGNALED);286 rc = pthread_cond_signal(&pIntEventSem->Cond);287 AssertMsg(!rc, ("Failed to signal event sem %p, rc=%d.\n", EventSem, rc));288 }289 else if (pIntEventSem->u32State == EVENT_STATE_SIGNALED)290 {291 rc = pthread_cond_signal(&pIntEventSem->Cond); /* give'm another kick... */292 AssertMsg(!rc, ("Failed to signal event sem %p, rc=%d. (2)\n", EventSem, rc));293 }294 else295 rc = VERR_SEM_DESTROYED;296 297 /*298 * Release the mutex and return.299 */300 int rc2 = pthread_mutex_unlock(&pIntEventSem->Mutex);301 AssertMsg(!rc2, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc));302 if (rc)303 return RTErrConvertFromErrno(rc);304 if (rc2)305 return RTErrConvertFromErrno(rc2);306 307 return VINF_SUCCESS;308 }309 310 311 static int rtSemEventWait(RTSEMEVENT EventSem, unsigned cMillies, bool fAutoResume)312 {313 /*314 * Validate input.315 */316 if (!rtsemEventValid(EventSem))317 {318 AssertMsgFailed(("Invalid handle %p!\n", EventSem));319 return VERR_INVALID_HANDLE;320 }321 322 /*323 * Timed or indefinite wait?324 */325 struct RTSEMEVENTINTERNAL *pIntEventSem = EventSem;326 if (cMillies == RT_INDEFINITE_WAIT)327 {328 /* for fairness, yield before going to sleep. */329 if ( ASMAtomicIncU32(&pIntEventSem->cWaiters) > 1330 && pIntEventSem->u32State == EVENT_STATE_SIGNALED)331 pthread_yield();332 333 /* take mutex */334 int rc = pthread_mutex_lock(&pIntEventSem->Mutex);335 if (rc)336 {337 ASMAtomicDecU32(&pIntEventSem->cWaiters);338 AssertMsgFailed(("Failed to lock event sem %p, rc=%d.\n", EventSem, rc));339 return RTErrConvertFromErrno(rc);340 }341 342 for (;;)343 {344 /* check state. */345 if (pIntEventSem->u32State == EVENT_STATE_SIGNALED)346 {347 ASMAtomicXchgU32(&pIntEventSem->u32State, EVENT_STATE_NOT_SIGNALED);348 ASMAtomicDecU32(&pIntEventSem->cWaiters);349 rc = pthread_mutex_unlock(&pIntEventSem->Mutex);350 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc)); NOREF(rc);351 return VINF_SUCCESS;352 }353 if (pIntEventSem->u32State == EVENT_STATE_UNINITIALIZED)354 {355 rc = pthread_mutex_unlock(&pIntEventSem->Mutex);356 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc)); NOREF(rc);357 return VERR_SEM_DESTROYED;358 }359 360 /* wait */361 rc = pthread_cond_wait(&pIntEventSem->Cond, &pIntEventSem->Mutex);362 if (rc)363 {364 AssertMsgFailed(("Failed to wait on event sem %p, rc=%d.\n", EventSem, rc));365 ASMAtomicDecU32(&pIntEventSem->cWaiters);366 int rc2 = pthread_mutex_unlock(&pIntEventSem->Mutex);367 AssertMsg(!rc2, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc2)); NOREF(rc2);368 return RTErrConvertFromErrno(rc);369 }370 }371 }372 else373 {374 /*375 * Get current time and calc end of wait time.376 */377 struct timespec ts = {0,0};378 #ifdef RT_OS_DARWIN379 struct timeval tv = {0,0};380 gettimeofday(&tv, NULL);381 ts.tv_sec = tv.tv_sec;382 ts.tv_nsec = tv.tv_usec * 1000;383 #else384 clock_gettime(CLOCK_REALTIME, &ts);385 #endif386 if (cMillies != 0)387 {388 ts.tv_nsec += (cMillies % 1000) * 1000000;389 ts.tv_sec += cMillies / 1000;390 if (ts.tv_nsec >= 1000000000)391 {392 ts.tv_nsec -= 1000000000;393 ts.tv_sec++;394 }395 }396 397 /* for fairness, yield before going to sleep. */398 if (ASMAtomicIncU32(&pIntEventSem->cWaiters) > 1)399 pthread_yield();400 401 /* take mutex */402 #ifdef RT_OS_DARWIN403 int rc = pthread_mutex_lock(&pIntEventSem->Mutex);404 #else405 int rc = pthread_mutex_timedlock(&pIntEventSem->Mutex, &ts);406 #endif407 if (rc)408 {409 ASMAtomicDecU32(&pIntEventSem->cWaiters);410 AssertMsg(rc == ETIMEDOUT, ("Failed to lock event sem %p, rc=%d.\n", EventSem, rc));411 return RTErrConvertFromErrno(rc);412 }413 414 for (;;)415 {416 /* check state. */417 if (pIntEventSem->u32State == EVENT_STATE_SIGNALED)418 {419 ASMAtomicXchgU32(&pIntEventSem->u32State, EVENT_STATE_NOT_SIGNALED);420 ASMAtomicDecU32(&pIntEventSem->cWaiters);421 rc = pthread_mutex_unlock(&pIntEventSem->Mutex);422 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc)); NOREF(rc);423 return VINF_SUCCESS;424 }425 if (pIntEventSem->u32State == EVENT_STATE_UNINITIALIZED)426 {427 rc = pthread_mutex_unlock(&pIntEventSem->Mutex);428 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc)); NOREF(rc);429 return VERR_SEM_DESTROYED;430 }431 432 /* wait */433 rc = pthread_cond_timedwait(&pIntEventSem->Cond, &pIntEventSem->Mutex, &ts);434 if (rc && (rc != EINTR || !fAutoResume)) /* according to SuS this function shall not return EINTR, but linux man page says differently. */435 {436 AssertMsg(rc == ETIMEDOUT, ("Failed to wait on event sem %p, rc=%d.\n", EventSem, rc));437 ASMAtomicDecU32(&pIntEventSem->cWaiters);438 int rc2 = pthread_mutex_unlock(&pIntEventSem->Mutex);439 AssertMsg(!rc2, ("Failed to unlock event sem %p, rc2=%d.\n", EventSem, rc2)); NOREF(rc2);440 return RTErrConvertFromErrno(rc);441 }442 } /* for (;;) */443 }444 }445 446 447 RTDECL(int) RTSemEventWait(RTSEMEVENT EventSem, unsigned cMillies)448 {449 int rc = rtSemEventWait(EventSem, cMillies, true);450 Assert(rc != VERR_INTERRUPTED);451 return rc;452 }453 454 455 RTDECL(int) RTSemEventWaitNoResume(RTSEMEVENT EventSem, unsigned cMillies)456 {457 return rtSemEventWait(EventSem, cMillies, false);458 }459 460 461 462 463 464 465 /**466 * Validate an event multi semaphore handle passed to one of the interface.467 *468 * @returns true if valid.469 * @returns false if invalid.470 * @param pIntEventMultiSem Pointer to the event semaphore to validate.471 */472 inline bool rtsemEventMultiValid(struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem)473 {474 if ((uintptr_t)pIntEventMultiSem < 0x10000)475 return false;476 477 uint32_t u32 = pIntEventMultiSem->u32State; /* this is volatile, so a explicit read like this is needed. */478 if ( u32 != EVENT_STATE_NOT_SIGNALED479 && u32 != EVENT_STATE_SIGNALED)480 return false;481 482 return true;483 }484 485 486 RTDECL(int) RTSemEventMultiCreate(PRTSEMEVENTMULTI pEventMultiSem)487 {488 /* the code and the structure is identical with other type for this function. */489 return RTSemEventCreate((PRTSEMEVENT)pEventMultiSem);490 }491 492 493 RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI EventMultiSem)494 {495 /* the code and the structure is identical with other type for this function. */496 return RTSemEventDestroy((RTSEMEVENT)EventMultiSem);497 }498 499 500 RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI EventMultiSem)501 {502 /* the code and the structure is identical with other type for this function. */503 return RTSemEventSignal((RTSEMEVENT)EventMultiSem);504 }505 506 507 RTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI EventMultiSem)508 {509 /*510 * Validate input.511 */512 if (!rtsemEventMultiValid(EventMultiSem))513 {514 AssertMsgFailed(("Invalid handle %p!\n", EventMultiSem));515 return VERR_INVALID_HANDLE;516 }517 518 /*519 * Lock the mutex semaphore.520 */521 struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem = EventMultiSem;522 int rc = pthread_mutex_lock(&pIntEventMultiSem->Mutex);523 if (rc)524 {525 AssertMsgFailed(("Failed to lock event multi sem %p, rc=%d.\n", EventMultiSem, rc));526 return RTErrConvertFromErrno(rc);527 }528 529 /*530 * Check the state.531 */532 if (pIntEventMultiSem->u32State == EVENT_STATE_SIGNALED)533 ASMAtomicXchgU32(&pIntEventMultiSem->u32State, EVENT_STATE_NOT_SIGNALED);534 else if (pIntEventMultiSem->u32State != EVENT_STATE_NOT_SIGNALED)535 rc = VERR_SEM_DESTROYED;536 537 /*538 * Release the mutex and return.539 */540 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);541 if (rc)542 {543 AssertMsgFailed(("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc));544 return RTErrConvertFromErrno(rc);545 }546 547 return VINF_SUCCESS;548 549 }550 551 552 static int rtSemEventMultiWait(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies, bool fAutoResume)553 {554 /*555 * Validate input.556 */557 if (!rtsemEventMultiValid(EventMultiSem))558 {559 AssertMsgFailed(("Invalid handle %p!\n", EventMultiSem));560 return VERR_INVALID_HANDLE;561 }562 563 /*564 * Timed or indefinite wait?565 */566 struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem = EventMultiSem;567 if (cMillies == RT_INDEFINITE_WAIT)568 {569 /* take mutex */570 int rc = pthread_mutex_lock(&pIntEventMultiSem->Mutex);571 if (rc)572 {573 AssertMsgFailed(("Failed to lock event multi sem %p, rc=%d.\n", EventMultiSem, rc));574 return RTErrConvertFromErrno(rc);575 }576 ASMAtomicIncU32(&pIntEventMultiSem->cWaiters);577 578 for (;;)579 {580 /* check state. */581 if (pIntEventMultiSem->u32State == EVENT_STATE_SIGNALED)582 {583 ASMAtomicDecU32(&pIntEventMultiSem->cWaiters);584 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);585 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc);586 return VINF_SUCCESS;587 }588 if (pIntEventMultiSem->u32State == EVENT_STATE_UNINITIALIZED)589 {590 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);591 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc);592 return VERR_SEM_DESTROYED;593 }594 595 /* wait */596 rc = pthread_cond_wait(&pIntEventMultiSem->Cond, &pIntEventMultiSem->Mutex);597 if (rc)598 {599 AssertMsgFailed(("Failed to wait on event multi sem %p, rc=%d.\n", EventMultiSem, rc));600 ASMAtomicDecU32(&pIntEventMultiSem->cWaiters);601 int rc2 = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);602 AssertMsg(!rc2, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc2)); NOREF(rc2);603 return RTErrConvertFromErrno(rc);604 }605 }606 }607 else608 {609 /*610 * Get current time and calc end of wait time.611 */612 struct timespec ts = {0,0};613 #ifdef RT_OS_DARWIN614 struct timeval tv = {0,0};615 gettimeofday(&tv, NULL);616 ts.tv_sec = tv.tv_sec;617 ts.tv_nsec = tv.tv_usec * 1000;618 #else619 clock_gettime(CLOCK_REALTIME, &ts);620 #endif621 if (cMillies != 0)622 {623 ts.tv_nsec += (cMillies % 1000) * 1000000;624 ts.tv_sec += cMillies / 1000;625 if (ts.tv_nsec >= 1000000000)626 {627 ts.tv_nsec -= 1000000000;628 ts.tv_sec++;629 }630 }631 632 /* take mutex */633 #ifdef RT_OS_DARWIN634 int rc = pthread_mutex_lock(&pIntEventMultiSem->Mutex);635 #else636 int rc = pthread_mutex_timedlock(&pIntEventMultiSem->Mutex, &ts);637 #endif638 if (rc)639 {640 AssertMsg(rc == ETIMEDOUT, ("Failed to lock event multi sem %p, rc=%d.\n", EventMultiSem, rc));641 return RTErrConvertFromErrno(rc);642 }643 ASMAtomicIncU32(&pIntEventMultiSem->cWaiters);644 645 for (;;)646 {647 /* check state. */648 if (pIntEventMultiSem->u32State == EVENT_STATE_SIGNALED)649 {650 ASMAtomicXchgU32(&pIntEventMultiSem->u32State, EVENT_STATE_NOT_SIGNALED);651 ASMAtomicDecU32(&pIntEventMultiSem->cWaiters);652 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);653 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc);654 return VINF_SUCCESS;655 }656 if (pIntEventMultiSem->u32State == EVENT_STATE_UNINITIALIZED)657 {658 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);659 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc);660 return VERR_SEM_DESTROYED;661 }662 663 /* wait */664 rc = pthread_cond_timedwait(&pIntEventMultiSem->Cond, &pIntEventMultiSem->Mutex, &ts);665 if (rc && (rc != EINTR || !fAutoResume)) /* according to SuS this function shall not return EINTR, but linux man page says differently. */666 {667 AssertMsg(rc == ETIMEDOUT, ("Failed to wait on event multi sem %p, rc=%d.\n", EventMultiSem, rc));668 ASMAtomicDecU32(&pIntEventMultiSem->cWaiters);669 int rc2 = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);670 AssertMsg(!rc2, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc2)); NOREF(rc2);671 return RTErrConvertFromErrno(rc);672 }673 }674 }675 }676 677 678 RTDECL(int) RTSemEventMultiWait(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies)679 {680 int rc = rtSemEventMultiWait(EventMultiSem, cMillies, true);681 Assert(rc != VERR_INTERRUPTED);682 return rc;683 }684 685 686 RTDECL(int) RTSemEventMultiWaitNoResume(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies)687 {688 return rtSemEventMultiWait(EventMultiSem, cMillies, false);689 }690 691 692 55 693 56 … … 921 284 } 922 285 923 924 925 926 927 /**928 * Validate a read-write semaphore handle passed to one of the interface.929 *930 * @returns true if valid.931 * @returns false if invalid.932 * @param pIntRWSem Pointer to the read-write semaphore to validate.933 */934 inline bool rtsemRWValid(struct RTSEMRWINTERNAL *pIntRWSem)935 {936 if ((uintptr_t)pIntRWSem < 0x10000)937 return false;938 939 if (pIntRWSem->uCheck != (unsigned)~0)940 return false;941 942 return true;943 }944 945 946 RTDECL(int) RTSemRWCreate(PRTSEMRW pRWSem)947 {948 int rc;949 950 /*951 * Allocate handle.952 */953 struct RTSEMRWINTERNAL *pIntRWSem = (struct RTSEMRWINTERNAL *)RTMemAlloc(sizeof(struct RTSEMRWINTERNAL));954 if (pIntRWSem)955 {956 /*957 * Create the rwlock.958 */959 pthread_rwlockattr_t Attr;960 rc = pthread_rwlockattr_init(&Attr);961 if (!rc)962 {963 rc = pthread_rwlock_init(&pIntRWSem->RWLock, &Attr);964 if (!rc)965 {966 pIntRWSem->uCheck = ~0;967 pIntRWSem->WROwner = (pthread_t)-1;968 *pRWSem = pIntRWSem;969 return VINF_SUCCESS;970 }971 }972 973 rc = RTErrConvertFromErrno(rc);974 RTMemFree(pIntRWSem);975 }976 else977 rc = VERR_NO_MEMORY;978 979 return rc;980 }981 982 983 RTDECL(int) RTSemRWDestroy(RTSEMRW RWSem)984 {985 /*986 * Validate input.987 */988 if (!rtsemRWValid(RWSem))989 {990 AssertMsgFailed(("Invalid handle %p!\n", RWSem));991 return VERR_INVALID_HANDLE;992 }993 994 /*995 * Try destroy it.996 */997 struct RTSEMRWINTERNAL *pIntRWSem = RWSem;998 int rc = pthread_rwlock_destroy(&pIntRWSem->RWLock);999 if (!rc)1000 {1001 pIntRWSem->uCheck = 0;1002 RTMemFree(pIntRWSem);1003 rc = VINF_SUCCESS;1004 }1005 else1006 {1007 AssertMsgFailed(("Failed to destroy read-write sem %p, rc=%d.\n", RWSem, rc));1008 rc = RTErrConvertFromErrno(rc);1009 }1010 1011 return rc;1012 }1013 1014 1015 RTDECL(int) RTSemRWRequestRead(RTSEMRW RWSem, unsigned cMillies)1016 {1017 /*1018 * Validate input.1019 */1020 if (!rtsemRWValid(RWSem))1021 {1022 AssertMsgFailed(("Invalid handle %p!\n", RWSem));1023 return VERR_INVALID_HANDLE;1024 }1025 1026 /*1027 * Try lock it.1028 */1029 struct RTSEMRWINTERNAL *pIntRWSem = RWSem;1030 if (cMillies == RT_INDEFINITE_WAIT)1031 {1032 /* take rwlock */1033 int rc = pthread_rwlock_rdlock(&pIntRWSem->RWLock);1034 if (rc)1035 {1036 AssertMsgFailed(("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));1037 return RTErrConvertFromErrno(rc);1038 }1039 }1040 else1041 {1042 #ifdef RT_OS_DARWIN1043 AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));1044 return VERR_NOT_IMPLEMENTED;1045 #else /* !RT_OS_DARWIN */1046 /*1047 * Get current time and calc end of wait time.1048 */1049 struct timespec ts = {0,0};1050 clock_gettime(CLOCK_REALTIME, &ts);1051 if (cMillies != 0)1052 {1053 ts.tv_nsec += (cMillies % 1000) * 1000000;1054 ts.tv_sec += cMillies / 1000;1055 if (ts.tv_nsec >= 1000000000)1056 {1057 ts.tv_nsec -= 1000000000;1058 ts.tv_sec++;1059 }1060 }1061 1062 /* take rwlock */1063 int rc = pthread_rwlock_timedrdlock(&pIntRWSem->RWLock, &ts);1064 if (rc)1065 {1066 AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));1067 return RTErrConvertFromErrno(rc);1068 }1069 #endif /* !RT_OS_DARWIN */1070 }1071 1072 return VINF_SUCCESS;1073 }1074 1075 1076 RTDECL(int) RTSemRWRequestReadNoResume(RTSEMRW RWSem, unsigned cMillies)1077 {1078 /* EINTR isn't returned by the wait functions we're using. */1079 return RTSemRWRequestRead(RWSem, cMillies);1080 }1081 1082 1083 RTDECL(int) RTSemRWReleaseRead(RTSEMRW RWSem)1084 {1085 /*1086 * Validate input.1087 */1088 if (!rtsemRWValid(RWSem))1089 {1090 AssertMsgFailed(("Invalid handle %p!\n", RWSem));1091 return VERR_INVALID_HANDLE;1092 }1093 1094 /*1095 * Try unlock it.1096 */1097 struct RTSEMRWINTERNAL *pIntRWSem = RWSem;1098 if (pIntRWSem->WROwner == pthread_self())1099 {1100 AssertMsgFailed(("Tried to read unlock when write owner - read-write sem %p.\n", RWSem));1101 return VERR_NOT_OWNER;1102 }1103 int rc = pthread_rwlock_unlock(&pIntRWSem->RWLock);1104 if (rc)1105 {1106 AssertMsgFailed(("Failed read unlock read-write sem %p, rc=%d.\n", RWSem, rc));1107 return RTErrConvertFromErrno(rc);1108 }1109 1110 return VINF_SUCCESS;1111 }1112 1113 1114 RTDECL(int) RTSemRWRequestWrite(RTSEMRW RWSem, unsigned cMillies)1115 {1116 /*1117 * Validate input.1118 */1119 if (!rtsemRWValid(RWSem))1120 {1121 AssertMsgFailed(("Invalid handle %p!\n", RWSem));1122 return VERR_INVALID_HANDLE;1123 }1124 1125 /*1126 * Try lock it.1127 */1128 struct RTSEMRWINTERNAL *pIntRWSem = RWSem;1129 if (cMillies == RT_INDEFINITE_WAIT)1130 {1131 /* take rwlock */1132 int rc = pthread_rwlock_wrlock(&pIntRWSem->RWLock);1133 if (rc)1134 {1135 AssertMsgFailed(("Failed write lock read-write sem %p, rc=%d.\n", RWSem, rc));1136 return RTErrConvertFromErrno(rc);1137 }1138 }1139 else1140 {1141 #ifdef RT_OS_DARWIN1142 AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));1143 return VERR_NOT_IMPLEMENTED;1144 #else /* !RT_OS_DARWIN */1145 /*1146 * Get current time and calc end of wait time.1147 */1148 struct timespec ts = {0,0};1149 clock_gettime(CLOCK_REALTIME, &ts);1150 if (cMillies != 0)1151 {1152 ts.tv_nsec += (cMillies % 1000) * 1000000;1153 ts.tv_sec += cMillies / 1000;1154 if (ts.tv_nsec >= 1000000000)1155 {1156 ts.tv_nsec -= 1000000000;1157 ts.tv_sec++;1158 }1159 }1160 1161 /* take rwlock */1162 int rc = pthread_rwlock_timedwrlock(&pIntRWSem->RWLock, &ts);1163 if (rc)1164 {1165 AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));1166 return RTErrConvertFromErrno(rc);1167 }1168 #endif /* !RT_OS_DARWIN */1169 }1170 1171 #ifdef RT_OS_SOLARIS1172 ASMAtomicXchgSize(&pIntRWSem->WROwner, pthread_self());1173 #else1174 ASMAtomicXchgPtr((void * volatile *)&pIntRWSem->WROwner, (void *)pthread_self());1175 #endif1176 1177 return VINF_SUCCESS;1178 }1179 1180 1181 RTDECL(int) RTSemRWRequestWriteNoResume(RTSEMRW RWSem, unsigned cMillies)1182 {1183 /* EINTR isn't returned by the wait functions we're using. */1184 return RTSemRWRequestWrite(RWSem, cMillies);1185 }1186 1187 1188 RTDECL(int) RTSemRWReleaseWrite(RTSEMRW RWSem)1189 {1190 /*1191 * Validate input.1192 */1193 if (!rtsemRWValid(RWSem))1194 {1195 AssertMsgFailed(("Invalid handle %p!\n", RWSem));1196 return VERR_INVALID_HANDLE;1197 }1198 1199 /*1200 * Try unlock it.1201 */1202 pthread_t Self = pthread_self();1203 struct RTSEMRWINTERNAL *pIntRWSem = RWSem;1204 if (pIntRWSem->WROwner != Self)1205 {1206 AssertMsgFailed(("Not Write owner!\n"));1207 return VERR_NOT_OWNER;1208 }1209 1210 /*1211 * Try unlock it.1212 */1213 #ifdef RT_OS_SOLARIS1214 ASMAtomicXchgSize(&pIntRWSem->WROwner, (pthread_t)-1);1215 #else1216 AssertMsg(sizeof(pthread_t) == sizeof(void *), ("pthread_t is not the size of a pointer but %d bytes\n", sizeof(pthread_t)));1217 ASMAtomicXchgPtr((void * volatile *)&pIntRWSem->WROwner, (void *)(pthread_t)-1);1218 #endif1219 int rc = pthread_rwlock_unlock(&pIntRWSem->RWLock);1220 if (rc)1221 {1222 AssertMsgFailed(("Failed write unlock read-write sem %p, rc=%d.\n", RWSem, rc));1223 return RTErrConvertFromErrno(rc);1224 }1225 1226 return VINF_SUCCESS;1227 }1228 -
trunk/src/VBox/Runtime/r3/posix/semrw-posix.cpp
r6734 r6738 1 1 /* $Id$ */ 2 2 /** @file 3 * innotek Portable Runtime - Semaphores, POSIX.3 * innotek Portable Runtime - Read-Write Semaphore, POSIX. 4 4 */ 5 5 … … 39 39 #include <sys/time.h> 40 40 41 #ifdef RT_OS_DARWIN42 # define pthread_yield() pthread_yield_np()43 #endif44 45 #ifdef RT_OS_SOLARIS46 # include <sched.h>47 # define pthread_yield() sched_yield()48 #endif49 50 41 51 42 /******************************************************************************* 52 43 * Structures and Typedefs * 53 44 *******************************************************************************/ 54 55 /** Internal representation of the POSIX implementation of an Event semaphore.56 * The POSIX implementation uses a mutex and a condition variable to implement57 * the automatic reset event semaphore semantics.58 *59 * This must be identical to RTSEMEVENTMULTIINTERNAL!60 */61 struct RTSEMEVENTINTERNAL62 {63 /** pthread condition. */64 pthread_cond_t Cond;65 /** pthread mutex which protects the condition and the event state. */66 pthread_mutex_t Mutex;67 /** The state of the semaphore.68 * This is operated while owning mutex and using atomic updating. */69 volatile uint32_t u32State;70 /** Number of waiters. */71 volatile uint32_t cWaiters;72 };73 74 /** Posix internal representation of a Mutex Multi semaphore.75 * This must be identical to RTSEMEVENTINTERNAL! */76 struct RTSEMEVENTMULTIINTERNAL77 {78 /** pthread condition. */79 pthread_cond_t Cond;80 /** pthread mutex which protects the condition and the event state. */81 pthread_mutex_t Mutex;82 /** The state of the semaphore.83 * This is operated while owning mutex and using atomic updating. */84 volatile uint32_t u32State;85 /** Number of waiters. */86 volatile uint32_t cWaiters;87 };88 89 /** The valus of the u32State variable in a RTSEMEVENTINTERNAL and RTSEMEVENTMULTIINTERNAL.90 * @{ */91 /** The object isn't initialized. */92 #define EVENT_STATE_UNINITIALIZED 093 /** The semaphore is is signaled. */94 #define EVENT_STATE_SIGNALED 0xff00ff0095 /** The semaphore is not signaled. */96 #define EVENT_STATE_NOT_SIGNALED 0x00ff00ff97 /** @} */98 99 100 /** Posix internal representation of a Mutex semaphore. */101 struct RTSEMMUTEXINTERNAL102 {103 /** pthread mutex. */104 pthread_mutex_t Mutex;105 /** The owner of the mutex. */106 volatile pthread_t Owner;107 /** Nesting count. */108 volatile uint32_t cNesting;109 };110 111 45 /** Posix internal representation of a read-write semaphore. */ 112 46 struct RTSEMRWINTERNAL … … 122 56 123 57 58 124 59 /** 125 * Validate a n Eventsemaphore handle passed to one of the interface.60 * Validate a read-write semaphore handle passed to one of the interface. 126 61 * 127 62 * @returns true if valid. 128 63 * @returns false if invalid. 129 * @param pInt EventSem Pointer to the eventsemaphore to validate.64 * @param pIntRWSem Pointer to the read-write semaphore to validate. 130 65 */ 131 inline bool rtsem EventValid(struct RTSEMEVENTINTERNAL *pIntEventSem)132 { 133 if ((uintptr_t)pInt EventSem < 0x10000)66 inline bool rtsemRWValid(struct RTSEMRWINTERNAL *pIntRWSem) 67 { 68 if ((uintptr_t)pIntRWSem < 0x10000) 134 69 return false; 135 70 136 uint32_t u32 = pIntEventSem->u32State; /* this is volatile, so a explicit read like this is needed. */ 137 if ( u32 != EVENT_STATE_NOT_SIGNALED 138 && u32 != EVENT_STATE_SIGNALED) 71 if (pIntRWSem->uCheck != (unsigned)~0) 139 72 return false; 140 73 … … 143 76 144 77 145 RTDECL(int) RTSemEventCreate(PRTSEMEVENT pEventSem)78 RTDECL(int) RTSemRWCreate(PRTSEMRW pRWSem) 146 79 { 147 80 int rc; 148 81 149 82 /* 150 * Allocate semaphorehandle.151 */ 152 struct RTSEM EVENTINTERNAL *pIntEventSem = (struct RTSEMEVENTINTERNAL *)RTMemAlloc(sizeof(struct RTSEMEVENTINTERNAL));153 if (pInt EventSem)83 * Allocate handle. 84 */ 85 struct RTSEMRWINTERNAL *pIntRWSem = (struct RTSEMRWINTERNAL *)RTMemAlloc(sizeof(struct RTSEMRWINTERNAL)); 86 if (pIntRWSem) 154 87 { 155 88 /* 156 * Create the condition variable.89 * Create the rwlock. 157 90 */ 158 pthread_ condattr_t CondAttr;159 rc = pthread_ condattr_init(&CondAttr);91 pthread_rwlockattr_t Attr; 92 rc = pthread_rwlockattr_init(&Attr); 160 93 if (!rc) 161 94 { 162 rc = pthread_ cond_init(&pIntEventSem->Cond, &CondAttr);95 rc = pthread_rwlock_init(&pIntRWSem->RWLock, &Attr); 163 96 if (!rc) 164 97 { 165 /* 166 * Create the semaphore. 167 */ 168 pthread_mutexattr_t MutexAttr; 169 rc = pthread_mutexattr_init(&MutexAttr); 170 if (!rc) 171 { 172 rc = pthread_mutex_init(&pIntEventSem->Mutex, &MutexAttr); 173 if (!rc) 174 { 175 pthread_mutexattr_destroy(&MutexAttr); 176 pthread_condattr_destroy(&CondAttr); 177 178 ASMAtomicXchgU32(&pIntEventSem->u32State, EVENT_STATE_NOT_SIGNALED); 179 ASMAtomicXchgU32(&pIntEventSem->cWaiters, 0); 180 181 *pEventSem = pIntEventSem; 182 return VINF_SUCCESS; 183 } 184 pthread_mutexattr_destroy(&MutexAttr); 185 } 186 pthread_cond_destroy(&pIntEventSem->Cond); 98 pIntRWSem->uCheck = ~0; 99 pIntRWSem->WROwner = (pthread_t)-1; 100 *pRWSem = pIntRWSem; 101 return VINF_SUCCESS; 187 102 } 188 pthread_condattr_destroy(&CondAttr);189 103 } 190 104 191 105 rc = RTErrConvertFromErrno(rc); 192 RTMemFree(pInt EventSem);106 RTMemFree(pIntRWSem); 193 107 } 194 108 else … … 199 113 200 114 201 RTDECL(int) RTSemEventDestroy(RTSEMEVENT EventSem) 202 { 203 /* 204 * Validate handle. 205 */ 206 if (!rtsemEventValid(EventSem)) 207 { 208 AssertMsgFailed(("Invalid handle %p!\n", EventSem)); 209 return VERR_INVALID_HANDLE; 210 } 211 212 /* 213 * Abort all waiters forcing them to return failure. 214 * 215 */ 216 struct RTSEMEVENTINTERNAL *pIntEventSem = EventSem; 217 int rc; 218 for (int i = 30; i > 0; i--) 219 { 220 ASMAtomicXchgU32(&pIntEventSem->u32State, EVENT_STATE_UNINITIALIZED); 221 rc = pthread_cond_destroy(&pIntEventSem->Cond); 222 if (rc != EBUSY) 223 break; 224 pthread_cond_broadcast(&pIntEventSem->Cond); 225 usleep(1000); 226 } while (rc == EBUSY); 227 if (rc) 228 { 229 AssertMsgFailed(("Failed to destroy event sem %p, rc=%d.\n", EventSem, rc)); 230 return RTErrConvertFromErrno(rc); 231 } 232 233 /* 234 * Destroy the semaphore 235 * If it's busy we'll wait a bit to give the threads a chance to be scheduled. 236 */ 237 for (int i = 30; i > 0; i--) 238 { 239 rc = pthread_mutex_destroy(&pIntEventSem->Mutex); 240 if (rc != EBUSY) 241 break; 242 usleep(1000); 243 } 244 if (rc) 245 { 246 AssertMsgFailed(("Failed to destroy event sem %p, rc=%d. (mutex)\n", EventSem, rc)); 247 return RTErrConvertFromErrno(rc); 248 } 249 250 /* 251 * Free the semaphore memory and be gone. 252 */ 253 RTMemFree(pIntEventSem); 254 return VINF_SUCCESS; 255 } 256 257 258 RTDECL(int) RTSemEventSignal(RTSEMEVENT EventSem) 259 { 260 /* 261 * Validate input. 262 */ 263 if (!rtsemEventValid(EventSem)) 264 { 265 AssertMsgFailed(("Invalid handle %p!\n", EventSem)); 266 return VERR_INVALID_HANDLE; 267 } 268 269 /* 270 * Lock the mutex semaphore. 271 */ 272 struct RTSEMEVENTINTERNAL *pIntEventSem = EventSem; 273 int rc = pthread_mutex_lock(&pIntEventSem->Mutex); 274 if (rc) 275 { 276 AssertMsgFailed(("Failed to lock event sem %p, rc=%d.\n", EventSem, rc)); 277 return RTErrConvertFromErrno(rc); 278 } 279 280 /* 281 * Check the state. 282 */ 283 if (pIntEventSem->u32State == EVENT_STATE_NOT_SIGNALED) 284 { 285 ASMAtomicXchgU32(&pIntEventSem->u32State, EVENT_STATE_SIGNALED); 286 rc = pthread_cond_signal(&pIntEventSem->Cond); 287 AssertMsg(!rc, ("Failed to signal event sem %p, rc=%d.\n", EventSem, rc)); 288 } 289 else if (pIntEventSem->u32State == EVENT_STATE_SIGNALED) 290 { 291 rc = pthread_cond_signal(&pIntEventSem->Cond); /* give'm another kick... */ 292 AssertMsg(!rc, ("Failed to signal event sem %p, rc=%d. (2)\n", EventSem, rc)); 115 RTDECL(int) RTSemRWDestroy(RTSEMRW RWSem) 116 { 117 /* 118 * Validate input. 119 */ 120 if (!rtsemRWValid(RWSem)) 121 { 122 AssertMsgFailed(("Invalid handle %p!\n", RWSem)); 123 return VERR_INVALID_HANDLE; 124 } 125 126 /* 127 * Try destroy it. 128 */ 129 struct RTSEMRWINTERNAL *pIntRWSem = RWSem; 130 int rc = pthread_rwlock_destroy(&pIntRWSem->RWLock); 131 if (!rc) 132 { 133 pIntRWSem->uCheck = 0; 134 RTMemFree(pIntRWSem); 135 rc = VINF_SUCCESS; 293 136 } 294 137 else 295 rc = VERR_SEM_DESTROYED; 296 297 /* 298 * Release the mutex and return. 299 */ 300 int rc2 = pthread_mutex_unlock(&pIntEventSem->Mutex); 301 AssertMsg(!rc2, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc)); 302 if (rc) 303 return RTErrConvertFromErrno(rc); 304 if (rc2) 305 return RTErrConvertFromErrno(rc2); 306 307 return VINF_SUCCESS; 308 } 309 310 311 static int rtSemEventWait(RTSEMEVENT EventSem, unsigned cMillies, bool fAutoResume) 312 { 313 /* 314 * Validate input. 315 */ 316 if (!rtsemEventValid(EventSem)) 317 { 318 AssertMsgFailed(("Invalid handle %p!\n", EventSem)); 319 return VERR_INVALID_HANDLE; 320 } 321 322 /* 323 * Timed or indefinite wait? 324 */ 325 struct RTSEMEVENTINTERNAL *pIntEventSem = EventSem; 138 { 139 AssertMsgFailed(("Failed to destroy read-write sem %p, rc=%d.\n", RWSem, rc)); 140 rc = RTErrConvertFromErrno(rc); 141 } 142 143 return rc; 144 } 145 146 147 RTDECL(int) RTSemRWRequestRead(RTSEMRW RWSem, unsigned cMillies) 148 { 149 /* 150 * Validate input. 151 */ 152 if (!rtsemRWValid(RWSem)) 153 { 154 AssertMsgFailed(("Invalid handle %p!\n", RWSem)); 155 return VERR_INVALID_HANDLE; 156 } 157 158 /* 159 * Try lock it. 160 */ 161 struct RTSEMRWINTERNAL *pIntRWSem = RWSem; 326 162 if (cMillies == RT_INDEFINITE_WAIT) 327 163 { 328 /* for fairness, yield before going to sleep. */ 329 if ( ASMAtomicIncU32(&pIntEventSem->cWaiters) > 1 330 && pIntEventSem->u32State == EVENT_STATE_SIGNALED) 331 pthread_yield(); 332 333 /* take mutex */ 334 int rc = pthread_mutex_lock(&pIntEventSem->Mutex); 164 /* take rwlock */ 165 int rc = pthread_rwlock_rdlock(&pIntRWSem->RWLock); 335 166 if (rc) 336 167 { 337 ASMAtomicDecU32(&pIntEventSem->cWaiters); 338 AssertMsgFailed(("Failed to lock event sem %p, rc=%d.\n", EventSem, rc)); 339 return RTErrConvertFromErrno(rc); 340 } 341 342 for (;;) 343 { 344 /* check state. */ 345 if (pIntEventSem->u32State == EVENT_STATE_SIGNALED) 346 { 347 ASMAtomicXchgU32(&pIntEventSem->u32State, EVENT_STATE_NOT_SIGNALED); 348 ASMAtomicDecU32(&pIntEventSem->cWaiters); 349 rc = pthread_mutex_unlock(&pIntEventSem->Mutex); 350 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc)); NOREF(rc); 351 return VINF_SUCCESS; 352 } 353 if (pIntEventSem->u32State == EVENT_STATE_UNINITIALIZED) 354 { 355 rc = pthread_mutex_unlock(&pIntEventSem->Mutex); 356 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc)); NOREF(rc); 357 return VERR_SEM_DESTROYED; 358 } 359 360 /* wait */ 361 rc = pthread_cond_wait(&pIntEventSem->Cond, &pIntEventSem->Mutex); 362 if (rc) 363 { 364 AssertMsgFailed(("Failed to wait on event sem %p, rc=%d.\n", EventSem, rc)); 365 ASMAtomicDecU32(&pIntEventSem->cWaiters); 366 int rc2 = pthread_mutex_unlock(&pIntEventSem->Mutex); 367 AssertMsg(!rc2, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc2)); NOREF(rc2); 368 return RTErrConvertFromErrno(rc); 369 } 370 } 371 } 372 else 373 { 374 /* 375 * Get current time and calc end of wait time. 376 */ 377 struct timespec ts = {0,0}; 378 #ifdef RT_OS_DARWIN 379 struct timeval tv = {0,0}; 380 gettimeofday(&tv, NULL); 381 ts.tv_sec = tv.tv_sec; 382 ts.tv_nsec = tv.tv_usec * 1000; 383 #else 384 clock_gettime(CLOCK_REALTIME, &ts); 385 #endif 386 if (cMillies != 0) 387 { 388 ts.tv_nsec += (cMillies % 1000) * 1000000; 389 ts.tv_sec += cMillies / 1000; 390 if (ts.tv_nsec >= 1000000000) 391 { 392 ts.tv_nsec -= 1000000000; 393 ts.tv_sec++; 394 } 395 } 396 397 /* for fairness, yield before going to sleep. */ 398 if (ASMAtomicIncU32(&pIntEventSem->cWaiters) > 1) 399 pthread_yield(); 400 401 /* take mutex */ 402 #ifdef RT_OS_DARWIN 403 int rc = pthread_mutex_lock(&pIntEventSem->Mutex); 404 #else 405 int rc = pthread_mutex_timedlock(&pIntEventSem->Mutex, &ts); 406 #endif 407 if (rc) 408 { 409 ASMAtomicDecU32(&pIntEventSem->cWaiters); 410 AssertMsg(rc == ETIMEDOUT, ("Failed to lock event sem %p, rc=%d.\n", EventSem, rc)); 411 return RTErrConvertFromErrno(rc); 412 } 413 414 for (;;) 415 { 416 /* check state. */ 417 if (pIntEventSem->u32State == EVENT_STATE_SIGNALED) 418 { 419 ASMAtomicXchgU32(&pIntEventSem->u32State, EVENT_STATE_NOT_SIGNALED); 420 ASMAtomicDecU32(&pIntEventSem->cWaiters); 421 rc = pthread_mutex_unlock(&pIntEventSem->Mutex); 422 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc)); NOREF(rc); 423 return VINF_SUCCESS; 424 } 425 if (pIntEventSem->u32State == EVENT_STATE_UNINITIALIZED) 426 { 427 rc = pthread_mutex_unlock(&pIntEventSem->Mutex); 428 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc)); NOREF(rc); 429 return VERR_SEM_DESTROYED; 430 } 431 432 /* wait */ 433 rc = pthread_cond_timedwait(&pIntEventSem->Cond, &pIntEventSem->Mutex, &ts); 434 if (rc && (rc != EINTR || !fAutoResume)) /* according to SuS this function shall not return EINTR, but linux man page says differently. */ 435 { 436 AssertMsg(rc == ETIMEDOUT, ("Failed to wait on event sem %p, rc=%d.\n", EventSem, rc)); 437 ASMAtomicDecU32(&pIntEventSem->cWaiters); 438 int rc2 = pthread_mutex_unlock(&pIntEventSem->Mutex); 439 AssertMsg(!rc2, ("Failed to unlock event sem %p, rc2=%d.\n", EventSem, rc2)); NOREF(rc2); 440 return RTErrConvertFromErrno(rc); 441 } 442 } /* for (;;) */ 443 } 444 } 445 446 447 RTDECL(int) RTSemEventWait(RTSEMEVENT EventSem, unsigned cMillies) 448 { 449 int rc = rtSemEventWait(EventSem, cMillies, true); 450 Assert(rc != VERR_INTERRUPTED); 451 return rc; 452 } 453 454 455 RTDECL(int) RTSemEventWaitNoResume(RTSEMEVENT EventSem, unsigned cMillies) 456 { 457 return rtSemEventWait(EventSem, cMillies, false); 458 } 459 460 461 462 463 464 465 /** 466 * Validate an event multi semaphore handle passed to one of the interface. 467 * 468 * @returns true if valid. 469 * @returns false if invalid. 470 * @param pIntEventMultiSem Pointer to the event semaphore to validate. 471 */ 472 inline bool rtsemEventMultiValid(struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem) 473 { 474 if ((uintptr_t)pIntEventMultiSem < 0x10000) 475 return false; 476 477 uint32_t u32 = pIntEventMultiSem->u32State; /* this is volatile, so a explicit read like this is needed. */ 478 if ( u32 != EVENT_STATE_NOT_SIGNALED 479 && u32 != EVENT_STATE_SIGNALED) 480 return false; 481 482 return true; 483 } 484 485 486 RTDECL(int) RTSemEventMultiCreate(PRTSEMEVENTMULTI pEventMultiSem) 487 { 488 /* the code and the structure is identical with other type for this function. */ 489 return RTSemEventCreate((PRTSEMEVENT)pEventMultiSem); 490 } 491 492 493 RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI EventMultiSem) 494 { 495 /* the code and the structure is identical with other type for this function. */ 496 return RTSemEventDestroy((RTSEMEVENT)EventMultiSem); 497 } 498 499 500 RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI EventMultiSem) 501 { 502 /* the code and the structure is identical with other type for this function. */ 503 return RTSemEventSignal((RTSEMEVENT)EventMultiSem); 504 } 505 506 507 RTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI EventMultiSem) 508 { 509 /* 510 * Validate input. 511 */ 512 if (!rtsemEventMultiValid(EventMultiSem)) 513 { 514 AssertMsgFailed(("Invalid handle %p!\n", EventMultiSem)); 515 return VERR_INVALID_HANDLE; 516 } 517 518 /* 519 * Lock the mutex semaphore. 520 */ 521 struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem = EventMultiSem; 522 int rc = pthread_mutex_lock(&pIntEventMultiSem->Mutex); 523 if (rc) 524 { 525 AssertMsgFailed(("Failed to lock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); 526 return RTErrConvertFromErrno(rc); 527 } 528 529 /* 530 * Check the state. 531 */ 532 if (pIntEventMultiSem->u32State == EVENT_STATE_SIGNALED) 533 ASMAtomicXchgU32(&pIntEventMultiSem->u32State, EVENT_STATE_NOT_SIGNALED); 534 else if (pIntEventMultiSem->u32State != EVENT_STATE_NOT_SIGNALED) 535 rc = VERR_SEM_DESTROYED; 536 537 /* 538 * Release the mutex and return. 539 */ 540 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex); 541 if (rc) 542 { 543 AssertMsgFailed(("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); 544 return RTErrConvertFromErrno(rc); 545 } 546 547 return VINF_SUCCESS; 548 549 } 550 551 552 static int rtSemEventMultiWait(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies, bool fAutoResume) 553 { 554 /* 555 * Validate input. 556 */ 557 if (!rtsemEventMultiValid(EventMultiSem)) 558 { 559 AssertMsgFailed(("Invalid handle %p!\n", EventMultiSem)); 560 return VERR_INVALID_HANDLE; 561 } 562 563 /* 564 * Timed or indefinite wait? 565 */ 566 struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem = EventMultiSem; 567 if (cMillies == RT_INDEFINITE_WAIT) 568 { 569 /* take mutex */ 570 int rc = pthread_mutex_lock(&pIntEventMultiSem->Mutex); 571 if (rc) 572 { 573 AssertMsgFailed(("Failed to lock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); 574 return RTErrConvertFromErrno(rc); 575 } 576 ASMAtomicIncU32(&pIntEventMultiSem->cWaiters); 577 578 for (;;) 579 { 580 /* check state. */ 581 if (pIntEventMultiSem->u32State == EVENT_STATE_SIGNALED) 582 { 583 ASMAtomicDecU32(&pIntEventMultiSem->cWaiters); 584 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex); 585 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc); 586 return VINF_SUCCESS; 587 } 588 if (pIntEventMultiSem->u32State == EVENT_STATE_UNINITIALIZED) 589 { 590 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex); 591 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc); 592 return VERR_SEM_DESTROYED; 593 } 594 595 /* wait */ 596 rc = pthread_cond_wait(&pIntEventMultiSem->Cond, &pIntEventMultiSem->Mutex); 597 if (rc) 598 { 599 AssertMsgFailed(("Failed to wait on event multi sem %p, rc=%d.\n", EventMultiSem, rc)); 600 ASMAtomicDecU32(&pIntEventMultiSem->cWaiters); 601 int rc2 = pthread_mutex_unlock(&pIntEventMultiSem->Mutex); 602 AssertMsg(!rc2, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc2)); NOREF(rc2); 603 return RTErrConvertFromErrno(rc); 604 } 605 } 606 } 607 else 608 { 609 /* 610 * Get current time and calc end of wait time. 611 */ 612 struct timespec ts = {0,0}; 613 #ifdef RT_OS_DARWIN 614 struct timeval tv = {0,0}; 615 gettimeofday(&tv, NULL); 616 ts.tv_sec = tv.tv_sec; 617 ts.tv_nsec = tv.tv_usec * 1000; 618 #else 619 clock_gettime(CLOCK_REALTIME, &ts); 620 #endif 621 if (cMillies != 0) 622 { 623 ts.tv_nsec += (cMillies % 1000) * 1000000; 624 ts.tv_sec += cMillies / 1000; 625 if (ts.tv_nsec >= 1000000000) 626 { 627 ts.tv_nsec -= 1000000000; 628 ts.tv_sec++; 629 } 630 } 631 632 /* take mutex */ 633 #ifdef RT_OS_DARWIN 634 int rc = pthread_mutex_lock(&pIntEventMultiSem->Mutex); 635 #else 636 int rc = pthread_mutex_timedlock(&pIntEventMultiSem->Mutex, &ts); 637 #endif 638 if (rc) 639 { 640 AssertMsg(rc == ETIMEDOUT, ("Failed to lock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); 641 return RTErrConvertFromErrno(rc); 642 } 643 ASMAtomicIncU32(&pIntEventMultiSem->cWaiters); 644 645 for (;;) 646 { 647 /* check state. */ 648 if (pIntEventMultiSem->u32State == EVENT_STATE_SIGNALED) 649 { 650 ASMAtomicXchgU32(&pIntEventMultiSem->u32State, EVENT_STATE_NOT_SIGNALED); 651 ASMAtomicDecU32(&pIntEventMultiSem->cWaiters); 652 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex); 653 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc); 654 return VINF_SUCCESS; 655 } 656 if (pIntEventMultiSem->u32State == EVENT_STATE_UNINITIALIZED) 657 { 658 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex); 659 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc); 660 return VERR_SEM_DESTROYED; 661 } 662 663 /* wait */ 664 rc = pthread_cond_timedwait(&pIntEventMultiSem->Cond, &pIntEventMultiSem->Mutex, &ts); 665 if (rc && (rc != EINTR || !fAutoResume)) /* according to SuS this function shall not return EINTR, but linux man page says differently. */ 666 { 667 AssertMsg(rc == ETIMEDOUT, ("Failed to wait on event multi sem %p, rc=%d.\n", EventMultiSem, rc)); 668 ASMAtomicDecU32(&pIntEventMultiSem->cWaiters); 669 int rc2 = pthread_mutex_unlock(&pIntEventMultiSem->Mutex); 670 AssertMsg(!rc2, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc2)); NOREF(rc2); 671 return RTErrConvertFromErrno(rc); 672 } 673 } 674 } 675 } 676 677 678 RTDECL(int) RTSemEventMultiWait(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies) 679 { 680 int rc = rtSemEventMultiWait(EventMultiSem, cMillies, true); 681 Assert(rc != VERR_INTERRUPTED); 682 return rc; 683 } 684 685 686 RTDECL(int) RTSemEventMultiWaitNoResume(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies) 687 { 688 return rtSemEventMultiWait(EventMultiSem, cMillies, false); 689 } 690 691 692 693 694 695 /** 696 * Validate a Mutex semaphore handle passed to one of the interface. 697 * 698 * @returns true if valid. 699 * @returns false if invalid. 700 * @param pIntMutexSem Pointer to the mutex semaphore to validate. 701 */ 702 inline bool rtsemMutexValid(struct RTSEMMUTEXINTERNAL *pIntMutexSem) 703 { 704 if ((uintptr_t)pIntMutexSem < 0x10000) 705 return false; 706 707 if (pIntMutexSem->cNesting == (uint32_t)~0) 708 return false; 709 710 return true; 711 } 712 713 714 RTDECL(int) RTSemMutexCreate(PRTSEMMUTEX pMutexSem) 715 { 716 int rc; 717 718 /* 719 * Allocate semaphore handle. 720 */ 721 struct RTSEMMUTEXINTERNAL *pIntMutexSem = (struct RTSEMMUTEXINTERNAL *)RTMemAlloc(sizeof(struct RTSEMMUTEXINTERNAL)); 722 if (pIntMutexSem) 723 { 724 /* 725 * Create the semaphore. 726 */ 727 pthread_mutexattr_t MutexAttr; 728 rc = pthread_mutexattr_init(&MutexAttr); 729 if (!rc) 730 { 731 rc = pthread_mutex_init(&pIntMutexSem->Mutex, &MutexAttr); 732 if (!rc) 733 { 734 pthread_mutexattr_destroy(&MutexAttr); 735 736 pIntMutexSem->Owner = (pthread_t)-1; 737 pIntMutexSem->cNesting = 0; 738 739 *pMutexSem = pIntMutexSem; 740 return VINF_SUCCESS; 741 } 742 pthread_mutexattr_destroy(&MutexAttr); 743 } 744 RTMemFree(pIntMutexSem); 745 } 746 else 747 rc = VERR_NO_MEMORY; 748 749 return rc; 750 } 751 752 753 RTDECL(int) RTSemMutexDestroy(RTSEMMUTEX MutexSem) 754 { 755 /* 756 * Validate input. 757 */ 758 if (!rtsemMutexValid(MutexSem)) 759 { 760 AssertMsgFailed(("Invalid handle %p!\n", MutexSem)); 761 return VERR_INVALID_HANDLE; 762 } 763 764 /* 765 * Try destroy it. 766 */ 767 struct RTSEMMUTEXINTERNAL *pIntMutexSem = MutexSem; 768 int rc = pthread_mutex_destroy(&pIntMutexSem->Mutex); 769 if (rc) 770 { 771 AssertMsgFailed(("Failed to destroy mutex sem %p, rc=%d.\n", MutexSem, rc)); 772 return RTErrConvertFromErrno(rc); 773 } 774 775 /* 776 * Free the memory and be gone. 777 */ 778 pIntMutexSem->Owner = (pthread_t)-1; 779 pIntMutexSem->cNesting = ~0; 780 RTMemTmpFree(pIntMutexSem); 781 782 return VINF_SUCCESS; 783 } 784 785 786 RTDECL(int) RTSemMutexRequest(RTSEMMUTEX MutexSem, unsigned cMillies) 787 { 788 /* 789 * Validate input. 790 */ 791 if (!rtsemMutexValid(MutexSem)) 792 { 793 AssertMsgFailed(("Invalid handle %p!\n", MutexSem)); 794 return VERR_INVALID_HANDLE; 795 } 796 797 /* 798 * Check if nested request. 799 */ 800 pthread_t Self = pthread_self(); 801 struct RTSEMMUTEXINTERNAL *pIntMutexSem = MutexSem; 802 if ( pIntMutexSem->Owner == Self 803 && pIntMutexSem->cNesting > 0) 804 { 805 pIntMutexSem->cNesting++; 806 return VINF_SUCCESS; 807 } 808 809 /* 810 * Lock it. 811 */ 812 if (cMillies == RT_INDEFINITE_WAIT) 813 { 814 /* take mutex */ 815 int rc = pthread_mutex_lock(&pIntMutexSem->Mutex); 816 if (rc) 817 { 818 AssertMsgFailed(("Failed to lock mutex sem %p, rc=%d.\n", MutexSem, rc)); NOREF(rc); 168 AssertMsgFailed(("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc)); 819 169 return RTErrConvertFromErrno(rc); 820 170 } … … 842 192 } 843 193 844 /* take mutex*/845 int rc = pthread_ mutex_timedlock(&pIntMutexSem->Mutex, &ts);194 /* take rwlock */ 195 int rc = pthread_rwlock_timedrdlock(&pIntRWSem->RWLock, &ts); 846 196 if (rc) 847 197 { 848 AssertMsg(rc == ETIMEDOUT, ("Failed to lock mutex sem %p, rc=%d.\n", MutexSem, rc)); NOREF(rc);198 AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc)); 849 199 return RTErrConvertFromErrno(rc); 850 200 } … … 852 202 } 853 203 854 /*855 * Set the owner and nesting.856 */857 pIntMutexSem->Owner = Self;858 ASMAtomicXchgU32(&pIntMutexSem->cNesting, 1);859 860 204 return VINF_SUCCESS; 861 205 } 862 206 863 207 864 RTDECL(int) RTSemMutexRequestNoResume(RTSEMMUTEX MutexSem, unsigned cMillies)208 RTDECL(int) RTSemRWRequestReadNoResume(RTSEMRW RWSem, unsigned cMillies) 865 209 { 866 210 /* EINTR isn't returned by the wait functions we're using. */ 867 return RTSemMutexRequest(MutexSem, cMillies); 868 } 869 870 871 RTDECL(int) RTSemMutexRelease(RTSEMMUTEX MutexSem) 872 { 873 /* 874 * Validate input. 875 */ 876 if (!rtsemMutexValid(MutexSem)) 877 { 878 AssertMsgFailed(("Invalid handle %p!\n", MutexSem)); 879 return VERR_INVALID_HANDLE; 880 } 881 882 /* 883 * Check if nested. 884 */ 885 pthread_t Self = pthread_self(); 886 struct RTSEMMUTEXINTERNAL *pIntMutexSem = MutexSem; 887 if ( pIntMutexSem->Owner != Self 888 || pIntMutexSem->cNesting == (uint32_t)~0) 889 { 890 AssertMsgFailed(("Not owner of mutex %p!! Self=%08x Owner=%08x cNesting=%d\n", 891 pIntMutexSem, Self, pIntMutexSem->Owner, pIntMutexSem->cNesting)); 211 return RTSemRWRequestRead(RWSem, cMillies); 212 } 213 214 215 RTDECL(int) RTSemRWReleaseRead(RTSEMRW RWSem) 216 { 217 /* 218 * Validate input. 219 */ 220 if (!rtsemRWValid(RWSem)) 221 { 222 AssertMsgFailed(("Invalid handle %p!\n", RWSem)); 223 return VERR_INVALID_HANDLE; 224 } 225 226 /* 227 * Try unlock it. 228 */ 229 struct RTSEMRWINTERNAL *pIntRWSem = RWSem; 230 if (pIntRWSem->WROwner == pthread_self()) 231 { 232 AssertMsgFailed(("Tried to read unlock when write owner - read-write sem %p.\n", RWSem)); 892 233 return VERR_NOT_OWNER; 893 234 } 894 895 /* 896 * If nested we'll just pop a nesting. 897 */ 898 if (pIntMutexSem->cNesting > 1) 899 { 900 pIntMutexSem->cNesting--; 901 return VINF_SUCCESS; 902 } 903 904 /* 905 * Clear the state. (cNesting == 1) 906 */ 907 pIntMutexSem->Owner = (pthread_t)-1; 908 ASMAtomicXchgU32(&pIntMutexSem->cNesting, 0); 909 910 /* 911 * Unlock mutex semaphore. 912 */ 913 int rc = pthread_mutex_unlock(&pIntMutexSem->Mutex); 235 int rc = pthread_rwlock_unlock(&pIntRWSem->RWLock); 914 236 if (rc) 915 237 { 916 AssertMsgFailed(("Failed to unlock mutex sem %p, rc=%d.\n", MutexSem, rc)); NOREF(rc);238 AssertMsgFailed(("Failed read unlock read-write sem %p, rc=%d.\n", RWSem, rc)); 917 239 return RTErrConvertFromErrno(rc); 918 240 } … … 922 244 923 245 924 925 926 927 /** 928 * Validate a read-write semaphore handle passed to one of the interface. 929 * 930 * @returns true if valid. 931 * @returns false if invalid. 932 * @param pIntRWSem Pointer to the read-write semaphore to validate. 933 */ 934 inline bool rtsemRWValid(struct RTSEMRWINTERNAL *pIntRWSem) 935 { 936 if ((uintptr_t)pIntRWSem < 0x10000) 937 return false; 938 939 if (pIntRWSem->uCheck != (unsigned)~0) 940 return false; 941 942 return true; 943 } 944 945 946 RTDECL(int) RTSemRWCreate(PRTSEMRW pRWSem) 947 { 948 int rc; 949 950 /* 951 * Allocate handle. 952 */ 953 struct RTSEMRWINTERNAL *pIntRWSem = (struct RTSEMRWINTERNAL *)RTMemAlloc(sizeof(struct RTSEMRWINTERNAL)); 954 if (pIntRWSem) 955 { 956 /* 957 * Create the rwlock. 958 */ 959 pthread_rwlockattr_t Attr; 960 rc = pthread_rwlockattr_init(&Attr); 961 if (!rc) 962 { 963 rc = pthread_rwlock_init(&pIntRWSem->RWLock, &Attr); 964 if (!rc) 965 { 966 pIntRWSem->uCheck = ~0; 967 pIntRWSem->WROwner = (pthread_t)-1; 968 *pRWSem = pIntRWSem; 969 return VINF_SUCCESS; 970 } 971 } 972 973 rc = RTErrConvertFromErrno(rc); 974 RTMemFree(pIntRWSem); 975 } 976 else 977 rc = VERR_NO_MEMORY; 978 979 return rc; 980 } 981 982 983 RTDECL(int) RTSemRWDestroy(RTSEMRW RWSem) 984 { 985 /* 986 * Validate input. 987 */ 988 if (!rtsemRWValid(RWSem)) 989 { 990 AssertMsgFailed(("Invalid handle %p!\n", RWSem)); 991 return VERR_INVALID_HANDLE; 992 } 993 994 /* 995 * Try destroy it. 996 */ 997 struct RTSEMRWINTERNAL *pIntRWSem = RWSem; 998 int rc = pthread_rwlock_destroy(&pIntRWSem->RWLock); 999 if (!rc) 1000 { 1001 pIntRWSem->uCheck = 0; 1002 RTMemFree(pIntRWSem); 1003 rc = VINF_SUCCESS; 1004 } 1005 else 1006 { 1007 AssertMsgFailed(("Failed to destroy read-write sem %p, rc=%d.\n", RWSem, rc)); 1008 rc = RTErrConvertFromErrno(rc); 1009 } 1010 1011 return rc; 1012 } 1013 1014 1015 RTDECL(int) RTSemRWRequestRead(RTSEMRW RWSem, unsigned cMillies) 246 RTDECL(int) RTSemRWRequestWrite(RTSEMRW RWSem, unsigned cMillies) 1016 247 { 1017 248 /* … … 1031 262 { 1032 263 /* take rwlock */ 1033 int rc = pthread_rwlock_ rdlock(&pIntRWSem->RWLock);264 int rc = pthread_rwlock_wrlock(&pIntRWSem->RWLock); 1034 265 if (rc) 1035 266 { 1036 AssertMsgFailed(("Failed readlock read-write sem %p, rc=%d.\n", RWSem, rc));267 AssertMsgFailed(("Failed write lock read-write sem %p, rc=%d.\n", RWSem, rc)); 1037 268 return RTErrConvertFromErrno(rc); 1038 269 } … … 1061 292 1062 293 /* take rwlock */ 1063 int rc = pthread_rwlock_timedrdlock(&pIntRWSem->RWLock, &ts);1064 if (rc)1065 {1066 AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));1067 return RTErrConvertFromErrno(rc);1068 }1069 #endif /* !RT_OS_DARWIN */1070 }1071 1072 return VINF_SUCCESS;1073 }1074 1075 1076 RTDECL(int) RTSemRWRequestReadNoResume(RTSEMRW RWSem, unsigned cMillies)1077 {1078 /* EINTR isn't returned by the wait functions we're using. */1079 return RTSemRWRequestRead(RWSem, cMillies);1080 }1081 1082 1083 RTDECL(int) RTSemRWReleaseRead(RTSEMRW RWSem)1084 {1085 /*1086 * Validate input.1087 */1088 if (!rtsemRWValid(RWSem))1089 {1090 AssertMsgFailed(("Invalid handle %p!\n", RWSem));1091 return VERR_INVALID_HANDLE;1092 }1093 1094 /*1095 * Try unlock it.1096 */1097 struct RTSEMRWINTERNAL *pIntRWSem = RWSem;1098 if (pIntRWSem->WROwner == pthread_self())1099 {1100 AssertMsgFailed(("Tried to read unlock when write owner - read-write sem %p.\n", RWSem));1101 return VERR_NOT_OWNER;1102 }1103 int rc = pthread_rwlock_unlock(&pIntRWSem->RWLock);1104 if (rc)1105 {1106 AssertMsgFailed(("Failed read unlock read-write sem %p, rc=%d.\n", RWSem, rc));1107 return RTErrConvertFromErrno(rc);1108 }1109 1110 return VINF_SUCCESS;1111 }1112 1113 1114 RTDECL(int) RTSemRWRequestWrite(RTSEMRW RWSem, unsigned cMillies)1115 {1116 /*1117 * Validate input.1118 */1119 if (!rtsemRWValid(RWSem))1120 {1121 AssertMsgFailed(("Invalid handle %p!\n", RWSem));1122 return VERR_INVALID_HANDLE;1123 }1124 1125 /*1126 * Try lock it.1127 */1128 struct RTSEMRWINTERNAL *pIntRWSem = RWSem;1129 if (cMillies == RT_INDEFINITE_WAIT)1130 {1131 /* take rwlock */1132 int rc = pthread_rwlock_wrlock(&pIntRWSem->RWLock);1133 if (rc)1134 {1135 AssertMsgFailed(("Failed write lock read-write sem %p, rc=%d.\n", RWSem, rc));1136 return RTErrConvertFromErrno(rc);1137 }1138 }1139 else1140 {1141 #ifdef RT_OS_DARWIN1142 AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));1143 return VERR_NOT_IMPLEMENTED;1144 #else /* !RT_OS_DARWIN */1145 /*1146 * Get current time and calc end of wait time.1147 */1148 struct timespec ts = {0,0};1149 clock_gettime(CLOCK_REALTIME, &ts);1150 if (cMillies != 0)1151 {1152 ts.tv_nsec += (cMillies % 1000) * 1000000;1153 ts.tv_sec += cMillies / 1000;1154 if (ts.tv_nsec >= 1000000000)1155 {1156 ts.tv_nsec -= 1000000000;1157 ts.tv_sec++;1158 }1159 }1160 1161 /* take rwlock */1162 294 int rc = pthread_rwlock_timedwrlock(&pIntRWSem->RWLock, &ts); 1163 295 if (rc)
Note:
See TracChangeset
for help on using the changeset viewer.