DECLVBGL(void) VbglTerminate (void) { # ifdef VBOX_WITH_HGCM vbglR0HGCMTerminate (); # endif /* driver open could fail, which does not prevent VbglInit from succeeding, * close the driver only if it is opened */ if (vbglDriverIsOpened(&g_vbgldata.driver)) vbglDriverClose(&g_vbgldata.driver); RTSemMutexDestroy(g_vbgldata.mutexDriverInit); g_vbgldata.mutexDriverInit = NIL_RTSEMMUTEX; /* note: do vbglTerminateCommon as a last step since it zeroez up the g_vbgldata * conceptually, doing vbglTerminateCommon last is correct * since this is the reverse order to how init is done */ vbglTerminateCommon (); return; }
DECLVBGL(int) VbglInitClient(void) { int rc = VINF_SUCCESS; if ( g_vbgldata.status == VbglStatusInitializing || g_vbgldata.status == VbglStatusReady) { /* Initialization is already in process. */ return rc; } rc = vbglInitCommon (); if (RT_SUCCESS(rc)) { rc = RTSemMutexCreate(&g_vbgldata.mutexDriverInit); if (RT_SUCCESS(rc)) { /* Try to obtain VMMDev port via IOCTL to VBoxGuest main driver. */ vbglQueryDriverInfo (); # ifdef VBOX_WITH_HGCM rc = vbglR0HGCMInit (); # endif /* VBOX_WITH_HGCM */ if (RT_FAILURE(rc)) { RTSemMutexDestroy(g_vbgldata.mutexDriverInit); g_vbgldata.mutexDriverInit = NIL_RTSEMMUTEX; } } if (RT_FAILURE(rc)) { vbglTerminateCommon (); } } return rc; }
/** * Service request callback function. * * @returns VBox status code. * @param pSession The caller's session. * @param u64Arg 64-bit integer argument. * @param pReqHdr The request header. Input / Output. Optional. */ DECLEXPORT(int) TSTRTR0SemMutexSrvReqHandler(PSUPDRVSESSION pSession, uint32_t uOperation, uint64_t u64Arg, PSUPR0SERVICEREQHDR pReqHdr) { NOREF(pSession); if (!VALID_PTR(pReqHdr)) return VERR_INVALID_PARAMETER; char *pszErr = (char *)(pReqHdr + 1); size_t cchErr = pReqHdr->cbReq - sizeof(*pReqHdr); if (cchErr < 32 || cchErr >= 0x10000) return VERR_INVALID_PARAMETER; *pszErr = '\0'; #define SET_ERROR(szFmt) do { if (!*pszErr) RTStrPrintf(pszErr, cchErr, "!" szFmt); } while (0) #define SET_ERROR1(szFmt, a1) do { if (!*pszErr) RTStrPrintf(pszErr, cchErr, "!" szFmt, a1); } while (0) #define SET_ERROR2(szFmt, a1, a2) do { if (!*pszErr) RTStrPrintf(pszErr, cchErr, "!" szFmt, a1, a2); } while (0) #define SET_ERROR3(szFmt, a1, a2, a3) do { if (!*pszErr) RTStrPrintf(pszErr, cchErr, "!" szFmt, a1, a2, a3); } while (0) #define CHECK_RC_BREAK(rc, rcExpect, szOp) \ if ((rc) != (rcExpect)) \ { \ RTStrPrintf(pszErr, cchErr, "!%s -> %Rrc, expected %Rrc. line %u", szOp, rc, rcExpect, __LINE__); \ SUPR0Printf("%s -> %d, expected %d. line %u", szOp, rc, rcExpect, __LINE__); \ break; \ } /* * Set up test timeout (when applicable). */ if (u64Arg > 120) { SET_ERROR1("Timeout is too large (max 120): %lld", u64Arg); return VINF_SUCCESS; } uint64_t const StartTS = RTTimeSystemMilliTS(); uint32_t const cMsMax = (uint32_t)u64Arg * 1000; /* * The big switch. */ RTSEMMUTEX hMtx; int rc; switch (uOperation) { case TSTRTR0SEMMUTEX_SANITY_OK: break; case TSTRTR0SEMMUTEX_SANITY_FAILURE: SET_ERROR1("42failure42%1024s", ""); break; case TSTRTR0SEMMUTEX_BASIC: rc = RTSemMutexCreate(&hMtx); CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexCreate"); do { /* * The interruptible version first. */ /* simple request and release, polling. */ rc = RTSemMutexRequestNoResume(hMtx, 0); CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRequestNoResume"); rc = RTSemMutexRelease(hMtx); CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRelease"); /* simple request and release, wait for ever. */ rc = RTSemMutexRequestNoResume(hMtx, RT_INDEFINITE_WAIT); CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRequestNoResume(indef_wait)"); rc = RTSemMutexRelease(hMtx); CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRelease"); /* simple request and release, wait a tiny while. */ rc = RTSemMutexRequestNoResume(hMtx, 133); CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRequestNoResume(133)"); rc = RTSemMutexRelease(hMtx); CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRelease"); /* nested request and release. */ rc = RTSemMutexRequestNoResume(hMtx, RT_INDEFINITE_WAIT); CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRequestNoResume#1"); rc = RTSemMutexRequestNoResume(hMtx, RT_INDEFINITE_WAIT); CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRequestNoResume#2"); rc = RTSemMutexRequestNoResume(hMtx, RT_INDEFINITE_WAIT); CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRequestNoResume#3"); rc = RTSemMutexRelease(hMtx); CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRelease#3"); rc = RTSemMutexRequestNoResume(hMtx, RT_INDEFINITE_WAIT); CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRequestNoResume#3b"); rc = RTSemMutexRelease(hMtx); CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRelease#3b"); rc = RTSemMutexRelease(hMtx); CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRelease#2"); rc = RTSemMutexRelease(hMtx); CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRelease#1"); /* * The uninterruptible variant. */ /* simple request and release, polling. */ rc = RTSemMutexRequest(hMtx, 0); CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRequest"); rc = RTSemMutexRelease(hMtx); CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRelease"); /* simple request and release, wait for ever. */ rc = RTSemMutexRequest(hMtx, RT_INDEFINITE_WAIT); CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRequest(indef_wait)"); rc = RTSemMutexRelease(hMtx); CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRelease"); /* simple request and release, wait a tiny while. */ rc = RTSemMutexRequest(hMtx, 133); CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRequest(133)"); rc = RTSemMutexRelease(hMtx); CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRelease"); /* nested request and release. */ rc = RTSemMutexRequest(hMtx, RT_INDEFINITE_WAIT); CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRequest#1"); rc = RTSemMutexRequest(hMtx, RT_INDEFINITE_WAIT); CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRequest#2"); rc = RTSemMutexRequest(hMtx, RT_INDEFINITE_WAIT); CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRequest#3"); rc = RTSemMutexRelease(hMtx); CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRelease#3"); rc = RTSemMutexRequest(hMtx, RT_INDEFINITE_WAIT); CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRequest#3b"); rc = RTSemMutexRelease(hMtx); CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRelease#3b"); rc = RTSemMutexRelease(hMtx); CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRelease#2"); rc = RTSemMutexRelease(hMtx); CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRelease#1"); } while (false); rc = RTSemMutexDestroy(hMtx); CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexDestroy"); break; case TSTRTR0SEMMUTEX_TEST2_SETUP: case TSTRTR0SEMMUTEX_TEST3_SETUP: case TSTRTR0SEMMUTEX_TEST4_SETUP: rc = RTSemMutexCreate(&g_hMtxTest2); CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexCreate"); break; case TSTRTR0SEMMUTEX_TEST2_DO: for (unsigned i = 0; i < 200; i++) { if (i & 1) { rc = RTSemMutexRequestNoResume(g_hMtxTest2, RT_INDEFINITE_WAIT); CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRequestNoResume(,indef_wait)"); } else { rc = RTSemMutexRequestNoResume(g_hMtxTest2, 30000); CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRequestNoResume(,30000)"); } RTThreadSleep(1); rc = RTSemMutexRelease(g_hMtxTest2); CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRelease"); if ((i % 16) == 15 && RTTimeSystemMilliTS() - StartTS >= cMsMax) break; } break; case TSTRTR0SEMMUTEX_TEST3_DO: for (unsigned i = 0; i < 1000000; i++) { if (i & 1) { rc = RTSemMutexRequestNoResume(g_hMtxTest2, RT_INDEFINITE_WAIT); CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRequestNoResume(,indef_wait)"); } else { rc = RTSemMutexRequestNoResume(g_hMtxTest2, 30000); CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRequestNoResume(,30000)"); } rc = RTSemMutexRelease(g_hMtxTest2); CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRelease"); if ((i % 256) == 255 && RTTimeSystemMilliTS() - StartTS >= cMsMax) break; } break; case TSTRTR0SEMMUTEX_TEST4_DO: for (unsigned i = 0; i < 1024; i++) { rc = RTSemMutexRequestNoResume(g_hMtxTest2, (i % 32)); if (rc != VERR_TIMEOUT) { CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRequestNoResume"); RTThreadSleep(1000); rc = RTSemMutexRelease(g_hMtxTest2); CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRelease"); } if (RTTimeSystemMilliTS() - StartTS >= cMsMax) break; } break; case TSTRTR0SEMMUTEX_TEST2_CLEANUP: case TSTRTR0SEMMUTEX_TEST3_CLEANUP: case TSTRTR0SEMMUTEX_TEST4_CLEANUP: rc = RTSemMutexDestroy(g_hMtxTest2); CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexCreate"); g_hMtxTest2 = NIL_RTSEMMUTEX; break; default: SET_ERROR1("Unknown test #%d", uOperation); break; } /* The error indicator is the '!' in the message buffer. */ return VINF_SUCCESS; }
static int Test1(unsigned cThreads, unsigned cSeconds, bool fYield, bool fQuiet) { int rc; unsigned i; uint64_t g_au64[32]; RTTHREAD aThreads[RT_ELEMENTS(g_au64)]; AssertRelease(cThreads <= RT_ELEMENTS(g_au64)); /* * Init globals. */ g_fYield = fYield; g_fQuiet = fQuiet; g_fTerminate = false; rc = RTSemMutexCreate(&g_hMutex); if (RT_FAILURE(rc)) return PrintError("RTSemMutexCreate failed (rc=%Rrc)\n", rc); /* * Create the threads and let them block on the mutex. */ rc = RTSemMutexRequest(g_hMutex, RT_INDEFINITE_WAIT); if (RT_FAILURE(rc)) return PrintError("RTSemMutexRequest failed (rc=%Rrc)\n", rc); for (i = 0; i < cThreads; i++) { g_au64[i] = 0; rc = RTThreadCreate(&aThreads[i], ThreadTest1, &g_au64[i], 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "test"); if (RT_FAILURE(rc)) return PrintError("RTThreadCreate failed for thread %u (rc=%Rrc)\n", i, rc); } if (!fQuiet) RTPrintf("tstSemMutex: %zu Threads created. Racing them for %u seconds (%s) ...\n", cThreads, cSeconds, g_fYield ? "yielding" : "no yielding"); uint64_t u64StartTS = RTTimeNanoTS(); rc = RTSemMutexRelease(g_hMutex); if (RT_FAILURE(rc)) PrintError("RTSemMutexRelease failed (rc=%Rrc)\n", rc); RTThreadSleep(cSeconds * 1000); ASMAtomicXchgBool(&g_fTerminate, true); uint64_t ElapsedNS = RTTimeNanoTS() - u64StartTS; for (i = 0; i < cThreads; i++) { rc = RTThreadWait(aThreads[i], 5000, NULL); if (RT_FAILURE(rc)) PrintError("RTThreadWait failed for thread %u (rc=%Rrc)\n", i, rc); } rc = RTSemMutexDestroy(g_hMutex); if (RT_FAILURE(rc)) PrintError("RTSemMutexDestroy failed - %Rrc\n", rc); g_hMutex = NIL_RTSEMMUTEX; if (g_cErrors) RTThreadSleep(100); /* * Collect and display the results. */ uint64_t Total = g_au64[0]; for (i = 1; i < cThreads; i++) Total += g_au64[i]; uint64_t Normal = Total / cThreads; uint64_t MaxDeviation = 0; for (i = 0; i < cThreads; i++) { uint64_t Delta = RT_ABS((int64_t)(g_au64[i] - Normal)); if (Delta > Normal / 2) RTPrintf("tstSemMutex: Warning! Thread %d deviates by more than 50%% - %llu (it) vs. %llu (avg)\n", i, g_au64[i], Normal); if (Delta > MaxDeviation) MaxDeviation = Delta; } RTPrintf("tstSemMutex: Threads: %u Total: %llu Per Sec: %llu Avg: %llu ns Max dev: %llu%%\n", cThreads, Total, Total / cSeconds, ElapsedNS / Total, MaxDeviation * 100 / Normal ); return 0; }