RTDECL(int) RTSemEventMultiWait(RTSEMEVENTMULTI EventSem, RTMSINTERVAL cMillies) { int rc; if (cMillies == RT_INDEFINITE_WAIT) { do rc = RTSemEventMultiWaitNoResume(EventSem, cMillies); while (rc == VERR_INTERRUPTED); } else { const uint64_t u64Start = RTTimeMilliTS(); rc = RTSemEventMultiWaitNoResume(EventSem, cMillies); if (rc == VERR_INTERRUPTED) { do { uint64_t u64Elapsed = RTTimeMilliTS() - u64Start; if (u64Elapsed >= cMillies) return VERR_TIMEOUT; rc = RTSemEventMultiWaitNoResume(EventSem, cMillies - (RTMSINTERVAL)u64Elapsed); } while (rc == VERR_INTERRUPTED); } } return rc; }
static void testBasicsWaitSuccess(RTSEMEVENTMULTI hSem, unsigned i) { RTTESTI_CHECK_RC_RETV(RTSemEventMultiWait(hSem, 0), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTSemEventMultiWait(hSem, RT_INDEFINITE_WAIT), VINF_SUCCESS); #if 0 RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitNoResume(hSem, 0), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitNoResume(hSem, RT_INDEFINITE_WAIT), VINF_SUCCESS); #else RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem, RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_RELATIVE, 0), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem, RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_INDEFINITE, 0), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem, RTSEMWAIT_FLAGS_NORESUME | RTSEMWAIT_FLAGS_INDEFINITE, 0), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem, RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_ABSOLUTE, RTTimeSystemNanoTS() + 1000*i), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem, RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_ABSOLUTE, RTTimeNanoTS() + 1000*i), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem, RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_ABSOLUTE, 0), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem, RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_ABSOLUTE, _1G), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem, RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_ABSOLUTE, UINT64_MAX), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem, RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_MILLISECS | RTSEMWAIT_FLAGS_ABSOLUTE, RTTimeSystemMilliTS() + 1000*i), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem, RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_MILLISECS | RTSEMWAIT_FLAGS_ABSOLUTE, RTTimeMilliTS() + 1000*i), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem, RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_MILLISECS | RTSEMWAIT_FLAGS_ABSOLUTE, 0), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem, RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_MILLISECS | RTSEMWAIT_FLAGS_ABSOLUTE, _1M), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem, RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_MILLISECS | RTSEMWAIT_FLAGS_ABSOLUTE, UINT64_MAX), VINF_SUCCESS); #endif }
static void testBasicsWaitTimeout(RTSEMEVENTMULTI hSem, unsigned i) { RTTESTI_CHECK_RC_RETV(RTSemEventMultiWait(hSem, 0), VERR_TIMEOUT); #if 0 RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitNoResume(hSem, 0), VERR_TIMEOUT); #else RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem, RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_RELATIVE, 0), VERR_TIMEOUT); RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem, RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_ABSOLUTE, RTTimeSystemNanoTS() + 1000*i), VERR_TIMEOUT); RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem, RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_ABSOLUTE, RTTimeNanoTS() + 1000*i), VERR_TIMEOUT); RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem, RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_MILLISECS | RTSEMWAIT_FLAGS_RELATIVE, 0), VERR_TIMEOUT); #endif }
/** * Wait for the user event, return on interruption. * * @returns iprt status code. * @param Thread The thread to wait for. * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for * an indefinite wait. */ RTDECL(int) RTThreadUserWaitNoResume(RTTHREAD Thread, RTMSINTERVAL cMillies) { int rc; PRTTHREADINT pThread = rtThreadGet(Thread); if (pThread) { rc = RTSemEventMultiWaitNoResume(pThread->EventUser, cMillies); rtThreadRelease(pThread); } else rc = VERR_INVALID_HANDLE; return rc; }
/** * Wait for the thread to terminate. * * @returns iprt status code. * @param Thread The thread to wait for. * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for * an indefinite wait. * @param prc Where to store the return code of the thread. Optional. * @param fAutoResume Whether or not to resume the wait on VERR_INTERRUPTED. */ static int rtThreadWait(RTTHREAD Thread, RTMSINTERVAL cMillies, int *prc, bool fAutoResume) { int rc = VERR_INVALID_HANDLE; if (Thread != NIL_RTTHREAD) { PRTTHREADINT pThread = rtThreadGet(Thread); if (pThread) { if (pThread->fFlags & RTTHREADFLAGS_WAITABLE) { if (fAutoResume) rc = RTSemEventMultiWait(pThread->EventTerminated, cMillies); else rc = RTSemEventMultiWaitNoResume(pThread->EventTerminated, cMillies); if (RT_SUCCESS(rc)) { if (prc) *prc = pThread->rc; /* * If the thread is marked as waitable, we'll do one additional * release in order to free up the thread structure (see how we * init cRef in rtThreadAlloc()). */ if (ASMAtomicBitTestAndClear(&pThread->fFlags, RTTHREADFLAGS_WAITABLE_BIT)) { rtThreadRelease(pThread); #ifdef IN_RING0 /* * IPRT termination kludge. Call native code to make sure * the last thread is really out of IPRT to prevent it from * crashing after we destroyed the spinlock in rtThreadTerm. */ if ( ASMAtomicReadU32(&g_cThreadInTree) == 1 && ASMAtomicReadU32(&pThread->cRefs) > 1) rtThreadNativeWaitKludge(pThread); #endif } } } else { rc = VERR_THREAD_NOT_WAITABLE; AssertRC(rc); } rtThreadRelease(pThread); } } return rc; }
/** * Called by the PDM thread instead of RTThreadSleep. * * The difference is that the sleep will be interrupted on state change. The * thread must be in the running state, otherwise it will return immediately. * * @returns VBox status code. * @retval VINF_SUCCESS on success or state change. * @retval VERR_INTERRUPTED on signal or APC. * * @param pThread The PDM thread. * @param cMillies The number of milliseconds to sleep. */ VMMR3DECL(int) PDMR3ThreadSleep(PPDMTHREAD pThread, RTMSINTERVAL cMillies) { /* * Assert sanity. */ AssertReturn(pThread->enmState > PDMTHREADSTATE_INVALID && pThread->enmState < PDMTHREADSTATE_TERMINATED, VERR_PDM_THREAD_IPE_2); AssertReturn(pThread->Thread == RTThreadSelf(), VERR_PDM_THREAD_INVALID_CALLER); /* * Reset the event semaphore, check the state and sleep. */ RTSemEventMultiReset(pThread->Internal.s.SleepEvent); if (pThread->enmState != PDMTHREADSTATE_RUNNING) return VINF_SUCCESS; return RTSemEventMultiWaitNoResume(pThread->Internal.s.SleepEvent, cMillies); }
/** * Wait for the thread to terminate. * * @returns iprt status code. * @param Thread The thread to wait for. * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for * an indefinite wait. * @param prc Where to store the return code of the thread. Optional. * @param fAutoResume Whether or not to resume the wait on VERR_INTERRUPTED. */ static int rtThreadWait(RTTHREAD Thread, RTMSINTERVAL cMillies, int *prc, bool fAutoResume) { int rc = VERR_INVALID_HANDLE; if (Thread != NIL_RTTHREAD) { PRTTHREADINT pThread = rtThreadGet(Thread); if (pThread) { if (pThread->fFlags & RTTHREADFLAGS_WAITABLE) { if (fAutoResume) rc = RTSemEventMultiWait(pThread->EventTerminated, cMillies); else rc = RTSemEventMultiWaitNoResume(pThread->EventTerminated, cMillies); if (RT_SUCCESS(rc)) { if (prc) *prc = pThread->rc; /* * If the thread is marked as waitable, we'll do one additional * release in order to free up the thread structure (see how we * init cRef in rtThreadAlloc()). */ if (ASMAtomicBitTestAndClear(&pThread->fFlags, RTTHREADFLAGS_WAITABLE_BIT)) rtThreadRelease(pThread); } } else { rc = VERR_THREAD_NOT_WAITABLE; AssertRC(rc); } rtThreadRelease(pThread); } } return rc; }
DECL_FORCE_INLINE(int) rtSemRWRequestRead(RTSEMRW hRWSem, RTMSINTERVAL cMillies, bool fInterruptible, PCRTLOCKVALSRCPOS pSrcPos) { /* * Validate handle. */ struct RTSEMRWINTERNAL *pThis = hRWSem; AssertPtrReturn(pThis, VERR_INVALID_HANDLE); AssertReturn(pThis->u32Magic == RTSEMRW_MAGIC, VERR_INVALID_HANDLE); RTMSINTERVAL cMilliesInitial = cMillies; uint64_t tsStart = 0; if (cMillies != RT_INDEFINITE_WAIT && cMillies != 0) tsStart = RTTimeNanoTS(); #ifdef RTSEMRW_STRICT RTTHREAD hThreadSelf = RTThreadSelfAutoAdopt(); if (cMillies > 0) { int rc9; if (pThis->hWriter != NIL_RTTHREAD && pThis->hWriter == RTThreadNativeSelf()) rc9 = RTLockValidatorRecExclCheckOrder(&pThis->ValidatorWrite, hThreadSelf, pSrcPos, cMillies); else rc9 = RTLockValidatorRecSharedCheckOrder(&pThis->ValidatorRead, hThreadSelf, pSrcPos, cMillies); if (RT_FAILURE(rc9)) return rc9; } #endif /* * Take critsect. */ int rc = RTCritSectEnter(&pThis->CritSect); if (RT_FAILURE(rc)) { AssertMsgFailed(("RTCritSectEnter failed on rwsem %p, rc=%Rrc\n", hRWSem, rc)); return rc; } /* * Check if the state of affairs allows read access. * Do not block further readers if there is a writer waiting, as * that will break/deadlock reader recursion. */ if ( pThis->hWriter == NIL_RTNATIVETHREAD #if 0 && ( !pThis->cWritesWaiting || pThis->cReads) #endif ) { pThis->cReads++; Assert(pThis->cReads > 0); #ifdef RTSEMRW_STRICT RTLockValidatorRecSharedAddOwner(&pThis->ValidatorRead, hThreadSelf, pSrcPos); #endif RTCritSectLeave(&pThis->CritSect); return VINF_SUCCESS; } RTNATIVETHREAD hNativeSelf = pThis->CritSect.NativeThreadOwner; if (pThis->hWriter == hNativeSelf) { #ifdef RTSEMRW_STRICT int rc9 = RTLockValidatorRecExclRecursionMixed(&pThis->ValidatorWrite, &pThis->ValidatorRead.Core, pSrcPos); if (RT_FAILURE(rc9)) { RTCritSectLeave(&pThis->CritSect); return rc9; } #endif pThis->cWriterReads++; Assert(pThis->cWriterReads > 0); RTCritSectLeave(&pThis->CritSect); return VINF_SUCCESS; } RTCritSectLeave(&pThis->CritSect); /* * Wait till it's ready for reading. */ if (cMillies == 0) return VERR_TIMEOUT; #ifndef RTSEMRW_STRICT RTTHREAD hThreadSelf = RTThreadSelf(); #endif for (;;) { if (cMillies != RT_INDEFINITE_WAIT) { int64_t tsDelta = RTTimeNanoTS() - tsStart; if (tsDelta >= 1000000) { tsDelta /= 1000000; if ((uint64_t)tsDelta < cMilliesInitial) cMilliesInitial = (RTMSINTERVAL)tsDelta; else cMilliesInitial = 1; } } #ifdef RTSEMRW_STRICT rc = RTLockValidatorRecSharedCheckBlocking(&pThis->ValidatorRead, hThreadSelf, pSrcPos, true, cMillies, RTTHREADSTATE_RW_READ, false); if (RT_FAILURE(rc)) break; #else RTThreadBlocking(hThreadSelf, RTTHREADSTATE_RW_READ, false); #endif int rcWait; if (fInterruptible) rcWait = rc = RTSemEventMultiWaitNoResume(pThis->ReadEvent, cMillies); else rcWait = rc = RTSemEventMultiWait(pThis->ReadEvent, cMillies); RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_RW_READ); if (RT_FAILURE(rc) && rc != VERR_TIMEOUT) /* handle timeout below */ { AssertMsgRC(rc, ("RTSemEventMultiWait failed on rwsem %p, rc=%Rrc\n", hRWSem, rc)); break; } if (pThis->u32Magic != RTSEMRW_MAGIC) { rc = VERR_SEM_DESTROYED; break; } /* * Re-take critsect and repeat the check we did before the loop. */ rc = RTCritSectEnter(&pThis->CritSect); if (RT_FAILURE(rc)) { AssertMsgFailed(("RTCritSectEnter failed on rwsem %p, rc=%Rrc\n", hRWSem, rc)); break; } if ( pThis->hWriter == NIL_RTNATIVETHREAD #if 0 && ( !pThis->cWritesWaiting || pThis->cReads) #endif ) { pThis->cReads++; Assert(pThis->cReads > 0); #ifdef RTSEMRW_STRICT RTLockValidatorRecSharedAddOwner(&pThis->ValidatorRead, hThreadSelf, pSrcPos); #endif RTCritSectLeave(&pThis->CritSect); return VINF_SUCCESS; } RTCritSectLeave(&pThis->CritSect); /* * Quit if the wait already timed out. */ if (rcWait == VERR_TIMEOUT) { rc = VERR_TIMEOUT; break; } } /* failed */ return rc; }