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(); }
static void test1(void) { RTTestISub("Three threads"); /* * Create the threads and let them block on the event multi semaphore. */ RTSEMEVENTMULTI hSem; RTTESTI_CHECK_RC_RETV(RTSemEventMultiCreate(&hSem), VINF_SUCCESS); RTTHREAD hThread2; RTTESTI_CHECK_RC_RETV(RTThreadCreate(&hThread2, test1Thread2, &hSem, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "test2"), VINF_SUCCESS); RTThreadSleep(100); RTTHREAD hThread1; RTTESTI_CHECK_RC_RETV(RTThreadCreate(&hThread1, test1Thread1, &hSem, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "test1"), VINF_SUCCESS); /* Force first thread (which has a timeout of 1 second) to timeout in the * first wait, and the second wait will succeed. */ RTTESTI_CHECK_RC(RTThreadSleep(1500), VINF_SUCCESS); RTTESTI_CHECK_RC(RTSemEventMultiSignal(hSem), VINF_SUCCESS); RTTESTI_CHECK_RC(RTThreadWait(hThread1, 5000, NULL), VINF_SUCCESS); RTTESTI_CHECK_RC(RTThreadWait(hThread2, 5000, NULL), VINF_SUCCESS); RTTESTI_CHECK_RC(RTSemEventMultiDestroy(hSem), VINF_SUCCESS); }
SUPDECL(int) SUPSemEventMultiCreate(PSUPDRVSESSION pSession, PSUPSEMEVENTMULTI phEventMulti) { int rc; RTSEMEVENTMULTI hEventMultReal; /* * Input validation. */ AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER); AssertPtrReturn(phEventMulti, VERR_INVALID_POINTER); /* * Create the event semaphore object. */ rc = RTSemEventMultiCreate(&hEventMultReal); if (RT_SUCCESS(rc)) { void *pvObj = SUPR0ObjRegister(pSession, SUPDRVOBJTYPE_SEM_EVENT_MULTI, supR0SemEventMultiDestructor, hEventMultReal, NULL); if (pvObj) { uint32_t h32; rc = RTHandleTableAllocWithCtx(pSession->hHandleTable, pvObj, SUPDRV_HANDLE_CTX_EVENT_MULTI, &h32); if (RT_SUCCESS(rc)) { *phEventMulti = (SUPSEMEVENTMULTI)(uintptr_t)h32; return VINF_SUCCESS; } SUPR0ObjRelease(pvObj, pSession); } else RTSemEventMultiDestroy(hEventMultReal); } return rc; }
/** @copydoc VBOXSERVICE::pfnInit */ static DECLCALLBACK(int) VBoxServiceAutoMountInit(void) { VBoxServiceVerbose(3, "VBoxServiceAutoMountInit\n"); int rc = RTSemEventMultiCreate(&g_AutoMountEvent); AssertRCReturn(rc, rc); rc = VbglR3SharedFolderConnect(&g_SharedFoldersSvcClientID); if (RT_SUCCESS(rc)) { VBoxServiceVerbose(3, "VBoxServiceAutoMountInit: Service Client ID: %#x\n", g_SharedFoldersSvcClientID); } else { /* If the service was not found, we disable this service without causing VBoxService to fail. */ if (rc == VERR_HGCM_SERVICE_NOT_FOUND) /* Host service is not available. */ { VBoxServiceVerbose(0, "VBoxServiceAutoMountInit: Shared Folders service is not available\n"); rc = VERR_SERVICE_DISABLED; } else VBoxServiceError("Control: Failed to connect to the Shared Folders service! Error: %Rrc\n", rc); RTSemEventMultiDestroy(g_AutoMountEvent); g_AutoMountEvent = NIL_RTSEMEVENTMULTI; } return rc; }
/** * Time constrained test with and unlimited N threads. */ static void tst3(uint32_t cThreads, uint32_t cbObject, int iMethod, uint32_t cSecs) { RTTestISubF("Benchmark - %u threads, %u bytes, %u secs, %s", cThreads, cbObject, cSecs, iMethod == 0 ? "RTMemCache" : "RTMemAlloc"); /* * Create a cache with unlimited space, a start semaphore and line up * the threads. */ RTTESTI_CHECK_RC_RETV(RTMemCacheCreate(&g_hMemCache, cbObject, 0 /*cbAlignment*/, UINT32_MAX, NULL, NULL, NULL, 0 /*fFlags*/), VINF_SUCCESS); RTSEMEVENTMULTI hEvt; RTTESTI_CHECK_RC_OK_RETV(RTSemEventMultiCreate(&hEvt)); TST3THREAD aThreads[64]; RTTESTI_CHECK_RETV(cThreads < RT_ELEMENTS(aThreads)); ASMAtomicWriteBool(&g_fTst3Stop, false); for (uint32_t i = 0; i < cThreads; i++) { aThreads[i].hThread = NIL_RTTHREAD; aThreads[i].cIterations = 0; aThreads[i].fUseCache = iMethod == 0; aThreads[i].cbObject = cbObject; aThreads[i].hEvt = hEvt; RTTESTI_CHECK_RC_OK_RETV(RTThreadCreateF(&aThreads[i].hThread, tst3Thread, &aThreads[i], 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "tst3-%u", i)); } /* * Start the race. */ RTTimeNanoTS(); /* warmup */ uint64_t uStartTS = RTTimeNanoTS(); RTTESTI_CHECK_RC_OK_RETV(RTSemEventMultiSignal(hEvt)); RTThreadSleep(cSecs * 1000); ASMAtomicWriteBool(&g_fTst3Stop, true); for (uint32_t i = 0; i < cThreads; i++) RTTESTI_CHECK_RC_OK_RETV(RTThreadWait(aThreads[i].hThread, 60*1000, NULL)); uint64_t cElapsedNS = RTTimeNanoTS() - uStartTS; /* * Sum up the counts. */ uint64_t cIterations = 0; for (uint32_t i = 0; i < cThreads; i++) cIterations += aThreads[i].cIterations; RTTestIPrintf(RTTESTLVL_ALWAYS, "%'8u iterations per second, %'llu ns on avg\n", (unsigned)((long double)cIterations * 1000000000.0 / cElapsedNS), cElapsedNS / cIterations); /* clean up */ RTTESTI_CHECK_RC(RTMemCacheDestroy(g_hMemCache), VINF_SUCCESS); RTTESTI_CHECK_RC_OK(RTSemEventMultiDestroy(hEvt)); }
RTDECL(int) RTSemRWCreateEx(PRTSEMRW phRWSem, uint32_t fFlags, RTLOCKVALCLASS hClass, uint32_t uSubClass, const char *pszNameFmt, ...) { AssertReturn(!(fFlags & ~RTSEMRW_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER); RTSEMRWINTERNAL *pThis = (RTSEMRWINTERNAL *)RTMemAlloc(sizeof(*pThis)); if (!pThis) return VERR_NO_MEMORY; int rc = RTSemEventMultiCreate(&pThis->hEvtRead); if (RT_SUCCESS(rc)) { rc = RTSemEventCreate(&pThis->hEvtWrite); if (RT_SUCCESS(rc)) { pThis->u32Magic = RTSEMRW_MAGIC; pThis->u32Padding = 0; pThis->u64State = 0; pThis->hNativeWriter = NIL_RTNATIVETHREAD; pThis->cWriterReads = 0; pThis->cWriteRecursions = 0; pThis->fNeedReset = false; #ifdef RTSEMRW_STRICT bool const fLVEnabled = !(fFlags & RTSEMRW_FLAGS_NO_LOCK_VAL); if (!pszNameFmt) { static uint32_t volatile s_iSemRWAnon = 0; uint32_t i = ASMAtomicIncU32(&s_iSemRWAnon) - 1; RTLockValidatorRecExclInit(&pThis->ValidatorWrite, hClass, uSubClass, pThis, fLVEnabled, "RTSemRW-%u", i); RTLockValidatorRecSharedInit(&pThis->ValidatorRead, hClass, uSubClass, pThis, false /*fSignaller*/, fLVEnabled, "RTSemRW-%u", i); } else { va_list va; va_start(va, pszNameFmt); RTLockValidatorRecExclInitV(&pThis->ValidatorWrite, hClass, uSubClass, pThis, fLVEnabled, pszNameFmt, va); va_end(va); va_start(va, pszNameFmt); RTLockValidatorRecSharedInitV(&pThis->ValidatorRead, hClass, uSubClass, pThis, false /*fSignaller*/, fLVEnabled, pszNameFmt, va); va_end(va); } RTLockValidatorRecMakeSiblings(&pThis->ValidatorWrite.Core, &pThis->ValidatorRead.Core); #endif *phRWSem = pThis; return VINF_SUCCESS; } RTSemEventMultiDestroy(pThis->hEvtRead); } return rc; }
/** * Create new mbox. */ err_t sys_mbox_new(sys_mbox_t *pvMbox, int size) { int rc; struct sys_mbox *mbox = NULL; if (pvMbox == NULL) return ERR_ARG; mbox = RTMemAllocZ(sizeof(struct sys_mbox)); Assert(mbox != NULL); if (!mbox) return ERR_MEM; rc = LWIPMutexCreate(&mbox->mutex); AssertRC(rc); if (RT_FAILURE(rc)) { RTMemFree(mbox); return ERR_VAL; } rc = RTSemEventMultiCreate(&mbox->nonempty); AssertRC(rc); if (RT_FAILURE(rc)) { rc = LWIPMutexDestroy(mbox->mutex); AssertRC(rc); RTMemFree(mbox); return ERR_VAL; } rc = RTSemEventMultiCreate(&mbox->nonfull); AssertRC(rc); if (RT_FAILURE(rc)) { rc = RTSemEventMultiDestroy(mbox->nonempty); AssertRC(rc); rc = LWIPMutexDestroy(mbox->mutex); AssertRC(rc); RTMemFree(mbox); return ERR_VAL; } mbox->valid = 1; *pvMbox = mbox; return ERR_OK; }
/** @copydoc VBOXSERVICE::pfnInit */ static DECLCALLBACK(int) VBoxServiceVMInfoInit(void) { /* * If not specified, find the right interval default. * Then create the event sem to block on. */ if (!g_cMsVMInfoInterval) g_cMsVMInfoInterval = g_DefaultInterval * 1000; if (!g_cMsVMInfoInterval) g_cMsVMInfoInterval = 10 * 1000; int rc = RTSemEventMultiCreate(&g_hVMInfoEvent); AssertRCReturn(rc, rc); VbglR3GetSessionId(&g_idVMInfoSession); /* The status code is ignored as this information is not available with VBox < 3.2.10. */ rc = VbglR3GuestPropConnect(&g_uVMInfoGuestPropSvcClientID); if (RT_SUCCESS(rc)) VBoxServiceVerbose(3, "VMInfo: Property Service Client ID: %#x\n", g_uVMInfoGuestPropSvcClientID); else { /* If the service was not found, we disable this service without causing VBoxService to fail. */ if (rc == VERR_HGCM_SERVICE_NOT_FOUND) /* Host service is not available. */ { VBoxServiceVerbose(0, "VMInfo: Guest property service is not available, disabling the service\n"); rc = VERR_SERVICE_DISABLED; } else VBoxServiceError("VMInfo: Failed to connect to the guest property service! Error: %Rrc\n", rc); RTSemEventMultiDestroy(g_hVMInfoEvent); g_hVMInfoEvent = NIL_RTSEMEVENTMULTI; } if (RT_SUCCESS(rc)) { VBoxServicePropCacheCreate(&g_VMInfoPropCache, g_uVMInfoGuestPropSvcClientID); /* * Declare some guest properties with flags and reset values. */ VBoxServicePropCacheUpdateEntry(&g_VMInfoPropCache, "/VirtualBox/GuestInfo/OS/LoggedInUsersList", VBOXSERVICEPROPCACHEFLAG_TEMPORARY | VBOXSERVICEPROPCACHEFLAG_TRANSIENT, NULL /* Delete on exit */); VBoxServicePropCacheUpdateEntry(&g_VMInfoPropCache, "/VirtualBox/GuestInfo/OS/LoggedInUsers", VBOXSERVICEPROPCACHEFLAG_TEMPORARY | VBOXSERVICEPROPCACHEFLAG_TRANSIENT, "0"); VBoxServicePropCacheUpdateEntry(&g_VMInfoPropCache, "/VirtualBox/GuestInfo/OS/NoLoggedInUsers", VBOXSERVICEPROPCACHEFLAG_TEMPORARY | VBOXSERVICEPROPCACHEFLAG_TRANSIENT, "true"); VBoxServicePropCacheUpdateEntry(&g_VMInfoPropCache, "/VirtualBox/GuestInfo/Net/Count", VBOXSERVICEPROPCACHEFLAG_TEMPORARY | VBOXSERVICEPROPCACHEFLAG_ALWAYS_UPDATE, NULL /* Delete on exit */); } return rc; }
/** * Allocates a per thread data structure and initializes the basic fields. * * @returns Pointer to per thread data structure. * This is reference once. * @returns NULL on failure. * @param enmType The thread type. * @param fFlags The thread flags. * @param fIntFlags The internal thread flags. * @param pszName Pointer to the thread name. */ PRTTHREADINT rtThreadAlloc(RTTHREADTYPE enmType, unsigned fFlags, uint32_t fIntFlags, const char *pszName) { PRTTHREADINT pThread = (PRTTHREADINT)RTMemAllocZ(sizeof(RTTHREADINT)); if (pThread) { size_t cchName; int rc; pThread->Core.Key = (void*)NIL_RTTHREAD; pThread->u32Magic = RTTHREADINT_MAGIC; cchName = strlen(pszName); if (cchName >= RTTHREAD_NAME_LEN) cchName = RTTHREAD_NAME_LEN - 1; memcpy(pThread->szName, pszName, cchName); pThread->szName[cchName] = '\0'; pThread->cRefs = 2 + !!(fFlags & RTTHREADFLAGS_WAITABLE); /* And extra reference if waitable. */ pThread->rc = VERR_PROCESS_RUNNING; /** @todo get a better error code! */ pThread->enmType = enmType; pThread->fFlags = fFlags; pThread->fIntFlags = fIntFlags; pThread->enmState = RTTHREADSTATE_INITIALIZING; pThread->fReallySleeping = false; #ifdef IN_RING3 rtLockValidatorInitPerThread(&pThread->LockValidator); #endif #ifdef RT_WITH_ICONV_CACHE rtStrIconvCacheInit(pThread); #endif rc = RTSemEventMultiCreate(&pThread->EventUser); if (RT_SUCCESS(rc)) { rc = RTSemEventMultiCreate(&pThread->EventTerminated); if (RT_SUCCESS(rc)) return pThread; RTSemEventMultiDestroy(pThread->EventUser); } RTMemFree(pThread); } return NULL; }
/** * Create new mbox. */ sys_mbox_t sys_mbox_new(void) { int rc; struct sys_mbox *mbox; mbox = RTMemAllocZ(sizeof(*mbox)); Assert(mbox != NULL); if (!mbox) return mbox; rc = LWIPMutexCreate(&mbox->mutex); AssertRC(rc); if (RT_FAILURE(rc)) { RTMemFree(mbox); return NULL; } rc = RTSemEventMultiCreate(&mbox->nonempty); AssertRC(rc); if (RT_FAILURE(rc)) { rc = LWIPMutexDestroy(mbox->mutex); AssertRC(rc); RTMemFree(mbox); return NULL; } rc = RTSemEventMultiCreate(&mbox->nonfull); AssertRC(rc); if (RT_FAILURE(rc)) { rc = RTSemEventMultiDestroy(mbox->nonempty); AssertRC(rc); rc = LWIPMutexDestroy(mbox->mutex); AssertRC(rc); RTMemFree(mbox); return NULL; } return mbox; }
/** @copydoc VBOXSERVICE::pfnInit */ static DECLCALLBACK(int) VBoxServiceVMStatsInit(void) { VBoxServiceVerbose(3, "VBoxServiceVMStatsInit\n"); int rc = RTSemEventMultiCreate(&g_VMStatEvent); AssertRCReturn(rc, rc); gCtx.cMsStatInterval = 0; /* default; update disabled */ RT_ZERO(gCtx.au64LastCpuLoad_Idle); RT_ZERO(gCtx.au64LastCpuLoad_Kernel); RT_ZERO(gCtx.au64LastCpuLoad_User); RT_ZERO(gCtx.au64LastCpuLoad_Nice); rc = VbglR3StatQueryInterval(&gCtx.cMsStatInterval); if (RT_SUCCESS(rc)) VBoxServiceVerbose(3, "VBoxStatsInit: New statistics interval %u seconds\n", gCtx.cMsStatInterval); else VBoxServiceVerbose(3, "VBoxStatsInit: DeviceIoControl failed with %d\n", rc); #ifdef RT_OS_WINDOWS /* NtQuerySystemInformation might be dropped in future releases, so load it dynamically as per Microsoft's recommendation. */ *(void **)&gCtx.pfnNtQuerySystemInformation = RTLdrGetSystemSymbol("ntdll.dll", "NtQuerySystemInformation"); if (gCtx.pfnNtQuerySystemInformation) VBoxServiceVerbose(3, "VBoxStatsInit: gCtx.pfnNtQuerySystemInformation = %x\n", gCtx.pfnNtQuerySystemInformation); else { VBoxServiceVerbose(3, "VBoxStatsInit: ntdll.NtQuerySystemInformation not found!\n"); return VERR_SERVICE_DISABLED; } /* GlobalMemoryStatus is win2k and up, so load it dynamically */ *(void **)&gCtx.pfnGlobalMemoryStatusEx = RTLdrGetSystemSymbol("kernel32.dll", "GlobalMemoryStatusEx"); if (gCtx.pfnGlobalMemoryStatusEx) VBoxServiceVerbose(3, "VBoxStatsInit: gCtx.GlobalMemoryStatusEx = %x\n", gCtx.pfnGlobalMemoryStatusEx); else { /** @todo Now fails in NT4; do we care? */ VBoxServiceVerbose(3, "VBoxStatsInit: kernel32.GlobalMemoryStatusEx not found!\n"); return VERR_SERVICE_DISABLED; } /* GetPerformanceInfo is xp and up, so load it dynamically */ *(void **)&gCtx.pfnGetPerformanceInfo = RTLdrGetSystemSymbol("psapi.dll", "GetPerformanceInfo"); if (gCtx.pfnGetPerformanceInfo) VBoxServiceVerbose(3, "VBoxStatsInit: gCtx.pfnGetPerformanceInfo= %x\n", gCtx.pfnGetPerformanceInfo); #endif /* RT_OS_WINDOWS */ return VINF_SUCCESS; }
RTDECL(int) RTSemXRoadsCreate(PRTSEMXROADS phXRoads) { RTSEMXROADSINTERNAL *pThis = (RTSEMXROADSINTERNAL *)RTMemAlloc(sizeof(*pThis)); if (!pThis) return VERR_NO_MEMORY; int rc = RTSemEventMultiCreate(&pThis->aDirs[0].hEvt); if (RT_SUCCESS(rc)) { rc = RTSemEventMultiCreate(&pThis->aDirs[1].hEvt); if (RT_SUCCESS(rc)) { pThis->u32Magic = RTSEMXROADS_MAGIC; pThis->u32Padding = 0; pThis->u64State = 0; pThis->aDirs[0].fNeedReset = false; pThis->aDirs[1].fNeedReset = false; *phXRoads = pThis; return VINF_SUCCESS; } RTSemEventMultiDestroy(pThis->aDirs[0].hEvt); } return rc; }
/** * 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; }
/** * 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; }
/** * @interface_method_impl{PDMDEVREG,pfnConstruct} */ static DECLCALLBACK(int) gimdevR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg) { PDMDEV_CHECK_VERSIONS_RETURN(pDevIns); RT_NOREF2(iInstance, pCfg); Assert(iInstance == 0); PGIMDEV pThis = PDMINS_2_DATA(pDevIns, PGIMDEV); /* * Initialize relevant state bits. */ pThis->pDevInsR3 = pDevIns; pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns); pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns); /* * Get debug setup requirements from GIM. */ PVM pVM = PDMDevHlpGetVM(pDevIns); int rc = GIMR3GetDebugSetup(pVM, &pThis->DbgSetup); if ( RT_SUCCESS(rc) && pThis->DbgSetup.cbDbgRecvBuf > 0) { /* * Attach the stream driver for the debug connection. */ PPDMISTREAM pDbgDrvStream = NULL; pThis->IDbgBase.pfnQueryInterface = gimdevR3QueryInterface; rc = PDMDevHlpDriverAttach(pDevIns, GIMDEV_DEBUG_LUN, &pThis->IDbgBase, &pThis->pDbgDrvBase, "GIM Debug Port"); if (RT_SUCCESS(rc)) { pDbgDrvStream = PDMIBASE_QUERY_INTERFACE(pThis->pDbgDrvBase, PDMISTREAM); if (pDbgDrvStream) LogRel(("GIMDev: LUN#%u: Debug port configured\n", GIMDEV_DEBUG_LUN)); else { LogRel(("GIMDev: LUN#%u: No unit\n", GIMDEV_DEBUG_LUN)); rc = VERR_INTERNAL_ERROR_2; } } else { pThis->pDbgDrvBase = NULL; LogRel(("GIMDev: LUN#%u: No debug port configured! rc=%Rrc\n", GIMDEV_DEBUG_LUN, rc)); } if (!pDbgDrvStream) { Assert(rc != VINF_SUCCESS); return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, N_("Debug port configuration expected when GIM configured with debugging support")); } void *pvDbgRecvBuf = RTMemAllocZ(pThis->DbgSetup.cbDbgRecvBuf); if (RT_UNLIKELY(!pvDbgRecvBuf)) { LogRel(("GIMDev: Failed to alloc %u bytes for debug receive buffer\n", pThis->DbgSetup.cbDbgRecvBuf)); return VERR_NO_MEMORY; } /* * Update the shared debug struct. */ pThis->Dbg.pDbgDrvStream = pDbgDrvStream; pThis->Dbg.pvDbgRecvBuf = pvDbgRecvBuf; pThis->Dbg.cbDbgRecvBufRead = 0; pThis->Dbg.fDbgRecvBufRead = false; /* * Create the sempahore and the debug receive thread itself. */ rc = RTSemEventMultiCreate(&pThis->Dbg.hDbgRecvThreadSem); if (RT_SUCCESS(rc)) { rc = RTThreadCreate(&pThis->hDbgRecvThread, gimDevR3DbgRecvThread, pDevIns, 0 /*cbStack*/, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "GIMDebugRecv"); if (RT_FAILURE(rc)) { RTSemEventMultiDestroy(pThis->Dbg.hDbgRecvThreadSem); pThis->Dbg.hDbgRecvThreadSem = NIL_RTSEMEVENTMULTI; RTMemFree(pThis->Dbg.pvDbgRecvBuf); pThis->Dbg.pvDbgRecvBuf = NULL; return rc; } } else return rc; } /* * Register this device with the GIM component. */ GIMR3GimDeviceRegister(pVM, pDevIns, pThis->DbgSetup.cbDbgRecvBuf ? &pThis->Dbg : NULL); /* * Get the MMIO2 regions from the GIM provider. */ uint32_t cRegions = 0; PGIMMMIO2REGION pRegionsR3 = GIMR3GetMmio2Regions(pVM, &cRegions); if ( cRegions && pRegionsR3) { /* * Register the MMIO2 regions. */ PGIMMMIO2REGION pCur = pRegionsR3; for (uint32_t i = 0; i < cRegions; i++, pCur++) { Assert(!pCur->fRegistered); rc = PDMDevHlpMMIO2Register(pDevIns, NULL, pCur->iRegion, pCur->cbRegion, 0 /* fFlags */, &pCur->pvPageR3, pCur->szDescription); if (RT_FAILURE(rc)) return rc; pCur->fRegistered = true; #if defined(VBOX_WITH_2X_4GB_ADDR_SPACE) RTR0PTR pR0Mapping = 0; rc = PDMDevHlpMMIO2MapKernel(pDevIns, NULL, pCur->iRegion, 0 /* off */, pCur->cbRegion, pCur->szDescription, &pR0Mapping); AssertLogRelMsgRCReturn(rc, ("PDMDevHlpMapMMIO2IntoR0(%#x,) -> %Rrc\n", pCur->cbRegion, rc), rc); pCur->pvPageR0 = pR0Mapping; #else pCur->pvPageR0 = (RTR0PTR)pCur->pvPageR3; #endif /* * Map into RC if required. */ if (pCur->fRCMapping) { RTRCPTR pRCMapping = 0; rc = PDMDevHlpMMHyperMapMMIO2(pDevIns, NULL, pCur->iRegion, 0 /* off */, pCur->cbRegion, pCur->szDescription, &pRCMapping); AssertLogRelMsgRCReturn(rc, ("PDMDevHlpMMHyperMapMMIO2(%#x,) -> %Rrc\n", pCur->cbRegion, rc), rc); pCur->pvPageRC = pRCMapping; } else pCur->pvPageRC = NIL_RTRCPTR; LogRel(("GIMDev: Registered %s\n", pCur->szDescription)); } } /** @todo Register SSM: PDMDevHlpSSMRegister(). */ /** @todo Register statistics: STAM_REG(). */ /** @todo Register DBGFInfo: PDMDevHlpDBGFInfoRegister(). */ return VINF_SUCCESS; }
/** * @interface_method_impl{VBOXSERVICE,pfnInit} */ static DECLCALLBACK(int) vgsvcTimeSyncInit(void) { /* * If not specified, find the right interval default. * Then create the event sem to block on. */ if (!g_TimeSyncInterval) g_TimeSyncInterval = g_DefaultInterval * 1000; if (!g_TimeSyncInterval) g_TimeSyncInterval = 10 * 1000; VbglR3GetSessionId(&g_idTimeSyncSession); /* The status code is ignored as this information is not available with VBox < 3.2.10. */ int rc = RTSemEventMultiCreate(&g_TimeSyncEvent); AssertRC(rc); #ifdef RT_OS_WINDOWS if (RT_SUCCESS(rc)) { /* * Adjust privileges of this process so we can make system time adjustments. */ if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &g_hTokenProcess)) { TOKEN_PRIVILEGES tkPriv; RT_ZERO(tkPriv); tkPriv.PrivilegeCount = 1; tkPriv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; if (LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkPriv.Privileges[0].Luid)) { DWORD cbRet = sizeof(g_TkOldPrivileges); if (AdjustTokenPrivileges(g_hTokenProcess, FALSE, &tkPriv, sizeof(TOKEN_PRIVILEGES), &g_TkOldPrivileges, &cbRet)) rc = VINF_SUCCESS; else { DWORD dwErr = GetLastError(); rc = RTErrConvertFromWin32(dwErr); VGSvcError("vgsvcTimeSyncInit: Adjusting token privileges (SE_SYSTEMTIME_NAME) failed with status code %u/%Rrc!\n", dwErr, rc); } } else { DWORD dwErr = GetLastError(); rc = RTErrConvertFromWin32(dwErr); VGSvcError("vgsvcTimeSyncInit: Looking up token privileges (SE_SYSTEMTIME_NAME) failed with status code %u/%Rrc!\n", dwErr, rc); } if (RT_FAILURE(rc)) { CloseHandle(g_hTokenProcess); g_hTokenProcess = NULL; } } else { DWORD dwErr = GetLastError(); rc = RTErrConvertFromWin32(dwErr); VGSvcError("vgsvcTimeSyncInit: Opening process token (SE_SYSTEMTIME_NAME) failed with status code %u/%Rrc!\n", dwErr, rc); g_hTokenProcess = NULL; } } if (GetSystemTimeAdjustment(&g_dwWinTimeAdjustment, &g_dwWinTimeIncrement, &g_bWinTimeAdjustmentDisabled)) VGSvcVerbose(3, "vgsvcTimeSyncInit: Initially %ld (100ns) units per %ld (100 ns) units interval, disabled=%d\n", g_dwWinTimeAdjustment, g_dwWinTimeIncrement, g_bWinTimeAdjustmentDisabled ? 1 : 0); else { DWORD dwErr = GetLastError(); rc = RTErrConvertFromWin32(dwErr); VGSvcError("vgsvcTimeSyncInit: Could not get time adjustment values! Last error: %ld!\n", dwErr); } #endif /* RT_OS_WINDOWS */ 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(); }
RTDECL(int) RTCritSectRwInitEx(PRTCRITSECTRW pThis, uint32_t fFlags, RTLOCKVALCLASS hClass, uint32_t uSubClass, const char *pszNameFmt, ...) { int rc; AssertReturn(!(fFlags & ~( RTCRITSECT_FLAGS_NO_NESTING | RTCRITSECT_FLAGS_NO_LOCK_VAL | RTCRITSECT_FLAGS_BOOTSTRAP_HACK | RTCRITSECT_FLAGS_NOP )), VERR_INVALID_PARAMETER); /* * Initialize the structure, allocate the lock validator stuff and sems. */ pThis->u32Magic = RTCRITSECTRW_MAGIC_DEAD; pThis->fNeedReset = false; #ifdef IN_RING0 pThis->fFlags = (uint16_t)(fFlags | RTCRITSECT_FLAGS_RING0); #else pThis->fFlags = (uint16_t)(fFlags & ~RTCRITSECT_FLAGS_RING0); #endif pThis->u64State = 0; pThis->hNativeWriter = NIL_RTNATIVETHREAD; pThis->cWriterReads = 0; pThis->cWriteRecursions = 0; pThis->hEvtWrite = NIL_RTSEMEVENT; pThis->hEvtRead = NIL_RTSEMEVENTMULTI; pThis->pValidatorWrite = NULL; pThis->pValidatorRead = NULL; #if HC_ARCH_BITS == 32 pThis->HCPtrPadding = NIL_RTHCPTR; #endif #ifdef RTCRITSECTRW_STRICT bool const fLVEnabled = !(fFlags & RTCRITSECT_FLAGS_NO_LOCK_VAL); if (!pszNameFmt) { static uint32_t volatile s_iAnon = 0; uint32_t i = ASMAtomicIncU32(&s_iAnon) - 1; rc = RTLockValidatorRecExclCreate(&pThis->pValidatorWrite, hClass, uSubClass, pThis, fLVEnabled, "RTCritSectRw-%u", i); if (RT_SUCCESS(rc)) rc = RTLockValidatorRecSharedCreate(&pThis->pValidatorRead, hClass, uSubClass, pThis, false /*fSignaller*/, fLVEnabled, "RTCritSectRw-%u", i); } else { va_list va; va_start(va, pszNameFmt); rc = RTLockValidatorRecExclCreateV(&pThis->pValidatorWrite, hClass, uSubClass, pThis, fLVEnabled, pszNameFmt, va); va_end(va); if (RT_SUCCESS(rc)) { va_start(va, pszNameFmt); RTLockValidatorRecSharedCreateV(&pThis->pValidatorRead, hClass, uSubClass, pThis, false /*fSignaller*/, fLVEnabled, pszNameFmt, va); va_end(va); } } if (RT_SUCCESS(rc)) rc = RTLockValidatorRecMakeSiblings(&pThis->pValidatorWrite->Core, &pThis->pValidatorRead->Core); if (RT_SUCCESS(rc)) #endif { rc = RTSemEventMultiCreate(&pThis->hEvtRead); if (RT_SUCCESS(rc)) { rc = RTSemEventCreate(&pThis->hEvtWrite); if (RT_SUCCESS(rc)) { pThis->u32Magic = RTCRITSECTRW_MAGIC; return VINF_SUCCESS; } RTSemEventMultiDestroy(pThis->hEvtRead); } } #ifdef RTCRITSECTRW_STRICT RTLockValidatorRecSharedDestroy(&pThis->pValidatorRead); RTLockValidatorRecExclDestroy(&pThis->pValidatorWrite); #endif return rc; }
int main() { RTR3InitExeNoArguments(0); /* * Just a simple testcase. */ RTPrintf("tstOnce: TESTING - smoke...\n"); RTONCE Once1 = RTONCE_INITIALIZER; g_fOnceCB1 = false; int rc = RTOnce(&Once1, Once1CB, (void *)1); if (rc != VINF_SUCCESS) RTPrintf("tstOnce: ERROR - Once1, 1 failed, rc=%Rrc\n", rc); g_fOnceCB1 = false; rc = RTOnce(&Once1, Once1CB, (void *)1); if (rc != VINF_SUCCESS) RTPrintf("tstOnce: ERROR - Once1, 2 failed, rc=%Rrc\n", rc); /* * Throw a bunch of threads up against a init once thing. */ RTPrintf("tstOnce: TESTING - bunch of threads...\n"); /* create the semaphore they'll be waiting on. */ rc = RTSemEventMultiCreate(&g_hEventMulti); if (RT_FAILURE(rc)) { RTPrintf("tstOnce: FATAL ERROR - RTSemEventMultiCreate returned %Rrc\n", rc); return 1; } /* create the threads */ RTTHREAD aThreads[32]; for (unsigned i = 0; i < RT_ELEMENTS(aThreads); i++) { char szName[16]; RTStrPrintf(szName, sizeof(szName), "ONCE2-%d\n", i); rc = RTThreadCreate(&aThreads[i], Once2Thread, NULL, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, szName); if (RT_FAILURE(rc)) { RTPrintf("tstOnce: ERROR - failed to create thread #%d\n", i); g_cErrors++; } } /* kick them off and yield */ rc = RTSemEventMultiSignal(g_hEventMulti); if (RT_FAILURE(rc)) { RTPrintf("tstOnce: FATAL ERROR - RTSemEventMultiSignal returned %Rrc\n", rc); return 1; } RTThreadYield(); /* wait for all of them to finish up, 30 seconds each. */ for (unsigned i = 0; i < RT_ELEMENTS(aThreads); i++) if (aThreads[i] != NIL_RTTHREAD) { int rc2; rc = RTThreadWait(aThreads[i], 30*1000, &rc2); if (RT_FAILURE(rc)) { RTPrintf("tstOnce: ERROR - RTThreadWait on thread #%u returned %Rrc\n", i, rc); g_cErrors++; } else if (RT_FAILURE(rc2)) { RTPrintf("tstOnce: ERROR - Thread #%u returned %Rrc\n", i, rc2); g_cErrors++; } } /* * Summary. */ if (!g_cErrors) RTPrintf("tstOnce: SUCCESS\n"); else RTPrintf("tstOnce: FAILURE - %d errors\n", g_cErrors); return !!g_cErrors; }
/** * Initialize a new thread, this actually creates the thread. * * @returns VBox status code. * @param pVM Pointer to the VM. * @param ppThread Where the thread instance data handle is. * @param cbStack The stack size, see RTThreadCreate(). * @param enmType The thread type, see RTThreadCreate(). * @param pszName The thread name, see RTThreadCreate(). */ static int pdmR3ThreadInit(PVM pVM, PPPDMTHREAD ppThread, size_t cbStack, RTTHREADTYPE enmType, const char *pszName) { PPDMTHREAD pThread = *ppThread; PUVM pUVM = pVM->pUVM; /* * Initialize the remainder of the structure. */ pThread->Internal.s.pVM = pVM; int rc = RTSemEventMultiCreate(&pThread->Internal.s.BlockEvent); if (RT_SUCCESS(rc)) { rc = RTSemEventMultiCreate(&pThread->Internal.s.SleepEvent); if (RT_SUCCESS(rc)) { /* * Create the thread and wait for it to initialize. * The newly created thread will set the PDMTHREAD::Thread member. */ RTTHREAD Thread; rc = RTThreadCreate(&Thread, pdmR3ThreadMain, pThread, cbStack, enmType, RTTHREADFLAGS_WAITABLE, pszName); if (RT_SUCCESS(rc)) { rc = RTThreadUserWait(Thread, 60*1000); if ( RT_SUCCESS(rc) && pThread->enmState != PDMTHREADSTATE_SUSPENDED) rc = VERR_PDM_THREAD_IPE_2; if (RT_SUCCESS(rc)) { /* * Insert it into the thread list. */ RTCritSectEnter(&pUVM->pdm.s.ListCritSect); pThread->Internal.s.pNext = NULL; if (pUVM->pdm.s.pThreadsTail) pUVM->pdm.s.pThreadsTail->Internal.s.pNext = pThread; else pUVM->pdm.s.pThreads = pThread; pUVM->pdm.s.pThreadsTail = pThread; RTCritSectLeave(&pUVM->pdm.s.ListCritSect); rc = RTThreadUserReset(Thread); AssertRC(rc); return rc; } /* bailout */ RTThreadWait(Thread, 60*1000, NULL); } RTSemEventMultiDestroy(pThread->Internal.s.SleepEvent); pThread->Internal.s.SleepEvent = NIL_RTSEMEVENTMULTI; } RTSemEventMultiDestroy(pThread->Internal.s.BlockEvent); pThread->Internal.s.BlockEvent = NIL_RTSEMEVENTMULTI; } MMHyperFree(pVM, pThread); *ppThread = NULL; return rc; }