/** * Try to place an entry in an mbox if there is a free slot. */ err_t sys_mbox_trypost(sys_mbox_t *pvMbox, void *msg) { int rc; struct sys_mbox *mbox = NULL; AssertReturn(pvMbox && *pvMbox, ERR_ARG); mbox = (struct sys_mbox*)*pvMbox; rc = LWIPMutexRequest((mbox)->mutex); AssertRC(rc); if (((mbox)->head + 1) % MBOX_ENTRIES_MAX == (mbox)->tail) { /* (mbox) is full */ rc = LWIPMutexRelease((mbox)->mutex); AssertRC(rc); return ERR_MEM; } 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); return ERR_OK; }
/** * Try to get an entry from an mbox. */ u32_t sys_arch_mbox_tryfetch(sys_mbox_t *pvMbox, void **msg) { int rc; struct sys_mbox *mbox = NULL; if (!pvMbox || !*pvMbox) return SYS_MBOX_EMPTY; mbox = (struct sys_mbox*)*pvMbox; rc = LWIPMutexRequest((mbox)->mutex); AssertRC(rc); if ((mbox)->head == (mbox)->tail) { /* (mbox) is empty, don't wait */ rc = LWIPMutexRelease((mbox)->mutex); AssertRC(rc); return SYS_MBOX_EMPTY; } 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); return 0; }
SUPDECL(int) SUPSemEventMultiReset(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti) { int rc; uint32_t h32; PSUPDRVOBJ pObj; /* * Input validation. */ AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER); h32 = (uint32_t)(uintptr_t)hEventMulti; if (h32 != (uintptr_t)hEventMulti) return VERR_INVALID_HANDLE; pObj = (PSUPDRVOBJ)RTHandleTableLookupWithCtx(pSession->hHandleTable, h32, SUPDRV_HANDLE_CTX_EVENT_MULTI); if (!pObj) return VERR_INVALID_HANDLE; /* * Do the job. */ rc = RTSemEventMultiReset((RTSEMEVENTMULTI)pObj->pvUser1); SUPR0ObjRelease(pObj, pSession); 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); }
/** * @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; }
/** * Suspends the thread. * * This can be called at the power off / suspend notifications to suspend the * PDM thread a bit early. The thread will be automatically suspend upon * completion of the device/driver notification cycle. * * The caller is responsible for serializing the control operations on the * thread. That basically means, always do these calls from the EMT. * * @returns VBox status code. * @param pThread The PDM thread. */ VMMR3DECL(int) PDMR3ThreadSuspend(PPDMTHREAD pThread) { /* * Assert sanity. */ AssertPtrReturn(pThread, VERR_INVALID_POINTER); AssertReturn(pThread->u32Version == PDMTHREAD_VERSION, VERR_INVALID_MAGIC); Assert(pThread->Thread != RTThreadSelf()); /* * This is a noop if the thread is already suspended. */ if (pThread->enmState == PDMTHREADSTATE_SUSPENDED) return VINF_SUCCESS; /* * Change the state to resuming and kick the thread. */ int rc = RTSemEventMultiReset(pThread->Internal.s.BlockEvent); if (RT_SUCCESS(rc)) { rc = RTThreadUserReset(pThread->Thread); if (RT_SUCCESS(rc)) { rc = VERR_WRONG_ORDER; if (pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_SUSPENDING, PDMTHREADSTATE_RUNNING)) { rc = pdmR3ThreadWakeUp(pThread); if (RT_SUCCESS(rc)) { /* * Wait for the thread to reach the suspended state. */ if (pThread->enmState != PDMTHREADSTATE_SUSPENDED) rc = RTThreadUserWait(pThread->Thread, 60*1000); if ( RT_SUCCESS(rc) && pThread->enmState != PDMTHREADSTATE_SUSPENDED) rc = VERR_PDM_THREAD_IPE_2; if (RT_SUCCESS(rc)) return rc; } } } } /* * Something failed, initialize termination. */ AssertMsgFailed(("PDMR3ThreadSuspend -> rc=%Rrc enmState=%d suspending '%s'\n", rc, pThread->enmState, RTThreadGetName(pThread->Thread))); pdmR3ThreadBailOut(pThread); return rc; }
/** * @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; }
/** * Reset the user event. * * @returns iprt status code. * @param Thread The thread to reset. */ RTDECL(int) RTThreadUserReset(RTTHREAD Thread) { int rc; PRTTHREADINT pThread = rtThreadGet(Thread); if (pThread) { rc = RTSemEventMultiReset(pThread->EventUser); rtThreadRelease(pThread); } else rc = VERR_INVALID_HANDLE; return rc; }
static void testBasics(void) { RTTestISub("Basics"); RTSEMEVENTMULTI hSem; RTTESTI_CHECK_RC_RETV(RTSemEventMultiCreate(&hSem), VINF_SUCCESS); /* The semaphore is created in a reset state, calling reset explicitly shouldn't make any difference. */ testBasicsWaitTimeout(hSem, 0); RTTESTI_CHECK_RC_RETV(RTSemEventMultiReset(hSem), VINF_SUCCESS); testBasicsWaitTimeout(hSem, 1); if (RTTestIErrorCount()) return; /* When signalling the semaphore all successive wait calls shall succeed, signalling it again should make no difference. */ RTTESTI_CHECK_RC_RETV(RTSemEventMultiSignal(hSem), VINF_SUCCESS); testBasicsWaitSuccess(hSem, 2); if (RTTestIErrorCount()) return; /* After resetting it we should time out again. */ RTTESTI_CHECK_RC_RETV(RTSemEventMultiReset(hSem), VINF_SUCCESS); testBasicsWaitTimeout(hSem, 3); if (RTTestIErrorCount()) return; /* The number of resets or signal calls shouldn't matter. */ RTTESTI_CHECK_RC_RETV(RTSemEventMultiReset(hSem), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTSemEventMultiReset(hSem), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTSemEventMultiReset(hSem), VINF_SUCCESS); testBasicsWaitTimeout(hSem, 4); RTTESTI_CHECK_RC_RETV(RTSemEventMultiSignal(hSem), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTSemEventMultiSignal(hSem), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTSemEventMultiSignal(hSem), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTSemEventMultiSignal(hSem), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTSemEventMultiSignal(hSem), VINF_SUCCESS); testBasicsWaitSuccess(hSem, 5); RTTESTI_CHECK_RC_RETV(RTSemEventMultiReset(hSem), VINF_SUCCESS); testBasicsWaitTimeout(hSem, 6); /* Destroy it. */ RTTESTI_CHECK_RC_RETV(RTSemEventMultiDestroy(hSem), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTSemEventMultiDestroy(NIL_RTSEMEVENTMULTI), VINF_SUCCESS); /* Whether it is reset (above), signalled or not used shouldn't matter. */ RTTESTI_CHECK_RC_RETV(RTSemEventMultiCreate(&hSem), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTSemEventMultiSignal(hSem), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTSemEventMultiDestroy(hSem), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTSemEventMultiCreate(&hSem), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTSemEventMultiDestroy(hSem), VINF_SUCCESS); RTTestISubDone(); }
/** * 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); }
/** * Initializes the sub-progress object that represents a specific operation of * the whole task. * * Objects initialized with this method are then combined together into the * single task using a Progress instance, so it doesn't require the * parent, initiator, description and doesn't create an ID. Note that calling * respective getter methods on an object initialized with this method is * useless. Such objects are used only to provide a separate wait semaphore and * store individual operation descriptions. * * @param aCancelable Flag whether the task maybe canceled. * @param aOperationCount Number of sub-operations within this task (at least 1). * @param aOperationDescription Description of the individual operation. */ HRESULT Progress::init(BOOL aCancelable, ULONG aOperationCount, Utf8Str aOperationDescription) { LogFlowThisFunc(("aOperationDescription=\"%s\"\n", aOperationDescription.c_str())); /* Enclose the state transition NotReady->InInit->Ready */ AutoInitSpan autoInitSpan(this); AssertReturn(autoInitSpan.isOk(), E_FAIL); HRESULT rc = S_OK; /* Guarantees subclasses call this method at the proper time */ NOREF(autoInitSpan); if (FAILED(rc)) return rc; mCancelable = aCancelable; // for this variant we assume for now that all operations are weighed "1" // and equal total weight = operation count m_cOperations = aOperationCount; m_ulTotalOperationsWeight = aOperationCount; m_ulOperationsCompletedWeight = 0; m_ulCurrentOperation = 0; m_operationDescription = aOperationDescription; m_ulCurrentOperationWeight = 1; m_ulOperationPercent = 0; int vrc = RTSemEventMultiCreate(&mCompletedSem); ComAssertRCRet(vrc, E_FAIL); RTSemEventMultiReset(mCompletedSem); /* Confirm a successful initialization when it's the case */ if (SUCCEEDED(rc)) autoInitSpan.setSucceeded(); 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); }
/** * 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) rtSemRWRequestWrite(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 = NIL_RTTHREAD; if (cMillies) { hThreadSelf = RTThreadSelfAutoAdopt(); int rc9 = RTLockValidatorRecExclCheckOrder(&pThis->ValidatorWrite, 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 write access. */ RTNATIVETHREAD hNativeSelf = pThis->CritSect.NativeThreadOwner; if ( !pThis->cReads && ( ( !pThis->cWrites && ( !pThis->cWritesWaiting /* play fair if we can wait */ || !cMillies) ) || pThis->hWriter == hNativeSelf ) ) { /* * Reset the reader event semaphore if necessary. */ if (pThis->fNeedResetReadEvent) { pThis->fNeedResetReadEvent = false; rc = RTSemEventMultiReset(pThis->ReadEvent); AssertMsgRC(rc, ("Failed to reset readers, rwsem %p, rc=%Rrc.\n", hRWSem, rc)); } pThis->cWrites++; pThis->hWriter = hNativeSelf; #ifdef RTSEMRW_STRICT RTLockValidatorRecExclSetOwner(&pThis->ValidatorWrite, hThreadSelf, pSrcPos, pThis->cWrites == 1); #endif RTCritSectLeave(&pThis->CritSect); return VINF_SUCCESS; } /* * Signal writer presence. */ if (cMillies != 0) pThis->cWritesWaiting++; RTCritSectLeave(&pThis->CritSect); /* * Wait till it's ready for writing. */ 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 = RTLockValidatorRecExclCheckBlocking(&pThis->ValidatorWrite, hThreadSelf, pSrcPos, true, cMillies, RTTHREADSTATE_RW_WRITE, false); if (RT_FAILURE(rc)) break; #else RTThreadBlocking(hThreadSelf, RTTHREADSTATE_RW_WRITE, false); #endif int rcWait; if (fInterruptible) rcWait = rc = RTSemEventWaitNoResume(pThis->WriteEvent, cMillies); else rcWait = rc = RTSemEventWait(pThis->WriteEvent, cMillies); RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_RW_WRITE); if (RT_UNLIKELY(RT_FAILURE_NP(rc) && rc != VERR_TIMEOUT)) /* timeouts are handled below */ { AssertMsgRC(rc, ("RTSemEventWait failed on rwsem %p, rc=%Rrc\n", hRWSem, rc)); break; } if (RT_UNLIKELY(pThis->u32Magic != RTSEMRW_MAGIC)) { rc = VERR_SEM_DESTROYED; break; } /* * Re-take critsect and repeat the check we did prior to this loop. */ rc = RTCritSectEnter(&pThis->CritSect); if (RT_FAILURE(rc)) { AssertMsgFailed(("RTCritSectEnter failed on rwsem %p, rc=%Rrc\n", hRWSem, rc)); break; } if (!pThis->cReads && (!pThis->cWrites || pThis->hWriter == hNativeSelf)) { /* * Reset the reader event semaphore if necessary. */ if (pThis->fNeedResetReadEvent) { pThis->fNeedResetReadEvent = false; rc = RTSemEventMultiReset(pThis->ReadEvent); AssertMsgRC(rc, ("Failed to reset readers, rwsem %p, rc=%Rrc.\n", hRWSem, rc)); } pThis->cWrites++; pThis->hWriter = hNativeSelf; pThis->cWritesWaiting--; #ifdef RTSEMRW_STRICT RTLockValidatorRecExclSetOwner(&pThis->ValidatorWrite, hThreadSelf, pSrcPos, true); #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; } } /* * Timeout/error case, clean up. */ if (pThis->u32Magic == RTSEMRW_MAGIC) { RTCritSectEnter(&pThis->CritSect); /* Adjust this counter, whether we got the critsect or not. */ pThis->cWritesWaiting--; RTCritSectLeave(&pThis->CritSect); } 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; }
/** * Initializes the normal progress object. With this variant, one can have * an arbitrary number of sub-operation which IProgress can analyze to * have a weighted progress computed. * * For example, say that one IProgress is supposed to track the cloning * of two hard disk images, which are 100 MB and 1000 MB in size, respectively, * and each of these hard disks should be one sub-operation of the IProgress. * * Obviously the progress would be misleading if the progress displayed 50% * after the smaller image was cloned and would then take much longer for * the second half. * * With weighted progress, one can invoke the following calls: * * 1) create progress object with cOperations = 2 and ulTotalOperationsWeight = * 1100 (100 MB plus 1100, but really the weights can be any ULONG); pass * in ulFirstOperationWeight = 100 for the first sub-operation * * 2) Then keep calling setCurrentOperationProgress() with a percentage * for the first image; the total progress will increase up to a value * of 9% (100MB / 1100MB * 100%). * * 3) Then call setNextOperation with the second weight (1000 for the megabytes * of the second disk). * * 4) Then keep calling setCurrentOperationProgress() with a percentage for * the second image, where 100% of the operation will then yield a 100% * progress of the entire task. * * Weighting is optional; you can simply assign a weight of 1 to each operation * and pass ulTotalOperationsWeight == cOperations to this constructor (but * for that variant and for backwards-compatibility a simpler constructor exists * in ProgressImpl.h as well). * * Even simpler, if you need no sub-operations at all, pass in cOperations = * ulTotalOperationsWeight = ulFirstOperationWeight = 1. * * @param aParent Parent object (only for server-side Progress objects). * @param aInitiator Initiator of the task (for server-side objects. Can be * NULL which means initiator = parent, otherwise must not * be NULL). * @param aDescription Overall task description. * @param aCancelable Flag whether the task maybe canceled. * @param cOperations Number of operations within this task (at least 1). * @param ulTotalOperationsWeight Total weight of operations; must be the sum of ulFirstOperationWeight and * what is later passed with each subsequent setNextOperation() call. * @param bstrFirstOperationDescription Description of the first operation. * @param ulFirstOperationWeight Weight of first sub-operation. */ HRESULT Progress::init( #if !defined(VBOX_COM_INPROC) VirtualBox *aParent, #endif IUnknown *aInitiator, Utf8Str aDescription, BOOL aCancelable, ULONG cOperations, ULONG ulTotalOperationsWeight, Utf8Str aFirstOperationDescription, ULONG ulFirstOperationWeight) { LogFlowThisFunc(("aDescription=\"%s\", cOperations=%d, ulTotalOperationsWeight=%d, aFirstOperationDescription=\"%s\", ulFirstOperationWeight=%d\n", aDescription.c_str(), cOperations, ulTotalOperationsWeight, aFirstOperationDescription.c_str(), ulFirstOperationWeight)); AssertReturn(ulTotalOperationsWeight >= 1, E_INVALIDARG); /* Enclose the state transition NotReady->InInit->Ready */ AutoInitSpan autoInitSpan(this); AssertReturn(autoInitSpan.isOk(), E_FAIL); HRESULT rc = S_OK; // rc = Progress::init( //#if !defined(VBOX_COM_INPROC) // aParent, //#endif // aInitiator, aDescription, FALSE, aId); // NA #if !defined(VBOX_COM_INPROC) AssertReturn(aParent, E_INVALIDARG); #else AssertReturn(aInitiator, E_INVALIDARG); #endif #if !defined(VBOX_COM_INPROC) /* share parent weakly */ unconst(mParent) = aParent; #endif #if !defined(VBOX_COM_INPROC) /* assign (and therefore addref) initiator only if it is not VirtualBox * (to avoid cycling); otherwise mInitiator will remain null which means * that it is the same as the parent */ if (aInitiator) { ComObjPtr<VirtualBox> pVirtualBox(mParent); if (!(pVirtualBox == aInitiator)) unconst(mInitiator) = aInitiator; } #else unconst(mInitiator) = aInitiator; #endif unconst(mId).create(); #if !defined(VBOX_COM_INPROC) /* add to the global collection of progress operations (note: after * creating mId) */ mParent->i_addProgress(this); #endif unconst(mDescription) = aDescription; // end of assertion if (FAILED(rc)) return rc; mCancelable = aCancelable; m_cOperations = cOperations; m_ulTotalOperationsWeight = ulTotalOperationsWeight; m_ulOperationsCompletedWeight = 0; m_ulCurrentOperation = 0; m_operationDescription = aFirstOperationDescription; m_ulCurrentOperationWeight = ulFirstOperationWeight; m_ulOperationPercent = 0; int vrc = RTSemEventMultiCreate(&mCompletedSem); ComAssertRCRet(vrc, E_FAIL); RTSemEventMultiReset(mCompletedSem); /* Confirm a successful initialization when it's the case */ if (SUCCEEDED(rc)) autoInitSpan.setSucceeded(); return rc; }
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; }