static void TestNegative(void) { RTTestSub(g_hTest, "Negative"); bool fSavedAssertQuiet = RTAssertSetQuiet(true); bool fSavedAssertMayPanic = RTAssertSetMayPanic(false); bool fSavedLckValEnabled = RTLockValidatorSetEnabled(false); RTCRITSECTRW CritSectRw; RTTEST_CHECK_RC_RETV(g_hTest, RTCritSectRwInit(&CritSectRw), VINF_SUCCESS); RTTEST_CHECK_RC(g_hTest, RTCritSectRwLeaveShared(&CritSectRw), VERR_NOT_OWNER); RTTEST_CHECK_RC(g_hTest, RTCritSectRwLeaveExcl(&CritSectRw), VERR_NOT_OWNER); RTTEST_CHECK_RC(g_hTest, RTCritSectRwEnterExcl(&CritSectRw), VINF_SUCCESS); RTTEST_CHECK_RC(g_hTest, RTCritSectRwLeaveShared(&CritSectRw), VERR_NOT_OWNER); RTTEST_CHECK_RC(g_hTest, RTCritSectRwEnterShared(&CritSectRw), VINF_SUCCESS); RTTEST_CHECK_RC(g_hTest, RTCritSectRwLeaveExcl(&CritSectRw), VERR_WRONG_ORDER); /* cannot release the final write before the reads. */ RTTEST_CHECK_RC(g_hTest, RTCritSectRwLeaveShared(&CritSectRw), VINF_SUCCESS); RTTEST_CHECK_RC(g_hTest, RTCritSectRwLeaveExcl(&CritSectRw), VINF_SUCCESS); RTTEST_CHECK_RC(g_hTest, RTCritSectRwDelete(&CritSectRw), VINF_SUCCESS); RTLockValidatorSetEnabled(fSavedLckValEnabled); RTAssertSetMayPanic(fSavedAssertMayPanic); RTAssertSetQuiet(fSavedAssertQuiet); }
static void Test3(void) { RTTestSub(g_hTest, "Negative"); bool fSavedAssertQuiet = RTAssertSetQuiet(true); bool fSavedAssertMayPanic = RTAssertSetMayPanic(false); bool fSavedLckValEnabled = RTLockValidatorSetEnabled(false); RTSEMRW hSemRW; RTTEST_CHECK_RC_RETV(g_hTest, RTSemRWCreate(&hSemRW), VINF_SUCCESS); RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseRead(hSemRW), VERR_NOT_OWNER); RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(hSemRW), VERR_NOT_OWNER); RTTEST_CHECK_RC(g_hTest, RTSemRWRequestWrite(hSemRW, RT_INDEFINITE_WAIT), VINF_SUCCESS); RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseRead(hSemRW), VERR_NOT_OWNER); RTTEST_CHECK_RC(g_hTest, RTSemRWRequestRead(hSemRW, RT_INDEFINITE_WAIT), VINF_SUCCESS); RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(hSemRW), VERR_WRONG_ORDER); /* cannot release the final write before the reads. */ RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseRead(hSemRW), VINF_SUCCESS); RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(hSemRW), VINF_SUCCESS); RTTEST_CHECK_RC(g_hTest, RTSemRWDestroy(hSemRW), VINF_SUCCESS); RTLockValidatorSetEnabled(fSavedLckValEnabled); RTAssertSetMayPanic(fSavedAssertMayPanic); RTAssertSetQuiet(fSavedAssertQuiet); }
static void Test2(void) { RTTestSub(g_hTest, "Timeout"); RTSEMRW hSemRW = NIL_RTSEMRW; RTTEST_CHECK_RC_RETV(g_hTest, RTSemRWCreate(&hSemRW), VINF_SUCCESS); /* Lock it for writing and let the thread do the remainder of the test. */ RTTEST_CHECK_RC_RETV(g_hTest, RTSemRWRequestWrite(hSemRW, RT_INDEFINITE_WAIT), VINF_SUCCESS); RTTHREAD hThread; RTTEST_CHECK_RC_RETV(g_hTest, RTThreadCreate(&hThread, Test2Thread, hSemRW, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "test2"), VINF_SUCCESS); RTTEST_CHECK_RC(g_hTest, RTThreadWait(hThread, 15000, NULL), VINF_SUCCESS); RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(hSemRW), VINF_SUCCESS); RTTEST_CHECK_RC(g_hTest, RTSemRWDestroy(hSemRW), VINF_SUCCESS); }
static void Test4(unsigned cThreads, unsigned cSeconds, unsigned uWritePercent, bool fYield, bool fQuiet) { unsigned i; uint64_t acIterations[32]; RTTHREAD aThreads[RT_ELEMENTS(acIterations)]; AssertRelease(cThreads <= RT_ELEMENTS(acIterations)); RTTestSubF(g_hTest, "Test4 - %u threads, %u sec, %u%% writes, %syielding", cThreads, cSeconds, uWritePercent, fYield ? "" : "non-"); /* * Init globals. */ g_fYield = fYield; g_fQuiet = fQuiet; g_fTerminate = false; g_uWritePercent = uWritePercent; g_cConcurrentWriters = 0; g_cConcurrentReaders = 0; RTTEST_CHECK_RC_RETV(g_hTest, RTCritSectRwInit(&g_CritSectRw), VINF_SUCCESS); /* * Create the threads and let them block on the semrw. */ RTTEST_CHECK_RC_RETV(g_hTest, RTCritSectRwEnterExcl(&g_CritSectRw), VINF_SUCCESS); for (i = 0; i < cThreads; i++) { acIterations[i] = 0; RTTEST_CHECK_RC_RETV(g_hTest, RTThreadCreateF(&aThreads[i], Test4Thread, &acIterations[i], 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "test-%u", i), VINF_SUCCESS); } /* * Do the test run. */ uint32_t cErrorsBefore = RTTestErrorCount(g_hTest); uint64_t u64StartTS = RTTimeNanoTS(); RTTEST_CHECK_RC(g_hTest, RTCritSectRwLeaveExcl(&g_CritSectRw), VINF_SUCCESS); RTThreadSleep(cSeconds * 1000); ASMAtomicWriteBool(&g_fTerminate, true); uint64_t ElapsedNS = RTTimeNanoTS() - u64StartTS; /* * Clean up the threads and semaphore. */ for (i = 0; i < cThreads; i++) RTTEST_CHECK_RC(g_hTest, RTThreadWait(aThreads[i], 5000, NULL), VINF_SUCCESS); RTTEST_CHECK_MSG(g_hTest, g_cConcurrentWriters == 0, (g_hTest, "g_cConcurrentWriters=%u at end of test\n", g_cConcurrentWriters)); RTTEST_CHECK_MSG(g_hTest, g_cConcurrentReaders == 0, (g_hTest, "g_cConcurrentReaders=%u at end of test\n", g_cConcurrentReaders)); RTTEST_CHECK_RC(g_hTest, RTCritSectRwDelete(&g_CritSectRw), VINF_SUCCESS); if (RTTestErrorCount(g_hTest) != cErrorsBefore) RTThreadSleep(100); /* * Collect and display the results. */ uint64_t cItrTotal = acIterations[0]; for (i = 1; i < cThreads; i++) cItrTotal += acIterations[i]; uint64_t cItrNormal = cItrTotal / cThreads; uint64_t cItrMinOK = cItrNormal / 20; /* 5% */ uint64_t cItrMaxDeviation = 0; for (i = 0; i < cThreads; i++) { uint64_t cItrDelta = RT_ABS((int64_t)(acIterations[i] - cItrNormal)); if (acIterations[i] < cItrMinOK) RTTestFailed(g_hTest, "Thread %u did less than 5%% of the iterations - %llu (it) vs. %llu (5%%) - %llu%%\n", i, acIterations[i], cItrMinOK, cItrDelta * 100 / cItrNormal); else if (cItrDelta > cItrNormal / 2) RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Warning! Thread %u deviates by more than 50%% - %llu (it) vs. %llu (avg) - %llu%%\n", i, acIterations[i], cItrNormal, cItrDelta * 100 / cItrNormal); if (cItrDelta > cItrMaxDeviation) cItrMaxDeviation = cItrDelta; } //RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, // "Threads: %u Total: %llu Per Sec: %llu Avg: %llu ns Max dev: %llu%%\n", // cThreads, // cItrTotal, // cItrTotal / cSeconds, // ElapsedNS / cItrTotal, // cItrMaxDeviation * 100 / cItrNormal // ); // RTTestValue(g_hTest, "Thruput", cItrTotal * UINT32_C(1000000000) / ElapsedNS, RTTESTUNIT_CALLS_PER_SEC); RTTestValue(g_hTest, "Max diviation", cItrMaxDeviation * 100 / cItrNormal, RTTESTUNIT_PCT); }
static void tstTraffic(unsigned cThreads, unsigned cSecs) { RTTestSubF(g_hTest, "Traffic - %u threads per direction, %u sec", cThreads, cSecs); /* * Create X worker threads which drives in the south/north direction and Y * worker threads which drives in the west/east direction. Let them drive * in a loop for 15 seconds with slight delays between some of the runs and * then check the numbers. */ /* init */ RTTHREAD ahThreadsX[8]; for (unsigned i = 0; i < RT_ELEMENTS(ahThreadsX); i++) ahThreadsX[i] = NIL_RTTHREAD; AssertRelease(RT_ELEMENTS(ahThreadsX) >= cThreads); RTTHREAD ahThreadsY[8]; for (unsigned i = 0; i < RT_ELEMENTS(ahThreadsY); i++) ahThreadsY[i] = NIL_RTTHREAD; AssertRelease(RT_ELEMENTS(ahThreadsY) >= cThreads); g_cNSCrossings = 0; g_cEWCrossings = 0; g_cSecs = cSecs; g_u64StartMilliTS = RTTimeMilliTS(); /* create */ RTTEST_CHECK_RC_RETV(g_hTest, RTSemXRoadsCreate(&g_hXRoads), VINF_SUCCESS); int rc = VINF_SUCCESS; for (unsigned i = 0; i < cThreads && RT_SUCCESS(rc); i++) { rc = RTThreadCreateF(&ahThreadsX[i], tstTrafficNSThread, (void *)(uintptr_t)i, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "NS-%u", i); RTTEST_CHECK_RC_OK(g_hTest, rc); } for (unsigned i = 0; i < cThreads && RT_SUCCESS(rc); i++) { rc = RTThreadCreateF(&ahThreadsX[i], tstTrafficEWThread, (void *)(uintptr_t)i, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "NS-%u", i); RTTEST_CHECK_RC_OK(g_hTest, rc); } /* wait */ for (unsigned i = 0; i < RT_ELEMENTS(ahThreadsX); i++) if (ahThreadsX[i] != NIL_RTTHREAD) { int rc2 = RTThreadWaitNoResume(ahThreadsX[i], (60 + cSecs) * 1000, NULL); RTTEST_CHECK_RC_OK(g_hTest, rc2); } for (unsigned i = 0; i < RT_ELEMENTS(ahThreadsY); i++) if (ahThreadsY[i] != NIL_RTTHREAD) { int rc2 = RTThreadWaitNoResume(ahThreadsY[i], (60 + cSecs) * 1000, NULL); RTTEST_CHECK_RC_OK(g_hTest, rc2); } RTTEST_CHECK_MSG_RETV(g_hTest, g_cEWCrossings > 10 && g_cNSCrossings, (g_hTest, "cEWCrossings=%u g_cNSCrossings=%u\n", g_cEWCrossings, g_cNSCrossings)); RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "cNSCrossings=%u\n", g_cNSCrossings); RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "cEWCrossings=%u\n", g_cEWCrossings); }