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 DECLCALLBACK(int) test1Thread1(RTTHREAD ThreadSelf, void *pvUser) { RTSEMEVENTMULTI hSem = *(PRTSEMEVENTMULTI)pvUser; uint64_t u64 = RTTimeSystemMilliTS(); RTTEST_CHECK_RC(g_hTest, RTSemEventMultiWait(hSem, 1000), VERR_TIMEOUT); u64 = RTTimeSystemMilliTS() - u64; RTTEST_CHECK_MSG(g_hTest, u64 < 1500 && u64 > 950, (g_hTest, "u64=%llu\n", u64)); RTTEST_CHECK_RC(g_hTest, RTSemEventMultiWait(hSem, 2000), VINF_SUCCESS); return VINF_SUCCESS; }
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 }
/** * Called by the PDM thread in response to a wakeup call with * suspending as the new state. * * The thread will block in side this call until the state is changed in * response to a VM state change or to the device/driver/whatever calling the * PDMR3ThreadResume API. * * @returns VBox status code. * On failure, terminate the thread. * @param pThread The PDM thread. */ VMMR3DECL(int) PDMR3ThreadIAmSuspending(PPDMTHREAD pThread) { /* * Assert sanity. */ AssertPtr(pThread); AssertReturn(pThread->u32Version == PDMTHREAD_VERSION, VERR_INVALID_MAGIC); Assert(pThread->Thread == RTThreadSelf() || pThread->enmState == PDMTHREADSTATE_INITIALIZING); PDMTHREADSTATE enmState = pThread->enmState; Assert( enmState == PDMTHREADSTATE_SUSPENDING || enmState == PDMTHREADSTATE_INITIALIZING); /* * Update the state, notify the control thread (the API caller) and go to sleep. */ int rc = VERR_WRONG_ORDER; if (pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_SUSPENDED, enmState)) { rc = RTThreadUserSignal(pThread->Thread); if (RT_SUCCESS(rc)) { rc = RTSemEventMultiWait(pThread->Internal.s.BlockEvent, RT_INDEFINITE_WAIT); if ( RT_SUCCESS(rc) && pThread->enmState != PDMTHREADSTATE_SUSPENDED) return rc; if (RT_SUCCESS(rc)) rc = VERR_PDM_THREAD_IPE_2; } } AssertMsgFailed(("rc=%d enmState=%d\n", rc, pThread->enmState)); pdmR3ThreadBailMeOut(pThread); return rc; }
/** * Place an entry in an mbox. */ void sys_mbox_post(sys_mbox_t mbox, void *msg) { int rc; Assert(mbox != NULL); rc = LWIPMutexRequest(mbox->mutex, RT_INDEFINITE_WAIT); AssertRC(rc); while ((mbox->head + 1) % MBOX_ENTRIES_MAX == mbox->tail) { /* mbox is full, have to wait until a slot becomes available. */ rc = LWIPMutexRelease(mbox->mutex); AssertRC(rc); rc = RTSemEventMultiWait(mbox->nonfull, RT_INDEFINITE_WAIT); AssertRC(rc); rc = LWIPMutexRequest(mbox->mutex, RT_INDEFINITE_WAIT); AssertRC(rc); } if (mbox->head == mbox->tail) { rc = RTSemEventMultiSignal(mbox->nonempty); AssertRC(rc); } mbox->apvEntries[mbox->head] = msg; mbox->head++; mbox->head %= MBOX_ENTRIES_MAX; if ((mbox->head + 1) % MBOX_ENTRIES_MAX == mbox->tail) { rc = RTSemEventMultiReset(mbox->nonfull); AssertRC(rc); } rc = LWIPMutexRelease(mbox->mutex); AssertRC(rc); }
static DECLCALLBACK(int) test1Thread2(RTTHREAD ThreadSelf, void *pvUser) { RTSEMEVENTMULTI hSem = *(PRTSEMEVENTMULTI)pvUser; RT_NOREF_PV(ThreadSelf); RTTEST_CHECK_RC(g_hTest, RTSemEventMultiWait(hSem, RT_INDEFINITE_WAIT), VINF_SUCCESS); return VINF_SUCCESS; }
/** * @note XPCOM: when this method is not called on the main XPCOM thread, it * simply blocks the thread until mCompletedSem is signalled. If the * thread has its own event queue (hmm, what for?) that it must run, then * calling this method will definitely freeze event processing. */ STDMETHODIMP Progress::WaitForOperationCompletion(ULONG aOperation, LONG aTimeout) { LogFlowThisFuncEnter(); LogFlowThisFunc(("aOperation=%d, aTimeout=%d\n", aOperation, aTimeout)); AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); CheckComArgExpr(aOperation, aOperation < m_cOperations); /* if we're already completed or if the given operation is already done, * then take a shortcut */ if ( !mCompleted && aOperation >= m_ulCurrentOperation) { int vrc = VINF_SUCCESS; bool fForever = aTimeout < 0; int64_t timeLeft = aTimeout; int64_t lastTime = RTTimeMilliTS(); while ( !mCompleted && aOperation >= m_ulCurrentOperation && (fForever || timeLeft > 0)) { mWaitersCount ++; alock.release(); vrc = RTSemEventMultiWait(mCompletedSem, fForever ? RT_INDEFINITE_WAIT : (unsigned) timeLeft); alock.acquire(); mWaitersCount--; /* the last waiter resets the semaphore */ if (mWaitersCount == 0) RTSemEventMultiReset(mCompletedSem); if (RT_FAILURE(vrc) && vrc != VERR_TIMEOUT) break; if (!fForever) { int64_t now = RTTimeMilliTS(); timeLeft -= now - lastTime; lastTime = now; } } if (RT_FAILURE(vrc) && vrc != VERR_TIMEOUT) return setError(E_FAIL, tr("Failed to wait for the operation completion (%Rrc)"), vrc); } LogFlowThisFuncLeave(); return S_OK; }
/** * @note XPCOM: when this method is not called on the main XPCOM thread, it * simply blocks the thread until mCompletedSem is signalled. If the * thread has its own event queue (hmm, what for?) that it must run, then * calling this method will definitely freeze event processing. */ STDMETHODIMP Progress::WaitForCompletion(LONG aTimeout) { LogFlowThisFuncEnter(); LogFlowThisFunc(("aTimeout=%d\n", aTimeout)); AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); /* if we're already completed, take a shortcut */ if (!mCompleted) { int vrc = VINF_SUCCESS; bool fForever = aTimeout < 0; int64_t timeLeft = aTimeout; int64_t lastTime = RTTimeMilliTS(); while (!mCompleted && (fForever || timeLeft > 0)) { mWaitersCount++; alock.release(); vrc = RTSemEventMultiWait(mCompletedSem, fForever ? RT_INDEFINITE_WAIT : (RTMSINTERVAL)timeLeft); alock.acquire(); mWaitersCount--; /* the last waiter resets the semaphore */ if (mWaitersCount == 0) RTSemEventMultiReset(mCompletedSem); if (RT_FAILURE(vrc) && vrc != VERR_TIMEOUT) break; if (!fForever) { int64_t now = RTTimeMilliTS(); timeLeft -= now - lastTime; lastTime = now; } } if (RT_FAILURE(vrc) && vrc != VERR_TIMEOUT) return setError(VBOX_E_IPRT_ERROR, tr("Failed to wait for the task completion (%Rrc)"), vrc); } LogFlowThisFuncLeave(); return S_OK; }
/** * Wait for the user event, resume 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) RTThreadUserWait(RTTHREAD Thread, RTMSINTERVAL cMillies) { int rc; PRTTHREADINT pThread = rtThreadGet(Thread); if (pThread) { rc = RTSemEventMultiWait(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; }
/** * Thread that allocates * @returns * @param hThreadSelf The thread. * @param pvArg Pointer to fUseCache. */ static DECLCALLBACK(int) tst3Thread(RTTHREAD hThreadSelf, void *pvArg) { PTST3THREAD pThread = (PTST3THREAD)(pvArg); size_t cbObject = pThread->cbObject; uint64_t cIterations = 0; /* wait for the kick-off */ RTTEST_CHECK_RC_OK(g_hTest, RTSemEventMultiWait(pThread->hEvt, RT_INDEFINITE_WAIT)); /* allocate and free loop */ if (pThread->fUseCache) { while (!g_fTst3Stop) { void *apv[64]; for (unsigned i = 0; i < RT_ELEMENTS(apv); i++) { apv[i] = RTMemCacheAlloc(g_hMemCache); RTTEST_CHECK(g_hTest, apv[i] != NULL); } for (unsigned i = 0; i < RT_ELEMENTS(apv); i++) RTMemCacheFree(g_hMemCache, apv[i]); cIterations += RT_ELEMENTS(apv); } } else { while (!g_fTst3Stop) { void *apv[64]; for (unsigned i = 0; i < RT_ELEMENTS(apv); i++) { apv[i] = RTMemAlloc(cbObject); RTTEST_CHECK(g_hTest, apv[i] != NULL); } for (unsigned i = 0; i < RT_ELEMENTS(apv); i++) RTMemFree(apv[i]); cIterations += RT_ELEMENTS(apv); } } /* report back the status */ pThread->cIterations = cIterations; return VINF_SUCCESS; }
static DECLCALLBACK(int) Once2Thread(RTTHREAD hThread, void *pvUser) { NOREF(hThread); NOREF(pvUser); int rc = RTSemEventMultiWait(g_hEventMulti, RT_INDEFINITE_WAIT); if (RT_FAILURE(rc)) return rc; rc = RTOnce(&g_Once2, Once2CB, (void *)42); if (RT_SUCCESS(rc)) { if (!ASMAtomicUoReadBool(&g_fOnce2Ready)) { RTPrintf("tstOnce: ERROR - Once2CB: Not initialized!\n"); g_cErrors++; } } return rc; }
/** * Place an entry in an mbox, waiting for a free slot if necessary. */ void sys_mbox_post(sys_mbox_t *pvMbox, void *msg) { int rc; struct sys_mbox *mbox = NULL; Assert(pvMbox && *pvMbox); mbox = (struct sys_mbox*)*pvMbox; rc = LWIPMutexRequest((mbox)->mutex); AssertRC(rc); while (((mbox)->head + 1) % MBOX_ENTRIES_MAX == (mbox)->tail) { /* (mbox) is full, have to wait until a slot becomes available. */ rc = LWIPMutexRelease((mbox)->mutex); AssertRC(rc); rc = RTSemEventMultiWait((mbox)->nonfull, RT_INDEFINITE_WAIT); AssertRC(rc); rc = LWIPMutexRequest((mbox)->mutex); AssertRC(rc); } if ((mbox)->head == (mbox)->tail) { rc = RTSemEventMultiSignal((mbox)->nonempty); AssertRC(rc); } (mbox)->apvEntries[(mbox)->head] = msg; (mbox)->head++; (mbox)->head %= MBOX_ENTRIES_MAX; if (((mbox)->head + 1) % MBOX_ENTRIES_MAX == (mbox)->tail) { rc = RTSemEventMultiReset((mbox)->nonfull); AssertRC(rc); } rc = LWIPMutexRelease((mbox)->mutex); AssertRC(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); } } else { rc = VERR_THREAD_NOT_WAITABLE; AssertRC(rc); } rtThreadRelease(pThread); } } return rc; }
/** * Get an entry from an mbox. */ u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout) { int rc; RTMSINTERVAL cMillies; uint64_t tsStart, tsEnd; Assert(mbox != NULL); tsStart = RTTimeMilliTS(); if (timeout == 0) cMillies = RT_INDEFINITE_WAIT; else cMillies = timeout; rc = LWIPMutexRequest(mbox->mutex, cMillies); if (rc == VERR_TIMEOUT) return SYS_ARCH_TIMEOUT; AssertRC(rc); while (mbox->head == mbox->tail) { /* mbox is empty, have to wait until a slot is filled. */ rc = LWIPMutexRelease(mbox->mutex); AssertRC(rc); if (timeout != 0) { tsEnd = RTTimeMilliTS(); if (tsEnd - tsStart >= cMillies) return SYS_ARCH_TIMEOUT; cMillies -= tsEnd - tsStart; } rc = RTSemEventMultiWait(mbox->nonempty, cMillies); if (rc == VERR_TIMEOUT) return SYS_ARCH_TIMEOUT; AssertRC(rc); if (timeout != 0) { tsEnd = RTTimeMilliTS(); if (tsEnd - tsStart >= cMillies) return SYS_ARCH_TIMEOUT; cMillies -= tsEnd - tsStart; } rc = LWIPMutexRequest(mbox->mutex, cMillies); if (rc == VERR_TIMEOUT) return SYS_ARCH_TIMEOUT; AssertRC(rc); } if ((mbox->head + 1) % MBOX_ENTRIES_MAX == mbox->tail) { rc = RTSemEventMultiSignal(mbox->nonfull); AssertRC(rc); } if (msg != NULL) *msg = mbox->apvEntries[mbox->tail]; mbox->tail++; mbox->tail %= MBOX_ENTRIES_MAX; rc = RTSemEventMultiSignal(mbox->nonfull); if (mbox->head == mbox->tail) { rc = RTSemEventMultiReset(mbox->nonempty); AssertRC(rc); } rc = LWIPMutexRelease(mbox->mutex); AssertRC(rc); tsEnd = RTTimeMilliTS(); return tsEnd - tsStart; }
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; }
/** @copydoc VBOXSERVICE::pfnWorker */ DECLCALLBACK(int) VBoxServiceVMStatsWorker(bool volatile *pfShutdown) { int rc = VINF_SUCCESS; /* Start monitoring of the stat event change event. */ rc = VbglR3CtlFilterMask(VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST, 0); if (RT_FAILURE(rc)) { VBoxServiceVerbose(3, "VBoxServiceVMStatsWorker: VbglR3CtlFilterMask failed with %d\n", rc); return rc; } /* * Tell the control thread that it can continue * spawning services. */ RTThreadUserSignal(RTThreadSelf()); /* * Now enter the loop retrieving runtime data continuously. */ for (;;) { uint32_t fEvents = 0; RTMSINTERVAL cWaitMillies; /* Check if an update interval change is pending. */ rc = VbglR3WaitEvent(VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST, 0 /* no wait */, &fEvents); if ( RT_SUCCESS(rc) && (fEvents & VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST)) { VbglR3StatQueryInterval(&gCtx.cMsStatInterval); } if (gCtx.cMsStatInterval) { VBoxServiceVMStatsReport(); cWaitMillies = gCtx.cMsStatInterval; } else cWaitMillies = 3000; /* * Block for a while. * * The event semaphore takes care of ignoring interruptions and it * allows us to implement service wakeup later. */ if (*pfShutdown) break; int rc2 = RTSemEventMultiWait(g_VMStatEvent, cWaitMillies); if (*pfShutdown) break; if (rc2 != VERR_TIMEOUT && RT_FAILURE(rc2)) { VBoxServiceError("VBoxServiceVMStatsWorker: RTSemEventMultiWait failed; rc2=%Rrc\n", rc2); rc = rc2; break; } } /* Cancel monitoring of the stat event change event. */ rc = VbglR3CtlFilterMask(0, VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST); if (RT_FAILURE(rc)) VBoxServiceVerbose(3, "VBoxServiceVMStatsWorker: VbglR3CtlFilterMask failed with %d\n", rc); RTSemEventMultiDestroy(g_VMStatEvent); g_VMStatEvent = NIL_RTSEMEVENTMULTI; VBoxServiceVerbose(3, "VBoxStatsThread: finished statistics change request thread\n"); return 0; }
static DECLCALLBACK(int) gimDevR3DbgRecvThread(RTTHREAD hThreadSelf, void *pvUser) { RT_NOREF1(hThreadSelf); /* * Validate. */ PPDMDEVINS pDevIns = (PPDMDEVINS)pvUser; AssertReturn(pDevIns, VERR_INVALID_PARAMETER); PDMDEV_CHECK_VERSIONS_RETURN(pDevIns); PGIMDEV pThis = PDMINS_2_DATA(pDevIns, PGIMDEV); AssertReturn(pThis, VERR_INVALID_POINTER); AssertReturn(pThis->DbgSetup.cbDbgRecvBuf, VERR_INTERNAL_ERROR); AssertReturn(pThis->Dbg.hDbgRecvThreadSem != NIL_RTSEMEVENTMULTI, VERR_INTERNAL_ERROR_2); AssertReturn(pThis->Dbg.pvDbgRecvBuf, VERR_INTERNAL_ERROR_3); PVM pVM = PDMDevHlpGetVM(pDevIns); AssertReturn(pVM, VERR_INVALID_POINTER); PPDMISTREAM pDbgDrvStream = pThis->Dbg.pDbgDrvStream; AssertReturn(pDbgDrvStream, VERR_INVALID_POINTER); for (;;) { /* * Read incoming debug data. */ size_t cbRead = pThis->DbgSetup.cbDbgRecvBuf; int rc = pDbgDrvStream->pfnRead(pDbgDrvStream, pThis->Dbg.pvDbgRecvBuf, &cbRead); if ( RT_SUCCESS(rc) && cbRead > 0) { /* * Notify the consumer thread. */ if (ASMAtomicReadBool(&pThis->Dbg.fDbgRecvBufRead) == false) { if (pThis->DbgSetup.pfnDbgRecvBufAvail) pThis->DbgSetup.pfnDbgRecvBufAvail(pVM); pThis->Dbg.cbDbgRecvBufRead = cbRead; RTSemEventMultiReset(pThis->Dbg.hDbgRecvThreadSem); ASMAtomicWriteBool(&pThis->Dbg.fDbgRecvBufRead, true); } /* * Wait until the consumer thread has acknowledged reading of the * current buffer or we're asked to shut down. * * It is important that we do NOT re-invoke 'pfnRead' before the * current buffer is consumed, otherwise we risk data corruption. */ while ( ASMAtomicReadBool(&pThis->Dbg.fDbgRecvBufRead) == true && !pThis->fDbgRecvThreadShutdown) { RTSemEventMultiWait(pThis->Dbg.hDbgRecvThreadSem, RT_INDEFINITE_WAIT); } } #ifdef RT_OS_LINUX else if (rc == VERR_NET_CONNECTION_REFUSED) { /* * With the current, simplistic PDMISTREAM interface, this is the best we can do. * Even using RTSocketSelectOne[Ex] on Linux returns immediately with 'ready-to-read' * on localhost UDP sockets that are not connected on the other end. */ /** @todo Fix socket waiting semantics on localhost Linux unconnected UDP sockets. */ RTThreadSleep(400); } #endif else if ( rc != VINF_TRY_AGAIN && rc != VERR_TRY_AGAIN && rc != VERR_NET_CONNECTION_RESET_BY_PEER) { LogRel(("GIMDev: Debug thread terminating with rc=%Rrc\n", rc)); break; } if (pThis->fDbgRecvThreadShutdown) { LogRel(("GIMDev: Debug thread shutting down\n")); break; } } return VINF_SUCCESS; }
/** * @interface_method_impl{VBOXSERVICE,pfnWorker} */ DECLCALLBACK(int) vgsvcTimeSyncWorker(bool volatile *pfShutdown) { RTTIME Time; char sz[64]; int rc = VINF_SUCCESS; /* * Tell the control thread that it can continue spawning services. */ RTThreadUserSignal(RTThreadSelf()); /* * The Work Loop. */ for (;;) { /* * Try get a reliable time reading. */ int cTries = 3; do { /* query it. */ RTTIMESPEC GuestNow0, GuestNow, HostNow; RTTimeNow(&GuestNow0); int rc2 = VbglR3GetHostTime(&HostNow); if (RT_FAILURE(rc2)) { if (g_cTimeSyncErrors++ < 10) VGSvcError("vgsvcTimeSyncWorker: VbglR3GetHostTime failed; rc2=%Rrc\n", rc2); break; } RTTimeNow(&GuestNow); /* calc latency and check if it's ok. */ RTTIMESPEC GuestElapsed = GuestNow; RTTimeSpecSub(&GuestElapsed, &GuestNow0); if ((uint32_t)RTTimeSpecGetMilli(&GuestElapsed) < g_TimeSyncMaxLatency) { /* * Set the time once after we were restored. * (Of course only if the drift is bigger than MinAdjust) */ uint32_t TimeSyncSetThreshold = g_TimeSyncSetThreshold; if (g_fTimeSyncSetOnRestore) { uint64_t idNewSession = g_idTimeSyncSession; VbglR3GetSessionId(&idNewSession); if (idNewSession != g_idTimeSyncSession) { VGSvcVerbose(3, "vgsvcTimeSyncWorker: The VM session ID changed, forcing resync.\n"); TimeSyncSetThreshold = 0; g_idTimeSyncSession = idNewSession; } } /* * Calculate the adjustment threshold and the current drift. */ uint32_t MinAdjust = RTTimeSpecGetMilli(&GuestElapsed) * g_TimeSyncLatencyFactor; if (MinAdjust < g_TimeSyncMinAdjust) MinAdjust = g_TimeSyncMinAdjust; RTTIMESPEC Drift = HostNow; RTTimeSpecSub(&Drift, &GuestNow); if (RTTimeSpecGetMilli(&Drift) < 0) MinAdjust += g_TimeSyncMinAdjust; /* extra buffer against moving time backwards. */ RTTIMESPEC AbsDrift = Drift; RTTimeSpecAbsolute(&AbsDrift); if (g_cVerbosity >= 3) { VGSvcVerbose(3, "vgsvcTimeSyncWorker: Host: %s (MinAdjust: %RU32 ms)\n", RTTimeToString(RTTimeExplode(&Time, &HostNow), sz, sizeof(sz)), MinAdjust); VGSvcVerbose(3, "vgsvcTimeSyncWorker: Guest: - %s => %RDtimespec drift\n", RTTimeToString(RTTimeExplode(&Time, &GuestNow), sz, sizeof(sz)), &Drift); } uint32_t AbsDriftMilli = RTTimeSpecGetMilli(&AbsDrift); if (AbsDriftMilli > MinAdjust) { /* * Ok, the drift is above the threshold. * * Try a gradual adjustment first, if that fails or the drift is * too big, fall back on just setting the time. */ if ( AbsDriftMilli > TimeSyncSetThreshold || g_fTimeSyncSetNext || !vgsvcTimeSyncAdjust(&Drift)) { vgsvcTimeSyncCancelAdjust(); vgsvcTimeSyncSet(&Drift); } } else vgsvcTimeSyncCancelAdjust(); break; } VGSvcVerbose(3, "vgsvcTimeSyncWorker: %RDtimespec: latency too high (%RDtimespec) sleeping 1s\n", GuestElapsed); RTThreadSleep(1000); } while (--cTries > 0); /* Clear the set-next/set-start flag. */ g_fTimeSyncSetNext = false; /* * Block for a while. * * The event semaphore takes care of ignoring interruptions and it * allows us to implement service wakeup later. */ if (*pfShutdown) break; int rc2 = RTSemEventMultiWait(g_TimeSyncEvent, g_TimeSyncInterval); if (*pfShutdown) break; if (rc2 != VERR_TIMEOUT && RT_FAILURE(rc2)) { VGSvcError("vgsvcTimeSyncWorker: RTSemEventMultiWait failed; rc2=%Rrc\n", rc2); rc = rc2; break; } } vgsvcTimeSyncCancelAdjust(); RTSemEventMultiDestroy(g_TimeSyncEvent); g_TimeSyncEvent = NIL_RTSEMEVENTMULTI; return rc; }
/** @copydoc VBOXSERVICE::pfnWorker */ DECLCALLBACK(int) VBoxServiceVMInfoWorker(bool volatile *pfShutdown) { int rc; /* * Tell the control thread that it can continue * spawning services. */ RTThreadUserSignal(RTThreadSelf()); #ifdef RT_OS_WINDOWS /* Required for network information (must be called per thread). */ WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), &wsaData)) VBoxServiceError("VMInfo/Network: WSAStartup failed! Error: %Rrc\n", RTErrConvertFromWin32(WSAGetLastError())); #endif /* RT_OS_WINDOWS */ /* * Write the fixed properties first. */ vboxserviceVMInfoWriteFixedProperties(); /* * Now enter the loop retrieving runtime data continuously. */ for (;;) { rc = vboxserviceVMInfoWriteUsers(); if (RT_FAILURE(rc)) break; rc = vboxserviceVMInfoWriteNetwork(); if (RT_FAILURE(rc)) break; /* * Flush all properties if we were restored. */ uint64_t idNewSession = g_idVMInfoSession; VbglR3GetSessionId(&idNewSession); if (idNewSession != g_idVMInfoSession) { VBoxServiceVerbose(3, "VMInfo: The VM session ID changed, flushing all properties\n"); vboxserviceVMInfoWriteFixedProperties(); VBoxServicePropCacheFlush(&g_VMInfoPropCache); g_idVMInfoSession = idNewSession; } /* * Block for a while. * * The event semaphore takes care of ignoring interruptions and it * allows us to implement service wakeup later. */ if (*pfShutdown) break; int rc2 = RTSemEventMultiWait(g_hVMInfoEvent, g_cMsVMInfoInterval); if (*pfShutdown) break; if (rc2 != VERR_TIMEOUT && RT_FAILURE(rc2)) { VBoxServiceError("VMInfo: RTSemEventMultiWait failed; rc2=%Rrc\n", rc2); rc = rc2; break; } else if (RT_LIKELY(RT_SUCCESS(rc2))) { /* Reset event semaphore if it got triggered. */ rc2 = RTSemEventMultiReset(g_hVMInfoEvent); if (RT_FAILURE(rc2)) rc2 = VBoxServiceError("VMInfo: RTSemEventMultiReset failed; rc2=%Rrc\n", rc2); } } #ifdef RT_OS_WINDOWS WSACleanup(); #endif return rc; }
/** * Windows Service Main. * * This is invoked when the service is started and should not return until * the service has been stopped. * * @param cArgs Argument count. * @param papszArgs Argument vector. */ static VOID WINAPI supSvcWinServiceMain(DWORD cArgs, LPSTR *papszArgs) { LogFlowFuncEnter(); /* * Register the control handler function for the service and report to SCM. */ Assert(g_u32SupSvcWinStatus == SERVICE_STOPPED); g_hSupSvcWinCtrlHandler = RegisterServiceCtrlHandlerEx(SUPSVC_SERVICE_NAME, supSvcWinServiceCtrlHandlerEx, NULL); if (g_hSupSvcWinCtrlHandler) { DWORD err = ERROR_GEN_FAILURE; if (supSvcWinSetServiceStatus(SERVICE_START_PENDING, 3000, NO_ERROR)) { /* * Parse arguments. */ static const RTOPTIONDEF s_aOptions[] = { { "--dummy", 'd', RTGETOPT_REQ_NOTHING } }; int iArg = 1; /* the first arg is the service name */ int ch; int rc = 0; RTGETOPTUNION Value; while ( !rc && (ch = RTGetOpt(cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), &iArg, &Value))) switch (ch) { default: rc = supSvcLogGetOptError("main", ch, cArgs, papszArgs, iArg, &Value); break; } if (iArg != cArgs) rc = supSvcLogTooManyArgsError("main", cArgs, papszArgs, iArg); if (!rc) { /* * Create the event semaphore we'll be waiting on and * then instantiate the actual services. */ int rc = RTSemEventMultiCreate(&g_hSupSvcWinEvent); if (RT_SUCCESS(rc)) { rc = supSvcCreateAndStartServices(); if (RT_SUCCESS(rc)) { /* * Update the status and enter the work loop. * * The work loop is just a dummy wait here as the services run * in independent threads. */ if (supSvcWinSetServiceStatus(SERVICE_RUNNING, 0, 0)) { LogFlow(("supSvcWinServiceMain: calling RTSemEventMultiWait\n")); rc = RTSemEventMultiWait(g_hSupSvcWinEvent, RT_INDEFINITE_WAIT); if (RT_SUCCESS(rc)) { LogFlow(("supSvcWinServiceMain: woke up\n")); err = NO_ERROR; } else supSvcLogError("RTSemEventWait failed, rc=%Rrc", rc); } else { err = GetLastError(); supSvcLogError("SetServiceStatus failed, err=%d", err); } /* * Destroy the service instances, stopping them if * they're still running (weird failure cause). */ supSvcStopAndDestroyServices(); } RTSemEventMultiDestroy(g_hSupSvcWinEvent); g_hSupSvcWinEvent = NIL_RTSEMEVENTMULTI; } else supSvcLogError("RTSemEventMultiCreate failed, rc=%Rrc", rc); } /* else: bad args */ } else { err = GetLastError(); supSvcLogError("SetServiceStatus failed, err=%d", err); } supSvcWinSetServiceStatus(SERVICE_STOPPED, 0, err); } else supSvcLogError("RegisterServiceCtrlHandlerEx failed, err=%d", GetLastError()); LogFlowFuncLeave(); }