RTDECL(int) RTSemXRoadsDestroy(RTSEMXROADS hXRoads) { /* * Validate input. */ RTSEMXROADSINTERNAL *pThis = hXRoads; if (pThis == NIL_RTSEMXROADS) return VINF_SUCCESS; AssertPtrReturn(pThis, VERR_INVALID_HANDLE); AssertReturn(pThis->u32Magic == RTSEMXROADS_MAGIC, VERR_INVALID_HANDLE); Assert(!(ASMAtomicReadU64(&pThis->u64State) & (RTSEMXROADS_CNT_NS_MASK | RTSEMXROADS_CNT_EW_MASK))); /* * Invalidate the object and free up the resources. */ AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, RTSEMXROADS_MAGIC_DEAD, RTSEMXROADS_MAGIC), VERR_INVALID_HANDLE); RTSEMEVENTMULTI hEvt; ASMAtomicXchgHandle(&pThis->aDirs[0].hEvt, NIL_RTSEMEVENTMULTI, &hEvt); int rc = RTSemEventMultiDestroy(hEvt); AssertRC(rc); ASMAtomicXchgHandle(&pThis->aDirs[1].hEvt, NIL_RTSEMEVENTMULTI, &hEvt); rc = RTSemEventMultiDestroy(hEvt); AssertRC(rc); RTMemFree(pThis); return VINF_SUCCESS; }
/** * Free an mbox. */ void sys_mbox_free(sys_mbox_t mbox) { Assert(mbox != NULL); LWIPMutexDestroy(mbox->mutex); RTSemEventMultiDestroy(mbox->nonempty); RTSemEventMultiDestroy(mbox->nonfull); RTMemFree(mbox); }
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(); }
/** * Free an mbox. */ void sys_mbox_free(sys_mbox_t *pvMbox) { struct sys_mbox *mbox = NULL; Assert(pvMbox && *pvMbox); mbox = (struct sys_mbox*)*pvMbox; LWIPMutexDestroy((mbox)->mutex); RTSemEventMultiDestroy((mbox)->nonempty); RTSemEventMultiDestroy((mbox)->nonfull); RTMemFree(mbox); *pvMbox = NULL; }
/** * Destroys the per thread data. * * @param pThread The thread to destroy. */ static void rtThreadDestroy(PRTTHREADINT pThread) { RTSEMEVENTMULTI hEvt1, hEvt2; /* * Remove it from the tree and mark it as dead. * * Threads that has seen rtThreadTerminate and should already have been * removed from the tree. There is probably no thread that should * require removing here. However, be careful making sure that cRefs * isn't 0 if we do or we'll blow up because the strict locking code * will be calling us back. */ if (ASMBitTest(&pThread->fIntFlags, RTTHREADINT_FLAG_IN_TREE_BIT)) { ASMAtomicIncU32(&pThread->cRefs); rtThreadRemove(pThread); ASMAtomicDecU32(&pThread->cRefs); } /* * Invalidate the thread structure. */ #ifdef IN_RING3 rtLockValidatorSerializeDestructEnter(); rtLockValidatorDeletePerThread(&pThread->LockValidator); #endif #ifdef RT_WITH_ICONV_CACHE rtStrIconvCacheDestroy(pThread); #endif ASMAtomicXchgU32(&pThread->u32Magic, RTTHREADINT_MAGIC_DEAD); ASMAtomicWritePtr(&pThread->Core.Key, (void *)NIL_RTTHREAD); pThread->enmType = RTTHREADTYPE_INVALID; hEvt1 = pThread->EventUser; pThread->EventUser = NIL_RTSEMEVENTMULTI; hEvt2 = pThread->EventTerminated; pThread->EventTerminated = NIL_RTSEMEVENTMULTI; #ifdef IN_RING3 rtLockValidatorSerializeDestructLeave(); #endif /* * Destroy semaphore resources and free the bugger. */ RTSemEventMultiDestroy(hEvt1); if (hEvt2 != NIL_RTSEMEVENTMULTI) RTSemEventMultiDestroy(hEvt2); rtThreadNativeDestroy(pThread); RTMemFree(pThread); }
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); }
/** @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; }
RTDECL(int) RTSemRWDestroy(RTSEMRW hRWSem) { /* * Validate input. */ RTSEMRWINTERNAL *pThis = hRWSem; if (pThis == NIL_RTSEMRW) return VINF_SUCCESS; AssertPtrReturn(pThis, VERR_INVALID_HANDLE); AssertReturn(pThis->u32Magic == RTSEMRW_MAGIC, VERR_INVALID_HANDLE); Assert(!(ASMAtomicReadU64(&pThis->u64State) & (RTSEMRW_CNT_RD_MASK | RTSEMRW_CNT_WR_MASK))); /* * Invalidate the object and free up the resources. */ AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, ~RTSEMRW_MAGIC, RTSEMRW_MAGIC), VERR_INVALID_HANDLE); RTSEMEVENTMULTI hEvtRead; ASMAtomicXchgHandle(&pThis->hEvtRead, NIL_RTSEMEVENTMULTI, &hEvtRead); int rc = RTSemEventMultiDestroy(hEvtRead); AssertRC(rc); RTSEMEVENT hEvtWrite; ASMAtomicXchgHandle(&pThis->hEvtWrite, NIL_RTSEMEVENT, &hEvtWrite); rc = RTSemEventDestroy(hEvtWrite); AssertRC(rc); #ifdef RTSEMRW_STRICT RTLockValidatorRecSharedDelete(&pThis->ValidatorRead); RTLockValidatorRecExclDelete(&pThis->ValidatorWrite); #endif RTMemFree(pThis); return VINF_SUCCESS; }
/** * Uninitializes the instance and sets the ready flag to FALSE. * * Called either from FinalRelease() or by the parent when it gets destroyed. */ void Progress::uninit() { LogFlowThisFunc(("\n")); /* Enclose the state transition Ready->InUninit->NotReady */ AutoUninitSpan autoUninitSpan(this); if (autoUninitSpan.uninitDone()) return; /* wake up all threads still waiting on occasion */ if (mWaitersCount > 0) { LogFlow(("WARNING: There are still %d threads waiting for '%s' completion!\n", mWaitersCount, mDescription.c_str())); RTSemEventMultiSignal(mCompletedSem); } RTSemEventMultiDestroy(mCompletedSem); /* release initiator (effective only if mInitiator has been assigned in * * init()) */ unconst(mInitiator).setNull(); #if !defined(VBOX_COM_INPROC) if (mParent) { /* remove the added progress on failure to complete the initialization */ if (autoUninitSpan.initFailed() && mId.isValid() && !mId.isZero()) mParent->i_removeProgress(mId.ref()); unconst(mParent) = NULL; } #endif }
/** @copydoc VBOXSERVICE::pfnTerm */ static DECLCALLBACK(void) VBoxServiceVMInfoTerm(void) { if (g_hVMInfoEvent != NIL_RTSEMEVENTMULTI) { /** @todo temporary solution: Zap all values which are not valid * anymore when VM goes down (reboot/shutdown ). Needs to * be replaced with "temporary properties" later. * * One idea is to introduce a (HGCM-)session guest property * flag meaning that a guest property is only valid as long * as the HGCM session isn't closed (e.g. guest application * terminates). [don't remove till implemented] */ /** @todo r=bird: Drop the VbglR3GuestPropDelSet call here and use the cache * since it remembers what we've written. */ /* Delete the "../Net" branch. */ const char *apszPat[1] = { "/VirtualBox/GuestInfo/Net/*" }; int rc = VbglR3GuestPropDelSet(g_uVMInfoGuestPropSvcClientID, &apszPat[0], RT_ELEMENTS(apszPat)); /* Destroy property cache. */ VBoxServicePropCacheDestroy(&g_VMInfoPropCache); /* Disconnect from guest properties service. */ rc = VbglR3GuestPropDisconnect(g_uVMInfoGuestPropSvcClientID); if (RT_FAILURE(rc)) VBoxServiceError("VMInfo: Failed to disconnect from guest property service! Error: %Rrc\n", rc); g_uVMInfoGuestPropSvcClientID = 0; RTSemEventMultiDestroy(g_hVMInfoEvent); g_hVMInfoEvent = NIL_RTSEMEVENTMULTI; } }
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; }
/** * @interface_method_impl{VBOXSERVICE,pfnTerm} */ static DECLCALLBACK(void) vgsvcVMStatsTerm(void) { if (g_VMStatEvent != NIL_RTSEMEVENTMULTI) { RTSemEventMultiDestroy(g_VMStatEvent); g_VMStatEvent = NIL_RTSEMEVENTMULTI; } }
/** * 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; }
/** @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; }
/** * Frees a request. * * @param pReq The request. */ DECLHIDDEN(void) rtReqFreeIt(PRTREQINT pReq) { Assert(pReq->u32Magic == RTREQ_MAGIC); Assert(pReq->cRefs == 0); pReq->u32Magic = RTREQ_MAGIC_DEAD; RTSemEventDestroy(pReq->EventSem); pReq->EventSem = NIL_RTSEMEVENT; RTSemEventMultiDestroy(pReq->hPushBackEvt); pReq->hPushBackEvt = NIL_RTSEMEVENTMULTI; RTMemFree(pReq); }
/** @copydoc VBOXSERVICE::pfnTerm */ static DECLCALLBACK(void) VBoxServiceAutoMountTerm(void) { VBoxServiceVerbose(3, "VBoxServiceAutoMountTerm\n"); VbglR3SharedFolderDisconnect(g_SharedFoldersSvcClientID); g_SharedFoldersSvcClientID = 0; if (g_AutoMountEvent != NIL_RTSEMEVENTMULTI) { RTSemEventMultiDestroy(g_AutoMountEvent); g_AutoMountEvent = NIL_RTSEMEVENTMULTI; } return; }
/** * @interface_method_impl{PDMDEVREG,pfnDestruct} */ static DECLCALLBACK(int) gimdevR3Destruct(PPDMDEVINS pDevIns) { PGIMDEV pThis = PDMINS_2_DATA(pDevIns, PGIMDEV); PVM pVM = PDMDevHlpGetVM(pDevIns); uint32_t cRegions = 0; PGIMMMIO2REGION pCur = GIMR3GetMmio2Regions(pVM, &cRegions); for (uint32_t i = 0; i < cRegions; i++, pCur++) { int rc = PDMDevHlpMMIOExDeregister(pDevIns, NULL, pCur->iRegion); if (RT_FAILURE(rc)) return rc; } /* * Signal and wait for the debug thread to terminate. */ if (pThis->hDbgRecvThread != NIL_RTTHREAD) { pThis->fDbgRecvThreadShutdown = true; if (pThis->Dbg.hDbgRecvThreadSem != NIL_RTSEMEVENT) RTSemEventMultiSignal(pThis->Dbg.hDbgRecvThreadSem); int rc = RTThreadWait(pThis->hDbgRecvThread, 20000, NULL /*prc*/); if (RT_SUCCESS(rc)) pThis->hDbgRecvThread = NIL_RTTHREAD; else { LogRel(("GIMDev: Debug thread did not terminate, rc=%Rrc!\n", rc)); return VERR_RESOURCE_BUSY; } } /* * Now clean up the semaphore & buffer now that the thread is gone. */ if (pThis->Dbg.hDbgRecvThreadSem != NIL_RTSEMEVENT) { RTSemEventMultiDestroy(pThis->Dbg.hDbgRecvThreadSem); pThis->Dbg.hDbgRecvThreadSem = NIL_RTSEMEVENTMULTI; } if (pThis->Dbg.pvDbgRecvBuf) { RTMemFree(pThis->Dbg.pvDbgRecvBuf); pThis->Dbg.pvDbgRecvBuf = NULL; } return VINF_SUCCESS; }
/** * 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; }
/** * 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; }
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; }
/** * @interface_method_impl{VBOXSERVICE,pfnTerm} */ static DECLCALLBACK(void) vgsvcTimeSyncTerm(void) { #ifdef RT_OS_WINDOWS /* * Restore the SE_SYSTEMTIME_NAME token privileges (if init succeeded). */ if (g_hTokenProcess) { if (!AdjustTokenPrivileges(g_hTokenProcess, FALSE, &g_TkOldPrivileges, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) { DWORD dwErr = GetLastError(); VGSvcError("vgsvcTimeSyncTerm: Restoring token privileges (SE_SYSTEMTIME_NAME) failed with code %u!\n", dwErr); } CloseHandle(g_hTokenProcess); g_hTokenProcess = NULL; } #endif /* !RT_OS_WINDOWS */ if (g_TimeSyncEvent != NIL_RTSEMEVENTMULTI) { RTSemEventMultiDestroy(g_TimeSyncEvent); g_TimeSyncEvent = NIL_RTSEMEVENTMULTI; } }
/** @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; }
/** * Destructor for objects created by SUPSemEventMultiCreate. * * @param pvObj The object handle. * @param pvUser1 The IPRT event handle. * @param pvUser2 NULL. */ static DECLCALLBACK(void) supR0SemEventMultiDestructor(void *pvObj, void *pvUser1, void *pvUser2) { Assert(pvUser2 == NULL); NOREF(pvObj); RTSemEventMultiDestroy((RTSEMEVENTMULTI)pvUser1); }
/** * 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) RTSemRWCreateEx(PRTSEMRW phRWSem, uint32_t fFlags, RTLOCKVALCLASS hClass, uint32_t uSubClass, const char *pszNameFmt, ...) { AssertReturn(!(fFlags & ~RTSEMRW_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER); /* * Allocate memory. */ int rc; struct RTSEMRWINTERNAL *pThis = (struct RTSEMRWINTERNAL *)RTMemAlloc(sizeof(struct RTSEMRWINTERNAL)); if (pThis) { /* * Create the semaphores. */ rc = RTSemEventCreateEx(&pThis->WriteEvent, RTSEMEVENT_FLAGS_NO_LOCK_VAL, NIL_RTLOCKVALCLASS, NULL); if (RT_SUCCESS(rc)) { rc = RTSemEventMultiCreateEx(&pThis->ReadEvent, RTSEMEVENT_FLAGS_NO_LOCK_VAL, NIL_RTLOCKVALCLASS, NULL); if (RT_SUCCESS(rc)) { rc = RTCritSectInitEx(&pThis->CritSect, RTCRITSECT_FLAGS_NO_LOCK_VAL, NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_NONE, NULL); if (RT_SUCCESS(rc)) { /* * Signal the read semaphore and initialize other variables. */ rc = RTSemEventMultiSignal(pThis->ReadEvent); if (RT_SUCCESS(rc)) { pThis->u32Padding = UINT32_C(0xa5a55a5a); pThis->cReads = 0; pThis->cWrites = 0; pThis->cWriterReads = 0; pThis->cWritesWaiting = 0; pThis->hWriter = NIL_RTNATIVETHREAD; pThis->fNeedResetReadEvent = true; pThis->u32Magic = RTSEMRW_MAGIC; #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; } RTCritSectDelete(&pThis->CritSect); } RTSemEventMultiDestroy(pThis->ReadEvent); } RTSemEventDestroy(pThis->WriteEvent); } RTMemFree(pThis); } else rc = VERR_NO_MEMORY; return rc; }
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; }
/** * @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,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; }