VirtualBox

source: vbox/trunk/src/VBox/Runtime/testcase/tstRTLockValidator.cpp@ 78395

Last change on this file since 78395 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 60.4 KB
Line 
1/* $Id: tstRTLockValidator.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * IPRT Testcase - RTLockValidator.
4 */
5
6/*
7 * Copyright (C) 2006-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <iprt/lockvalidator.h>
32
33#include <iprt/asm.h> /* for return addresses */
34#include <iprt/critsect.h>
35#include <iprt/err.h>
36#include <iprt/semaphore.h>
37#include <iprt/test.h>
38#include <iprt/thread.h>
39#include <iprt/time.h>
40
41
42/*********************************************************************************************************************************
43* Defined Constants And Macros *
44*********************************************************************************************************************************/
45#define SECS_SIMPLE_TEST 1
46#define SECS_RACE_TEST 3
47#define TEST_SMALL_TIMEOUT ( 10*1000)
48#define TEST_LARGE_TIMEOUT ( 60*1000)
49#define TEST_DEBUG_TIMEOUT (3600*1000)
50
51
52/*********************************************************************************************************************************
53* Global Variables *
54*********************************************************************************************************************************/
55/** The testcase handle. */
56static RTTEST g_hTest;
57/** Flip this in the debugger to get some peace to single step wild code. */
58bool volatile g_fDoNotSpin = false;
59
60/** Set when the main thread wishes to terminate the test. */
61bool volatile g_fShutdown = false;
62/** The number of threads. */
63static uint32_t g_cThreads;
64static uint32_t g_iDeadlockThread;
65static RTTHREAD g_ahThreads[32];
66static RTLOCKVALCLASS g_ahClasses[32];
67static RTCRITSECT g_aCritSects[32];
68static RTSEMRW g_ahSemRWs[32];
69static RTSEMMUTEX g_ahSemMtxes[32];
70static RTSEMEVENT g_hSemEvt;
71static RTSEMEVENTMULTI g_hSemEvtMulti;
72
73/** Multiple release event semaphore that is signalled by the main thread after
74 * it has started all the threads. */
75static RTSEMEVENTMULTI g_hThreadsStartedEvt;
76
77/** The number of threads that have called testThreadBlocking */
78static uint32_t volatile g_cThreadsBlocking;
79/** Multiple release event semaphore that is signalled by the last thread to
80 * call testThreadBlocking. testWaitForAllOtherThreadsToSleep waits on this. */
81static RTSEMEVENTMULTI g_hThreadsBlockingEvt;
82
83/** When to stop testing. */
84static uint64_t g_NanoTSStop;
85/** The number of deadlocks. */
86static uint32_t volatile g_cDeadlocks;
87/** The number of loops. */
88static uint32_t volatile g_cLoops;
89
90
91/**
92 * Spin until the callback stops returning VERR_TRY_AGAIN.
93 *
94 * @returns Callback result. VERR_TIMEOUT if too much time elapses.
95 * @param pfnCallback Callback for checking the state.
96 * @param pvWhat Callback parameter.
97 */
98static int testWaitForSomethingToBeOwned(int (*pfnCallback)(void *), void *pvWhat)
99{
100 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
101 RTTEST_CHECK_RC_OK(g_hTest, RTSemEventMultiWait(g_hThreadsStartedEvt, TEST_SMALL_TIMEOUT));
102
103 uint64_t u64StartMS = RTTimeMilliTS();
104 for (unsigned iLoop = 0; ; iLoop++)
105 {
106 RTTEST_CHECK_RET(g_hTest, !g_fShutdown, VERR_INTERNAL_ERROR);
107
108 int rc = pfnCallback(pvWhat);
109 if (rc != VERR_TRY_AGAIN/* && !g_fDoNotSpin*/)
110 {
111 RTTEST_CHECK_RC_OK(g_hTest, rc);
112 return rc;
113 }
114
115 uint64_t cMsElapsed = RTTimeMilliTS() - u64StartMS;
116 if (!g_fDoNotSpin)
117 RTTEST_CHECK_RET(g_hTest, cMsElapsed <= TEST_SMALL_TIMEOUT, VERR_TIMEOUT);
118
119 RTTEST_CHECK_RET(g_hTest, !g_fShutdown, VERR_INTERNAL_ERROR);
120 RTThreadSleep(/*g_fDoNotSpin ? TEST_DEBUG_TIMEOUT :*/ iLoop > 256 ? 1 : 0);
121 }
122}
123
124
125static int testCheckIfCritSectIsOwned(void *pvWhat)
126{
127 PRTCRITSECT pCritSect = (PRTCRITSECT)pvWhat;
128 if (!RTCritSectIsInitialized(pCritSect))
129 return VERR_SEM_DESTROYED;
130 if (RTCritSectIsOwned(pCritSect))
131 return VINF_SUCCESS;
132 return VERR_TRY_AGAIN;
133}
134
135
136static int testWaitForCritSectToBeOwned(PRTCRITSECT pCritSect)
137{
138 return testWaitForSomethingToBeOwned(testCheckIfCritSectIsOwned, pCritSect);
139}
140
141
142static int testCheckIfSemRWIsOwned(void *pvWhat)
143{
144 RTSEMRW hSemRW = (RTSEMRW)pvWhat;
145 if (RTSemRWGetWriteRecursion(hSemRW) > 0)
146 return VINF_SUCCESS;
147 if (RTSemRWGetReadCount(hSemRW) > 0)
148 return VINF_SUCCESS;
149 return VERR_TRY_AGAIN;
150}
151
152static int testWaitForSemRWToBeOwned(RTSEMRW hSemRW)
153{
154 return testWaitForSomethingToBeOwned(testCheckIfSemRWIsOwned, hSemRW);
155}
156
157
158static int testCheckIfSemMutexIsOwned(void *pvWhat)
159{
160 RTSEMMUTEX hSemRW = (RTSEMMUTEX)pvWhat;
161 if (RTSemMutexIsOwned(hSemRW))
162 return VINF_SUCCESS;
163 return VERR_TRY_AGAIN;
164}
165
166static int testWaitForSemMutexToBeOwned(RTSEMMUTEX hSemMutex)
167{
168 return testWaitForSomethingToBeOwned(testCheckIfSemMutexIsOwned, hSemMutex);
169}
170
171
172/**
173 * For reducing spin in testWaitForAllOtherThreadsToSleep.
174 */
175static void testThreadBlocking(void)
176{
177 if (ASMAtomicIncU32(&g_cThreadsBlocking) == g_cThreads)
178 RTTEST_CHECK_RC_OK(g_hTest, RTSemEventMultiSignal(g_hThreadsBlockingEvt));
179}
180
181
182/**
183 * Waits for all the other threads to enter sleeping states.
184 *
185 * @returns VINF_SUCCESS on success, VERR_INTERNAL_ERROR on failure.
186 * @param enmDesiredState The desired thread sleep state.
187 * @param cWaitOn The distance to the lock they'll be waiting on,
188 * the lock type is derived from the desired state.
189 * UINT32_MAX means no special lock.
190 */
191static int testWaitForAllOtherThreadsToSleep(RTTHREADSTATE enmDesiredState, uint32_t cWaitOn)
192{
193 testThreadBlocking();
194 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
195 RTTEST_CHECK_RC_OK(g_hTest, RTSemEventMultiWait(g_hThreadsBlockingEvt, TEST_SMALL_TIMEOUT));
196
197 RTTHREAD hThreadSelf = RTThreadSelf();
198 for (uint32_t iOuterLoop = 0; ; iOuterLoop++)
199 {
200 uint32_t cMissing = 0;
201 uint32_t cWaitedOn = 0;
202 for (uint32_t i = 0; i < g_cThreads; i++)
203 {
204 RTTHREAD hThread = g_ahThreads[i];
205 if (hThread == NIL_RTTHREAD)
206 cMissing++;
207 else if (hThread != hThreadSelf)
208 {
209 /*
210 * Figure out which lock to wait for.
211 */
212 void *pvLock = NULL;
213 if (cWaitOn != UINT32_MAX)
214 {
215 uint32_t j = (i + cWaitOn) % g_cThreads;
216 switch (enmDesiredState)
217 {
218 case RTTHREADSTATE_CRITSECT: pvLock = &g_aCritSects[j]; break;
219 case RTTHREADSTATE_RW_WRITE:
220 case RTTHREADSTATE_RW_READ: pvLock = g_ahSemRWs[j]; break;
221 case RTTHREADSTATE_MUTEX: pvLock = g_ahSemMtxes[j]; break;
222 default: break;
223 }
224 }
225
226 /*
227 * Wait for this thread.
228 */
229 for (unsigned iLoop = 0; ; iLoop++)
230 {
231 RTTHREADSTATE enmState = RTThreadGetReallySleeping(hThread);
232 if (RTTHREAD_IS_SLEEPING(enmState))
233 {
234 if ( enmState == enmDesiredState
235 && ( !pvLock
236 || ( pvLock == RTLockValidatorQueryBlocking(hThread)
237 && !RTLockValidatorIsBlockedThreadInValidator(hThread) )
238 )
239 && RTThreadGetNativeState(hThread) != RTTHREADNATIVESTATE_RUNNING
240 )
241 break;
242 }
243 else if ( enmState != RTTHREADSTATE_RUNNING
244 && enmState != RTTHREADSTATE_INITIALIZING)
245 return VERR_INTERNAL_ERROR;
246 RTTEST_CHECK_RET(g_hTest, !g_fShutdown, VERR_INTERNAL_ERROR);
247 RTThreadSleep(g_fDoNotSpin ? TEST_DEBUG_TIMEOUT : iOuterLoop + iLoop > 256 ? 1 : 0);
248 RTTEST_CHECK_RET(g_hTest, !g_fShutdown, VERR_INTERNAL_ERROR);
249 cWaitedOn++;
250 }
251 }
252 RTTEST_CHECK_RET(g_hTest, !g_fShutdown, VERR_INTERNAL_ERROR);
253 }
254
255 if (!cMissing && !cWaitedOn)
256 break;
257 RTTEST_CHECK_RET(g_hTest, !g_fShutdown, VERR_INTERNAL_ERROR);
258 RTThreadSleep(g_fDoNotSpin ? TEST_DEBUG_TIMEOUT : iOuterLoop > 256 ? 1 : 0);
259 RTTEST_CHECK_RET(g_hTest, !g_fShutdown, VERR_INTERNAL_ERROR);
260 }
261
262 RTThreadSleep(0); /* fudge factor */
263 RTTEST_CHECK_RET(g_hTest, !g_fShutdown, VERR_INTERNAL_ERROR);
264 return VINF_SUCCESS;
265}
266
267
268/**
269 * Worker that starts the threads.
270 *
271 * @returns Same as RTThreadCreate.
272 * @param cThreads The number of threads to start.
273 * @param pfnThread Thread function.
274 */
275static int testStartThreads(uint32_t cThreads, PFNRTTHREAD pfnThread)
276{
277 RTSemEventMultiReset(g_hThreadsStartedEvt);
278
279 for (uint32_t i = 0; i < RT_ELEMENTS(g_ahThreads); i++)
280 g_ahThreads[i] = NIL_RTTHREAD;
281
282 int rc = VINF_SUCCESS;
283 for (uint32_t i = 0; i < cThreads; i++)
284 {
285 rc = RTThreadCreateF(&g_ahThreads[i], pfnThread, (void *)(uintptr_t)i, 0,
286 RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "thread-%02u", i);
287 RTTEST_CHECK_RC_OK(g_hTest, rc);
288 if (RT_FAILURE(rc))
289 break;
290 }
291
292 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemEventMultiSignal(g_hThreadsStartedEvt), rcCheck);
293 return rc;
294}
295
296
297/**
298 * Worker that waits for the threads to complete.
299 *
300 * @param cMillies How long to wait for each.
301 * @param fStopOnError Whether to stop on error and heed the thread
302 * return status.
303 */
304static void testWaitForThreads(uint32_t cMillies, bool fStopOnError)
305{
306 uint32_t i = RT_ELEMENTS(g_ahThreads);
307 while (i-- > 0)
308 if (g_ahThreads[i] != NIL_RTTHREAD)
309 {
310 int rcThread;
311 int rc2;
312 RTTEST_CHECK_RC_OK(g_hTest, rc2 = RTThreadWait(g_ahThreads[i], cMillies, &rcThread));
313 if (RT_SUCCESS(rc2))
314 g_ahThreads[i] = NIL_RTTHREAD;
315 if (fStopOnError && (RT_FAILURE(rc2) || RT_FAILURE(rcThread)))
316 return;
317 }
318}
319
320
321static void testIt(uint32_t cThreads, uint32_t cSecs, bool fLoops, PFNRTTHREAD pfnThread, const char *pszName)
322{
323 /*
324 * Init test.
325 */
326 if (cSecs > 0)
327 RTTestSubF(g_hTest, "%s, %u threads, %u secs", pszName, cThreads, cSecs);
328 else
329 RTTestSubF(g_hTest, "%s, %u threads, single pass", pszName, cThreads);
330
331 RTTEST_CHECK_RETV(g_hTest, RT_ELEMENTS(g_ahThreads) >= cThreads);
332 RTTEST_CHECK_RETV(g_hTest, RT_ELEMENTS(g_aCritSects) >= cThreads);
333
334 g_cThreads = cThreads;
335 g_fShutdown = false;
336
337 for (uint32_t i = 0; i < cThreads; i++)
338 {
339 RTTEST_CHECK_RC_RETV(g_hTest, RTCritSectInitEx(&g_aCritSects[i], 0 /*fFlags*/, NIL_RTLOCKVALCLASS,
340 RTLOCKVAL_SUB_CLASS_ANY, "RTCritSect"), VINF_SUCCESS);
341 RTTEST_CHECK_RC_RETV(g_hTest, RTSemRWCreateEx(&g_ahSemRWs[i], 0 /*fFlags*/, NIL_RTLOCKVALCLASS,
342 RTLOCKVAL_SUB_CLASS_ANY, "RTSemRW"), VINF_SUCCESS);
343 RTTEST_CHECK_RC_RETV(g_hTest, RTSemMutexCreateEx(&g_ahSemMtxes[i], 0 /*fFlags*/, NIL_RTLOCKVALCLASS,
344 RTLOCKVAL_SUB_CLASS_ANY, "RTSemMutex"), VINF_SUCCESS);
345 }
346 RTTEST_CHECK_RC_RETV(g_hTest, RTSemEventCreate(&g_hSemEvt), VINF_SUCCESS);
347 RTTEST_CHECK_RC_RETV(g_hTest, RTSemEventMultiCreate(&g_hSemEvtMulti), VINF_SUCCESS);
348 RTTEST_CHECK_RC_RETV(g_hTest, RTSemEventMultiCreate(&g_hThreadsStartedEvt), VINF_SUCCESS);
349 RTTEST_CHECK_RC_RETV(g_hTest, RTSemEventMultiCreate(&g_hThreadsBlockingEvt), VINF_SUCCESS);
350
351 /*
352 * The test loop.
353 */
354 uint32_t cPasses = 0;
355 uint32_t cLoops = 0;
356 uint32_t cDeadlocks = 0;
357 uint32_t cErrors = RTTestErrorCount(g_hTest);
358 uint64_t uStartNS = RTTimeNanoTS();
359 g_NanoTSStop = uStartNS + cSecs * UINT64_C(1000000000);
360 do
361 {
362 g_iDeadlockThread = (cThreads - 1 + cPasses) % cThreads;
363 g_cLoops = 0;
364 g_cDeadlocks = 0;
365 g_cThreadsBlocking = 0;
366 RTTEST_CHECK_RC(g_hTest, RTSemEventMultiReset(g_hThreadsBlockingEvt), VINF_SUCCESS);
367
368 int rc = testStartThreads(cThreads, pfnThread);
369 if (RT_SUCCESS(rc))
370 {
371 testWaitForThreads(TEST_LARGE_TIMEOUT + cSecs*1000, true);
372 if (g_fDoNotSpin && RTTestErrorCount(g_hTest) != cErrors)
373 testWaitForThreads(TEST_DEBUG_TIMEOUT, true);
374 }
375
376 RTTEST_CHECK(g_hTest, !fLoops || g_cLoops > 0);
377 cLoops += g_cLoops;
378 RTTEST_CHECK(g_hTest, !fLoops || g_cDeadlocks > 0);
379 cDeadlocks += g_cDeadlocks;
380 cPasses++;
381 } while ( RTTestErrorCount(g_hTest) == cErrors
382 && !fLoops
383 && RTTimeNanoTS() < g_NanoTSStop);
384
385 /*
386 * Cleanup.
387 */
388 ASMAtomicWriteBool(&g_fShutdown, true);
389 RTTEST_CHECK_RC(g_hTest, RTSemEventMultiSignal(g_hThreadsBlockingEvt), VINF_SUCCESS);
390 RTTEST_CHECK_RC(g_hTest, RTSemEventMultiSignal(g_hThreadsStartedEvt), VINF_SUCCESS);
391 RTThreadSleep(RTTestErrorCount(g_hTest) == cErrors ? 0 : 50);
392
393 for (uint32_t i = 0; i < cThreads; i++)
394 {
395 RTTEST_CHECK_RC(g_hTest, RTCritSectDelete(&g_aCritSects[i]), VINF_SUCCESS);
396 RTTEST_CHECK_RC(g_hTest, RTSemRWDestroy(g_ahSemRWs[i]), VINF_SUCCESS);
397 RTTEST_CHECK_RC(g_hTest, RTSemMutexDestroy(g_ahSemMtxes[i]), VINF_SUCCESS);
398 }
399 RTTEST_CHECK_RC(g_hTest, RTSemEventDestroy(g_hSemEvt), VINF_SUCCESS);
400 RTTEST_CHECK_RC(g_hTest, RTSemEventMultiDestroy(g_hSemEvtMulti), VINF_SUCCESS);
401 RTTEST_CHECK_RC(g_hTest, RTSemEventMultiDestroy(g_hThreadsStartedEvt), VINF_SUCCESS);
402 RTTEST_CHECK_RC(g_hTest, RTSemEventMultiDestroy(g_hThreadsBlockingEvt), VINF_SUCCESS);
403
404 testWaitForThreads(TEST_SMALL_TIMEOUT, false);
405
406 /*
407 * Print results if applicable.
408 */
409 if (cSecs)
410 {
411 if (fLoops)
412 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "cLoops=%u cDeadlocks=%u (%u%%)\n",
413 cLoops, cDeadlocks, cLoops ? cDeadlocks * 100 / cLoops : 0);
414 else
415 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "cPasses=%u\n", cPasses);
416 }
417}
418
419
420static DECLCALLBACK(int) testDd1Thread(RTTHREAD ThreadSelf, void *pvUser)
421{
422 uintptr_t i = (uintptr_t)pvUser;
423 PRTCRITSECT pMine = &g_aCritSects[i];
424 PRTCRITSECT pNext = &g_aCritSects[(i + 1) % g_cThreads];
425 RT_NOREF_PV(ThreadSelf);
426
427 RTTEST_CHECK_RC_RET(g_hTest, RTCritSectEnter(pMine), VINF_SUCCESS, rcCheck);
428 if (!(i & 1))
429 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(pMine), VINF_SUCCESS);
430 if (RT_SUCCESS(testWaitForCritSectToBeOwned(pNext)))
431 {
432 int rc;
433 if (i != g_iDeadlockThread)
434 {
435 testThreadBlocking();
436 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(pNext), VINF_SUCCESS);
437 }
438 else
439 {
440 RTTEST_CHECK_RC_OK(g_hTest, rc = testWaitForAllOtherThreadsToSleep(RTTHREADSTATE_CRITSECT, 1));
441 if (RT_SUCCESS(rc))
442 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(pNext), VERR_SEM_LV_DEADLOCK);
443 }
444 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
445 if (RT_SUCCESS(rc))
446 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectLeave(pNext), VINF_SUCCESS);
447 }
448 if (!(i & 1))
449 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(pMine), VINF_SUCCESS);
450 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(pMine), VINF_SUCCESS);
451 return VINF_SUCCESS;
452}
453
454
455static void testDd1(uint32_t cThreads, uint32_t cSecs)
456{
457 testIt(cThreads, cSecs, false, testDd1Thread, "deadlock, critsect");
458}
459
460
461static DECLCALLBACK(int) testDd2Thread(RTTHREAD ThreadSelf, void *pvUser)
462{
463 uintptr_t i = (uintptr_t)pvUser;
464 RTSEMRW hMine = g_ahSemRWs[i];
465 RTSEMRW hNext = g_ahSemRWs[(i + 1) % g_cThreads];
466 int rc;
467 RT_NOREF_PV(ThreadSelf);
468
469 if (i & 1)
470 {
471 RTTEST_CHECK_RC_RET(g_hTest, RTSemRWRequestWrite(hMine, RT_INDEFINITE_WAIT), VINF_SUCCESS, rcCheck);
472 if ((i & 3) == 3)
473 RTTEST_CHECK_RC(g_hTest, RTSemRWRequestWrite(hMine, RT_INDEFINITE_WAIT), VINF_SUCCESS);
474 }
475 else
476 RTTEST_CHECK_RC_RET(g_hTest, RTSemRWRequestRead(hMine, RT_INDEFINITE_WAIT), VINF_SUCCESS, rcCheck);
477 if (RT_SUCCESS(testWaitForSemRWToBeOwned(hNext)))
478 {
479 if (i != g_iDeadlockThread)
480 {
481 testThreadBlocking();
482 RTTEST_CHECK_RC(g_hTest, rc = RTSemRWRequestWrite(hNext, RT_INDEFINITE_WAIT), VINF_SUCCESS);
483 }
484 else
485 {
486 RTTEST_CHECK_RC_OK(g_hTest, rc = testWaitForAllOtherThreadsToSleep(RTTHREADSTATE_RW_WRITE, 1));
487 if (RT_SUCCESS(rc))
488 {
489 if (g_cThreads > 1)
490 RTTEST_CHECK_RC(g_hTest, rc = RTSemRWRequestWrite(hNext, RT_INDEFINITE_WAIT), VERR_SEM_LV_DEADLOCK);
491 else
492 RTTEST_CHECK_RC(g_hTest, rc = RTSemRWRequestWrite(hNext, RT_INDEFINITE_WAIT), VERR_SEM_LV_ILLEGAL_UPGRADE);
493 }
494 }
495 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
496 if (RT_SUCCESS(rc))
497 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(hNext), VINF_SUCCESS);
498 }
499 if (i & 1)
500 {
501 if ((i & 3) == 3)
502 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(hMine), VINF_SUCCESS);
503 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(hMine), VINF_SUCCESS);
504 }
505 else
506 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseRead(hMine), VINF_SUCCESS);
507 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
508 return VINF_SUCCESS;
509}
510
511
512static void testDd2(uint32_t cThreads, uint32_t cSecs)
513{
514 testIt(cThreads, cSecs, false, testDd2Thread, "deadlock, read-write");
515}
516
517
518static DECLCALLBACK(int) testDd3Thread(RTTHREAD ThreadSelf, void *pvUser)
519{
520 uintptr_t i = (uintptr_t)pvUser;
521 RTSEMRW hMine = g_ahSemRWs[i];
522 RTSEMRW hNext = g_ahSemRWs[(i + 1) % g_cThreads];
523 int rc;
524 RT_NOREF_PV(ThreadSelf);
525
526 if (i & 1)
527 RTTEST_CHECK_RC_RET(g_hTest, RTSemRWRequestWrite(hMine, RT_INDEFINITE_WAIT), VINF_SUCCESS, rcCheck);
528 else
529 RTTEST_CHECK_RC_RET(g_hTest, RTSemRWRequestRead(hMine, RT_INDEFINITE_WAIT), VINF_SUCCESS, rcCheck);
530 if (RT_SUCCESS(testWaitForSemRWToBeOwned(hNext)))
531 {
532 do
533 {
534 rc = RTSemRWRequestWrite(hNext, TEST_SMALL_TIMEOUT);
535 if (rc != VINF_SUCCESS && rc != VERR_SEM_LV_DEADLOCK && rc != VERR_SEM_LV_ILLEGAL_UPGRADE)
536 {
537 RTTestFailed(g_hTest, "#%u: RTSemRWRequestWrite -> %Rrc\n", i, rc);
538 break;
539 }
540 if (RT_SUCCESS(rc))
541 {
542 RTTEST_CHECK_RC(g_hTest, rc = RTSemRWReleaseWrite(hNext), VINF_SUCCESS);
543 if (RT_FAILURE(rc))
544 break;
545 }
546 else
547 ASMAtomicIncU32(&g_cDeadlocks);
548 ASMAtomicIncU32(&g_cLoops);
549 } while (RTTimeNanoTS() < g_NanoTSStop);
550 }
551 if (i & 1)
552 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(hMine), VINF_SUCCESS);
553 else
554 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseRead(hMine), VINF_SUCCESS);
555 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
556 return VINF_SUCCESS;
557}
558
559
560static void testDd3(uint32_t cThreads, uint32_t cSecs)
561{
562 testIt(cThreads, cSecs, true, testDd3Thread, "deadlock, read-write race");
563}
564
565
566static DECLCALLBACK(int) testDd4Thread(RTTHREAD ThreadSelf, void *pvUser)
567{
568 uintptr_t i = (uintptr_t)pvUser;
569 RTSEMRW hMine = g_ahSemRWs[i];
570 RTSEMRW hNext = g_ahSemRWs[(i + 1) % g_cThreads];
571 RT_NOREF_PV(ThreadSelf);
572
573 do
574 {
575 int rc1 = (i & 1 ? RTSemRWRequestWrite : RTSemRWRequestRead)(hMine, TEST_SMALL_TIMEOUT); /* ugly ;-) */
576 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
577 if (rc1 != VINF_SUCCESS && rc1 != VERR_SEM_LV_DEADLOCK && rc1 != VERR_SEM_LV_ILLEGAL_UPGRADE)
578 {
579 RTTestFailed(g_hTest, "#%u: RTSemRWRequest%s(hMine,) -> %Rrc\n", i, i & 1 ? "Write" : "read", rc1);
580 break;
581 }
582 if (RT_SUCCESS(rc1))
583 {
584 for (unsigned iInner = 0; iInner < 4; iInner++)
585 {
586 int rc2 = RTSemRWRequestWrite(hNext, TEST_SMALL_TIMEOUT);
587 if (rc2 != VINF_SUCCESS && rc2 != VERR_SEM_LV_DEADLOCK && rc2 != VERR_SEM_LV_ILLEGAL_UPGRADE)
588 {
589 RTTestFailed(g_hTest, "#%u: RTSemRWRequestWrite -> %Rrc\n", i, rc2);
590 break;
591 }
592 if (RT_SUCCESS(rc2))
593 {
594 RTTEST_CHECK_RC(g_hTest, rc2 = RTSemRWReleaseWrite(hNext), VINF_SUCCESS);
595 if (RT_FAILURE(rc2))
596 break;
597 }
598 else
599 ASMAtomicIncU32(&g_cDeadlocks);
600 ASMAtomicIncU32(&g_cLoops);
601 }
602
603 RTTEST_CHECK_RC(g_hTest, rc1 = (i & 1 ? RTSemRWReleaseWrite : RTSemRWReleaseRead)(hMine), VINF_SUCCESS);
604 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
605 if (RT_FAILURE(rc1))
606 break;
607 }
608 else
609 ASMAtomicIncU32(&g_cDeadlocks);
610 ASMAtomicIncU32(&g_cLoops);
611 } while (RTTimeNanoTS() < g_NanoTSStop);
612
613 return VINF_SUCCESS;
614}
615
616
617static void testDd4(uint32_t cThreads, uint32_t cSecs)
618{
619 testIt(cThreads, cSecs, true, testDd4Thread, "deadlock, read-write race v2");
620}
621
622
623static DECLCALLBACK(int) testDd5Thread(RTTHREAD ThreadSelf, void *pvUser)
624{
625 uintptr_t i = (uintptr_t)pvUser;
626 RTSEMMUTEX hMine = g_ahSemMtxes[i];
627 RTSEMMUTEX hNext = g_ahSemMtxes[(i + 1) % g_cThreads];
628 RT_NOREF_PV(ThreadSelf);
629
630 RTTEST_CHECK_RC_RET(g_hTest, RTSemMutexRequest(hMine, RT_INDEFINITE_WAIT), VINF_SUCCESS, rcCheck);
631 if (i & 1)
632 RTTEST_CHECK_RC(g_hTest, RTSemMutexRequest(hMine, RT_INDEFINITE_WAIT), VINF_SUCCESS);
633 if (RT_SUCCESS(testWaitForSemMutexToBeOwned(hNext)))
634 {
635 int rc;
636 if (i != g_iDeadlockThread)
637 {
638 testThreadBlocking();
639 RTTEST_CHECK_RC(g_hTest, rc = RTSemMutexRequest(hNext, RT_INDEFINITE_WAIT), VINF_SUCCESS);
640 }
641 else
642 {
643 RTTEST_CHECK_RC_OK(g_hTest, rc = testWaitForAllOtherThreadsToSleep(RTTHREADSTATE_MUTEX, 1));
644 if (RT_SUCCESS(rc))
645 RTTEST_CHECK_RC(g_hTest, rc = RTSemMutexRequest(hNext, RT_INDEFINITE_WAIT), VERR_SEM_LV_DEADLOCK);
646 }
647 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
648 if (RT_SUCCESS(rc))
649 RTTEST_CHECK_RC(g_hTest, rc = RTSemMutexRelease(hNext), VINF_SUCCESS);
650 }
651 if (i & 1)
652 RTTEST_CHECK_RC(g_hTest, RTSemMutexRelease(hMine), VINF_SUCCESS);
653 RTTEST_CHECK_RC(g_hTest, RTSemMutexRelease(hMine), VINF_SUCCESS);
654 return VINF_SUCCESS;
655}
656
657
658static void testDd5(uint32_t cThreads, uint32_t cSecs)
659{
660 testIt(cThreads, cSecs, false, testDd5Thread, "deadlock, mutex");
661}
662
663
664static DECLCALLBACK(int) testDd6Thread(RTTHREAD ThreadSelf, void *pvUser)
665{
666 uintptr_t i = (uintptr_t)pvUser;
667 PRTCRITSECT pMine = &g_aCritSects[i];
668 PRTCRITSECT pNext = &g_aCritSects[(i + 1) % g_cThreads];
669 RT_NOREF_PV(ThreadSelf);
670
671 RTTEST_CHECK_RC_RET(g_hTest, RTCritSectEnter(pMine), VINF_SUCCESS, rcCheck);
672 if (i & 1)
673 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(pMine), VINF_SUCCESS);
674 if (RT_SUCCESS(testWaitForCritSectToBeOwned(pNext)))
675 {
676 int rc;
677 if (i != g_iDeadlockThread)
678 {
679 testThreadBlocking();
680 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(pNext), VINF_SUCCESS);
681 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
682 if (RT_SUCCESS(rc))
683 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectLeave(pNext), VINF_SUCCESS);
684 }
685 else
686 {
687 RTTEST_CHECK_RC_OK(g_hTest, rc = testWaitForAllOtherThreadsToSleep(RTTHREADSTATE_CRITSECT, 1));
688 if (RT_SUCCESS(rc))
689 {
690 RTSemEventSetSignaller(g_hSemEvt, g_ahThreads[0]);
691 for (uint32_t iThread = 1; iThread < g_cThreads; iThread++)
692 RTSemEventAddSignaller(g_hSemEvt, g_ahThreads[iThread]);
693 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
694 RTTEST_CHECK_RC(g_hTest, RTSemEventWait(g_hSemEvt, TEST_SMALL_TIMEOUT), VERR_SEM_LV_DEADLOCK);
695 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
696 RTTEST_CHECK_RC(g_hTest, RTSemEventSignal(g_hSemEvt), VINF_SUCCESS);
697 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
698 RTTEST_CHECK_RC(g_hTest, RTSemEventWait(g_hSemEvt, TEST_SMALL_TIMEOUT), VINF_SUCCESS);
699 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
700 RTSemEventSetSignaller(g_hSemEvt, NIL_RTTHREAD);
701 }
702 }
703 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
704 }
705 if (i & 1)
706 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(pMine), VINF_SUCCESS);
707 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(pMine), VINF_SUCCESS);
708 return VINF_SUCCESS;
709}
710
711
712static void testDd6(uint32_t cThreads, uint32_t cSecs)
713{
714 testIt(cThreads, cSecs, false, testDd6Thread, "deadlock, event");
715}
716
717
718static DECLCALLBACK(int) testDd7Thread(RTTHREAD ThreadSelf, void *pvUser)
719{
720 uintptr_t i = (uintptr_t)pvUser;
721 PRTCRITSECT pMine = &g_aCritSects[i];
722 PRTCRITSECT pNext = &g_aCritSects[(i + 1) % g_cThreads];
723 RT_NOREF_PV(ThreadSelf);
724
725 RTTEST_CHECK_RC_RET(g_hTest, RTCritSectEnter(pMine), VINF_SUCCESS, rcCheck);
726 if (i & 1)
727 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(pMine), VINF_SUCCESS);
728 if (RT_SUCCESS(testWaitForCritSectToBeOwned(pNext)))
729 {
730 int rc;
731 if (i != g_iDeadlockThread)
732 {
733 testThreadBlocking();
734 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(pNext), VINF_SUCCESS);
735 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
736 if (RT_SUCCESS(rc))
737 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectLeave(pNext), VINF_SUCCESS);
738 }
739 else
740 {
741 RTTEST_CHECK_RC_OK(g_hTest, rc = testWaitForAllOtherThreadsToSleep(RTTHREADSTATE_CRITSECT, 1));
742 if (RT_SUCCESS(rc))
743 {
744 RTSemEventMultiSetSignaller(g_hSemEvtMulti, g_ahThreads[0]);
745 for (uint32_t iThread = 1; iThread < g_cThreads; iThread++)
746 RTSemEventMultiAddSignaller(g_hSemEvtMulti, g_ahThreads[iThread]);
747 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
748 RTTEST_CHECK_RC(g_hTest, RTSemEventMultiReset(g_hSemEvtMulti), VINF_SUCCESS);
749 RTTEST_CHECK_RC(g_hTest, RTSemEventMultiWait(g_hSemEvtMulti, TEST_SMALL_TIMEOUT), VERR_SEM_LV_DEADLOCK);
750 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
751 RTTEST_CHECK_RC(g_hTest, RTSemEventMultiSignal(g_hSemEvtMulti), VINF_SUCCESS);
752 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
753 RTTEST_CHECK_RC(g_hTest, RTSemEventMultiWait(g_hSemEvtMulti, TEST_SMALL_TIMEOUT), VINF_SUCCESS);
754 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
755 RTSemEventMultiSetSignaller(g_hSemEvtMulti, NIL_RTTHREAD);
756 }
757 }
758 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
759 }
760 if (i & 1)
761 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(pMine), VINF_SUCCESS);
762 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(pMine), VINF_SUCCESS);
763 return VINF_SUCCESS;
764}
765
766
767static void testDd7(uint32_t cThreads, uint32_t cSecs)
768{
769 testIt(cThreads, cSecs, false, testDd7Thread, "deadlock, event multi");
770}
771
772
773static void testLo1(void)
774{
775 RTTestSub(g_hTest, "locking order basics");
776
777 /* Initialize the critsections, the first 4 has their own classes, the rest
778 use the same class and relies on the sub-class mechanism for ordering. */
779 for (unsigned i = 0; i < RT_ELEMENTS(g_ahClasses); i++)
780 {
781 if (i <= 3)
782 {
783 RTTEST_CHECK_RC_RETV(g_hTest, RTLockValidatorClassCreate(&g_ahClasses[i], true /*fAutodidact*/, RT_SRC_POS, "testLo1-%u", i), VINF_SUCCESS);
784 RTTEST_CHECK_RC_RETV(g_hTest, RTCritSectInitEx(&g_aCritSects[i], 0, g_ahClasses[i], RTLOCKVAL_SUB_CLASS_NONE, "RTCritSectLO-Auto"), VINF_SUCCESS);
785 RTTEST_CHECK_RETV(g_hTest, RTLockValidatorClassRetain(g_ahClasses[i]) == 3);
786 RTTEST_CHECK_RETV(g_hTest, RTLockValidatorClassRelease(g_ahClasses[i]) == 2);
787 }
788 else
789 {
790 g_ahClasses[i] = RTLockValidatorClassForSrcPos(RT_SRC_POS, "testLo1-%u", i);
791 RTTEST_CHECK_RETV(g_hTest, g_ahClasses[i] != NIL_RTLOCKVALCLASS);
792 RTTEST_CHECK_RETV(g_hTest, i == 4 || g_ahClasses[i] == g_ahClasses[i - 1]);
793 if (i == 4)
794 RTTEST_CHECK_RC_RETV(g_hTest, RTCritSectInitEx(&g_aCritSects[i], 0, g_ahClasses[i], RTLOCKVAL_SUB_CLASS_NONE, "RTCritSectLO-None"), VINF_SUCCESS);
795 else if (i == 5)
796 RTTEST_CHECK_RC_RETV(g_hTest, RTCritSectInitEx(&g_aCritSects[i], 0, g_ahClasses[i], RTLOCKVAL_SUB_CLASS_ANY, "RTCritSectLO-Any"), VINF_SUCCESS);
797 else
798 RTTEST_CHECK_RC_RETV(g_hTest, RTCritSectInitEx(&g_aCritSects[i], 0, g_ahClasses[i], RTLOCKVAL_SUB_CLASS_USER + i, "RTCritSectLO-User"), VINF_SUCCESS);
799
800 RTTEST_CHECK_RETV(g_hTest, RTLockValidatorClassRetain(g_ahClasses[i]) == 1 + (i - 4 + 1) * 2); /* released in cleanup. */
801 }
802 }
803
804 /* Enter the first 4 critsects in ascending order and thereby defining
805 this as a valid lock order. */
806 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[0]), VINF_SUCCESS);
807 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[1]), VINF_SUCCESS);
808 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[2]), VINF_SUCCESS);
809 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[3]), VINF_SUCCESS);
810
811 /* Now, leave and re-enter the critsects in a way that should break the
812 order and check that we get the appropriate response. */
813 int rc;
814 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[0]), VINF_SUCCESS);
815 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(&g_aCritSects[0]), VERR_SEM_LV_WRONG_ORDER);
816 if (RT_SUCCESS(rc))
817 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[0]), VINF_SUCCESS);
818
819 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[1]), VINF_SUCCESS);
820 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(&g_aCritSects[1]), VERR_SEM_LV_WRONG_ORDER);
821 if (RT_SUCCESS(rc))
822 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[1]), VINF_SUCCESS);
823
824 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[2]), VINF_SUCCESS);
825 RTTEST_CHECK_RC(g_hTest, rc= RTCritSectEnter(&g_aCritSects[2]), VERR_SEM_LV_WRONG_ORDER);
826 if (RT_SUCCESS(rc))
827 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[2]), VINF_SUCCESS);
828
829 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[3]), VINF_SUCCESS);
830
831 /* Check that recursion isn't subject to order checks. */
832 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[0]), VINF_SUCCESS);
833 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[1]), VINF_SUCCESS);
834 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[2]), VINF_SUCCESS);
835 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[3]), VINF_SUCCESS);
836 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(&g_aCritSects[0]), VINF_SUCCESS);
837 if (RT_SUCCESS(rc))
838 {
839 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[0]), VINF_SUCCESS);
840 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[3]), VINF_SUCCESS);
841 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[2]), VINF_SUCCESS);
842 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[1]), VINF_SUCCESS);
843
844 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[3]), VINF_SUCCESS);
845 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[2]), VINF_SUCCESS);
846 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[1]), VINF_SUCCESS);
847 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[0]), VINF_SUCCESS);
848 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[0]), VINF_SUCCESS);
849 }
850 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[3]), VINF_SUCCESS);
851 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[2]), VINF_SUCCESS);
852 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[1]), VINF_SUCCESS);
853 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[0]), VINF_SUCCESS);
854
855 /* Enable strict release order for class 2 and check that violations
856 are caught. */
857 RTTEST_CHECK_RC(g_hTest, RTLockValidatorClassEnforceStrictReleaseOrder(g_ahClasses[2], true), VINF_SUCCESS);
858
859 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[0]), VINF_SUCCESS);
860 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[1]), VINF_SUCCESS);
861 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[2]), VINF_SUCCESS);
862 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[3]), VINF_SUCCESS);
863
864 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectLeave(&g_aCritSects[2]), VERR_SEM_LV_WRONG_RELEASE_ORDER);
865 if (RT_FAILURE(rc))
866 {
867 /* applies to recursions as well */
868 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[2]), VINF_SUCCESS);
869 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[3]), VINF_SUCCESS);
870 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[2]), VERR_SEM_LV_WRONG_RELEASE_ORDER);
871 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[3]), VINF_SUCCESS);
872 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[2]), VINF_SUCCESS);
873 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[2]), VERR_SEM_LV_WRONG_RELEASE_ORDER);
874 }
875 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[0]), VINF_SUCCESS);
876 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[1]), VINF_SUCCESS);
877 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[3]), VINF_SUCCESS);
878 if (RT_FAILURE(rc))
879 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[2]), VINF_SUCCESS);
880
881 /* Test that sub-class order works (4 = NONE, 5 = ANY, 6+ = USER). */
882 uint32_t cErrorsBefore = RTTestErrorCount(g_hTest);
883 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[7]), VINF_SUCCESS);
884
885 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(&g_aCritSects[4]), VERR_SEM_LV_WRONG_ORDER);
886 if (RT_SUCCESS(rc))
887 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[4]), VINF_SUCCESS);
888
889 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(&g_aCritSects[5]), VINF_SUCCESS);
890 if (RT_SUCCESS(rc))
891 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[5]), VINF_SUCCESS);
892
893 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(&g_aCritSects[8]), VINF_SUCCESS);
894 if (RT_SUCCESS(rc))
895 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[8]), VINF_SUCCESS);
896
897 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(&g_aCritSects[6]), VERR_SEM_LV_WRONG_ORDER);
898 if (RT_SUCCESS(rc))
899 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[6]), VINF_SUCCESS);
900
901 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(&g_aCritSects[7]), VINF_SUCCESS);
902 if (RT_SUCCESS(rc))
903 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[7]), VINF_SUCCESS);
904 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[7]), VINF_SUCCESS);
905
906 /* Check that NONE trumps both ANY and USER. */
907 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[4]), VINF_SUCCESS);
908
909 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(&g_aCritSects[5]), VERR_SEM_LV_WRONG_ORDER);
910 if (RT_SUCCESS(rc))
911 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[5]), VINF_SUCCESS);
912
913 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(&g_aCritSects[6]), VERR_SEM_LV_WRONG_ORDER);
914 if (RT_SUCCESS(rc))
915 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[6]), VINF_SUCCESS);
916
917 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[4]), VINF_SUCCESS);
918
919 /* Take all the locks using sub-classes. */
920 if (cErrorsBefore == RTTestErrorCount(g_hTest))
921 {
922 bool fSavedQuiet = RTLockValidatorSetQuiet(true);
923 for (uint32_t i = 6; i < RT_ELEMENTS(g_aCritSects); i++)
924 {
925 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[i]), VINF_SUCCESS);
926 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[4]), VERR_SEM_LV_WRONG_ORDER);
927 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[5]), VINF_SUCCESS);
928 }
929 for (uint32_t i = 6; i < RT_ELEMENTS(g_aCritSects); i++)
930 {
931 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[i]), VINF_SUCCESS);
932 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[5]), VINF_SUCCESS);
933 }
934 RTLockValidatorSetQuiet(fSavedQuiet);
935 }
936
937 /* Work up some hash statistics and trigger a violation to show them. */
938 for (uint32_t i = 0; i < 10240; i++)
939 {
940 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[0]), VINF_SUCCESS);
941 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[1]), VINF_SUCCESS);
942 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[2]), VINF_SUCCESS);
943 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[3]), VINF_SUCCESS);
944 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[5]), VINF_SUCCESS);
945
946 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[5]), VINF_SUCCESS);
947 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[3]), VINF_SUCCESS);
948 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[2]), VINF_SUCCESS);
949 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[1]), VINF_SUCCESS);
950 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[0]), VINF_SUCCESS);
951 }
952 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[5]), VINF_SUCCESS);
953 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[3]), VERR_SEM_LV_WRONG_ORDER);
954 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[5]), VINF_SUCCESS);
955
956 /* clean up */
957 //for (int i = RT_ELEMENTS(g_ahClasses) - 1; i >= 0; i--)
958 for (unsigned i = 0; i < RT_ELEMENTS(g_ahClasses); i++)
959 {
960 uint32_t c;
961 if (i <= 3)
962 RTTEST_CHECK_MSG(g_hTest, (c = RTLockValidatorClassRelease(g_ahClasses[i])) == 5 - i,
963 (g_hTest, "c=%u i=%u\n", c, i));
964 else
965 {
966 uint32_t cExpect = 1 + (RT_ELEMENTS(g_ahClasses) - i) * 2 - 1;
967 RTTEST_CHECK_MSG(g_hTest, (c = RTLockValidatorClassRelease(g_ahClasses[i])) == cExpect,
968 (g_hTest, "c=%u e=%u i=%u\n", c, cExpect, i));
969 }
970 g_ahClasses[i] = NIL_RTLOCKVALCLASS;
971 RTTEST_CHECK_RC_RETV(g_hTest, RTCritSectDelete(&g_aCritSects[i]), VINF_SUCCESS);
972 }
973}
974
975
976static void testLo2(void)
977{
978 RTTestSub(g_hTest, "locking order, critsect");
979
980 /* Initialize the critsection with all different classes */
981 for (unsigned i = 0; i < 4; i++)
982 {
983 RTTEST_CHECK_RC_RETV(g_hTest, RTLockValidatorClassCreate(&g_ahClasses[i], true /*fAutodidact*/, RT_SRC_POS, "testLo2-%u", i), VINF_SUCCESS);
984 RTTEST_CHECK_RC_RETV(g_hTest, RTCritSectInitEx(&g_aCritSects[i], 0, g_ahClasses[i], RTLOCKVAL_SUB_CLASS_NONE, "RTCritSectLO"), VINF_SUCCESS);
985 RTTEST_CHECK_RETV(g_hTest, RTLockValidatorClassRetain(g_ahClasses[i]) == 3);
986 RTTEST_CHECK_RETV(g_hTest, RTLockValidatorClassRelease(g_ahClasses[i]) == 2);
987 }
988
989 /* Check the sub-class API.*/
990 RTTEST_CHECK(g_hTest, RTCritSectSetSubClass(&g_aCritSects[0], RTLOCKVAL_SUB_CLASS_ANY) == RTLOCKVAL_SUB_CLASS_NONE);
991 RTTEST_CHECK(g_hTest, RTCritSectSetSubClass(&g_aCritSects[0], RTLOCKVAL_SUB_CLASS_NONE) == RTLOCKVAL_SUB_CLASS_ANY);
992
993 /* Enter the first 4 critsects in ascending order and thereby defining
994 this as a valid lock order. */
995 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[0]), VINF_SUCCESS);
996 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[1]), VINF_SUCCESS);
997 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[2]), VINF_SUCCESS);
998 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[3]), VINF_SUCCESS);
999
1000 /* Now, leave and re-enter the critsects in a way that should break the
1001 order and check that we get the appropriate response. */
1002 int rc;
1003 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[0]), VINF_SUCCESS);
1004 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(&g_aCritSects[0]), VERR_SEM_LV_WRONG_ORDER);
1005 if (RT_SUCCESS(rc))
1006 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[0]), VINF_SUCCESS);
1007
1008 /* Check that recursion isn't subject to order checks. */
1009 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(&g_aCritSects[1]), VINF_SUCCESS);
1010 if (RT_SUCCESS(rc))
1011 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[1]), VINF_SUCCESS);
1012
1013 /* Enable strict release order for class 2 and check that violations
1014 are caught - including recursion. */
1015 RTTEST_CHECK_RC(g_hTest, RTLockValidatorClassEnforceStrictReleaseOrder(g_ahClasses[2], true), VINF_SUCCESS);
1016 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[2]), VINF_SUCCESS); /* start recursion */
1017 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[3]), VINF_SUCCESS);
1018 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[2]), VERR_SEM_LV_WRONG_RELEASE_ORDER);
1019 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[3]), VINF_SUCCESS);
1020 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[2]), VINF_SUCCESS); /* end recursion */
1021 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[2]), VERR_SEM_LV_WRONG_RELEASE_ORDER);
1022 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[1]), VINF_SUCCESS);
1023 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[3]), VINF_SUCCESS);
1024 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[2]), VINF_SUCCESS);
1025
1026 /* clean up */
1027 for (int i = 4 - 1; i >= 0; i--)
1028 {
1029 RTTEST_CHECK(g_hTest, RTLockValidatorClassRelease(g_ahClasses[i]) == 1);
1030 g_ahClasses[i] = NIL_RTLOCKVALCLASS;
1031 RTTEST_CHECK_RC_RETV(g_hTest, RTCritSectDelete(&g_aCritSects[i]), VINF_SUCCESS);
1032 }
1033}
1034
1035
1036static void testLo3(void)
1037{
1038 RTTestSub(g_hTest, "locking order, read-write");
1039
1040 /* Initialize the critsection with all different classes */
1041 for (unsigned i = 0; i < 6; i++)
1042 {
1043 RTTEST_CHECK_RC_RETV(g_hTest, RTLockValidatorClassCreate(&g_ahClasses[i], true /*fAutodidact*/, RT_SRC_POS, "testLo3-%u", i), VINF_SUCCESS);
1044 RTTEST_CHECK_RC_RETV(g_hTest, RTSemRWCreateEx(&g_ahSemRWs[i], 0, g_ahClasses[i], RTLOCKVAL_SUB_CLASS_NONE, "hSemRW-Lo3-%u", i), VINF_SUCCESS);
1045 RTTEST_CHECK_RETV(g_hTest, RTLockValidatorClassRetain(g_ahClasses[i]) == 4);
1046 RTTEST_CHECK_RETV(g_hTest, RTLockValidatorClassRelease(g_ahClasses[i]) == 3);
1047 }
1048
1049 /* Check the sub-class API.*/
1050 RTTEST_CHECK(g_hTest, RTSemRWSetSubClass(g_ahSemRWs[0], RTLOCKVAL_SUB_CLASS_ANY) == RTLOCKVAL_SUB_CLASS_NONE);
1051 RTTEST_CHECK(g_hTest, RTSemRWSetSubClass(g_ahSemRWs[0], RTLOCKVAL_SUB_CLASS_NONE) == RTLOCKVAL_SUB_CLASS_ANY);
1052
1053 /* Enter the first 4 critsects in ascending order and thereby defining
1054 this as a valid lock order. */
1055 RTTEST_CHECK_RC(g_hTest, RTSemRWRequestWrite(g_ahSemRWs[0], RT_INDEFINITE_WAIT), VINF_SUCCESS);
1056 RTTEST_CHECK_RC(g_hTest, RTSemRWRequestRead( g_ahSemRWs[1], RT_INDEFINITE_WAIT), VINF_SUCCESS);
1057 RTTEST_CHECK_RC(g_hTest, RTSemRWRequestRead( g_ahSemRWs[2], RT_INDEFINITE_WAIT), VINF_SUCCESS);
1058 RTTEST_CHECK_RC(g_hTest, RTSemRWRequestWrite(g_ahSemRWs[3], RT_INDEFINITE_WAIT), VINF_SUCCESS);
1059 RTTEST_CHECK_RC(g_hTest, RTSemRWRequestWrite(g_ahSemRWs[4], RT_INDEFINITE_WAIT), VINF_SUCCESS);
1060 RTTEST_CHECK_RC(g_hTest, RTSemRWRequestWrite(g_ahSemRWs[5], RT_INDEFINITE_WAIT), VINF_SUCCESS);
1061
1062 /* Now, leave and re-enter the critsects in a way that should break the
1063 order and check that we get the appropriate response. */
1064 int rc;
1065 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(g_ahSemRWs[0]), VINF_SUCCESS);
1066 RTTEST_CHECK_RC(g_hTest, rc = RTSemRWRequestWrite(g_ahSemRWs[0], RT_INDEFINITE_WAIT), VERR_SEM_LV_WRONG_ORDER);
1067 if (RT_SUCCESS(rc))
1068 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(g_ahSemRWs[0]), VINF_SUCCESS);
1069
1070 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseRead(g_ahSemRWs[1]), VINF_SUCCESS);
1071 RTTEST_CHECK_RC(g_hTest, rc = RTSemRWRequestRead(g_ahSemRWs[1], RT_INDEFINITE_WAIT), VERR_SEM_LV_WRONG_ORDER);
1072 if (RT_SUCCESS(rc))
1073 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseRead(g_ahSemRWs[1]), VINF_SUCCESS);
1074
1075 /* Check that recursion isn't subject to order checks. */
1076 RTTEST_CHECK_RC(g_hTest, rc = RTSemRWRequestRead(g_ahSemRWs[2], RT_INDEFINITE_WAIT), VINF_SUCCESS);
1077 if (RT_SUCCESS(rc))
1078 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseRead(g_ahSemRWs[2]), VINF_SUCCESS);
1079 RTTEST_CHECK(g_hTest, RTSemRWGetReadCount(g_ahSemRWs[2]) == 1);
1080
1081 RTTEST_CHECK_RC(g_hTest, rc = RTSemRWRequestWrite(g_ahSemRWs[3], RT_INDEFINITE_WAIT), VINF_SUCCESS);
1082 if (RT_SUCCESS(rc))
1083 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(g_ahSemRWs[3]), VINF_SUCCESS);
1084 RTTEST_CHECK(g_hTest, RTSemRWGetWriteRecursion(g_ahSemRWs[3]) == 1);
1085
1086 /* Enable strict release order for class 2 and 3, then check that violations
1087 are caught - including recursion. */
1088 RTTEST_CHECK_RC(g_hTest, RTLockValidatorClassEnforceStrictReleaseOrder(g_ahClasses[2], true), VINF_SUCCESS);
1089 RTTEST_CHECK_RC(g_hTest, RTLockValidatorClassEnforceStrictReleaseOrder(g_ahClasses[3], true), VINF_SUCCESS);
1090
1091 RTTEST_CHECK_RC(g_hTest, RTSemRWRequestRead( g_ahSemRWs[2], RT_INDEFINITE_WAIT), VINF_SUCCESS); /* start recursion */
1092 RTTEST_CHECK( g_hTest, RTSemRWGetReadCount(g_ahSemRWs[2]) == 2);
1093 RTTEST_CHECK_RC(g_hTest, RTSemRWRequestWrite(g_ahSemRWs[3], RT_INDEFINITE_WAIT), VINF_SUCCESS);
1094 RTTEST_CHECK( g_hTest, RTSemRWGetWriteRecursion(g_ahSemRWs[3]) == 2);
1095 RTTEST_CHECK_RC(g_hTest, RTSemRWRequestRead( g_ahSemRWs[4], RT_INDEFINITE_WAIT), VINF_SUCCESS); /* (mixed) */
1096
1097 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseRead( g_ahSemRWs[2]), VERR_SEM_LV_WRONG_RELEASE_ORDER);
1098 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(g_ahSemRWs[3]), VERR_SEM_LV_WRONG_RELEASE_ORDER);
1099 RTTEST_CHECK( g_hTest, RTSemRWGetWriteRecursion(g_ahSemRWs[3]) == 2);
1100 RTTEST_CHECK( g_hTest, RTSemRWGetReadCount(g_ahSemRWs[2]) == 2);
1101 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseRead( g_ahSemRWs[4]), VINF_SUCCESS);
1102 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(g_ahSemRWs[3]), VINF_SUCCESS);
1103 RTTEST_CHECK( g_hTest, RTSemRWGetWriteRecursion(g_ahSemRWs[3]) == 1);
1104 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseRead( g_ahSemRWs[2]), VINF_SUCCESS); /* end recursion */
1105 RTTEST_CHECK( g_hTest, RTSemRWGetReadCount(g_ahSemRWs[2]) == 1);
1106
1107 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseRead( g_ahSemRWs[2]), VERR_SEM_LV_WRONG_RELEASE_ORDER);
1108 RTTEST_CHECK(g_hTest, RTSemRWGetReadCount(g_ahSemRWs[2]) == 1);
1109 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(g_ahSemRWs[3]), VERR_SEM_LV_WRONG_RELEASE_ORDER);
1110 RTTEST_CHECK(g_hTest, RTSemRWGetWriteRecursion(g_ahSemRWs[3]) == 1);
1111 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(g_ahSemRWs[5]), VINF_SUCCESS);
1112 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(g_ahSemRWs[4]), VINF_SUCCESS);
1113 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(g_ahSemRWs[3]), VINF_SUCCESS);
1114 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseRead( g_ahSemRWs[2]), VINF_SUCCESS);
1115
1116 /* clean up */
1117 for (int i = 6 - 1; i >= 0; i--)
1118 {
1119 uint32_t c;
1120 RTTEST_CHECK_MSG(g_hTest, (c = RTLockValidatorClassRelease(g_ahClasses[i])) == 2, (g_hTest, "c=%u i=%u\n", c, i));
1121 g_ahClasses[i] = NIL_RTLOCKVALCLASS;
1122 RTTEST_CHECK_RC_RETV(g_hTest, RTSemRWDestroy(g_ahSemRWs[i]), VINF_SUCCESS);
1123 g_ahSemRWs[i] = NIL_RTSEMRW;
1124 }
1125}
1126
1127
1128static void testLo4(void)
1129{
1130 RTTestSub(g_hTest, "locking order, mutex");
1131
1132 /* Initialize the critsection with all different classes */
1133 for (unsigned i = 0; i < 4; i++)
1134 {
1135 RTTEST_CHECK_RC_RETV(g_hTest, RTLockValidatorClassCreate(&g_ahClasses[i], true /*fAutodidact*/, RT_SRC_POS, "testLo4-%u", i), VINF_SUCCESS);
1136 RTTEST_CHECK_RC_RETV(g_hTest, RTSemMutexCreateEx(&g_ahSemMtxes[i], 0, g_ahClasses[i], RTLOCKVAL_SUB_CLASS_NONE, "RTSemMutexLo4-%u", i), VINF_SUCCESS);
1137 RTTEST_CHECK_RETV(g_hTest, RTLockValidatorClassRetain(g_ahClasses[i]) == 3);
1138 RTTEST_CHECK_RETV(g_hTest, RTLockValidatorClassRelease(g_ahClasses[i]) == 2);
1139 }
1140
1141 /* Check the sub-class API.*/
1142 RTTEST_CHECK(g_hTest, RTSemMutexSetSubClass(g_ahSemMtxes[0], RTLOCKVAL_SUB_CLASS_ANY) == RTLOCKVAL_SUB_CLASS_NONE);
1143 RTTEST_CHECK(g_hTest, RTSemMutexSetSubClass(g_ahSemMtxes[0], RTLOCKVAL_SUB_CLASS_NONE) == RTLOCKVAL_SUB_CLASS_ANY);
1144
1145 /* Enter the first 4 critsects in ascending order and thereby defining
1146 this as a valid lock order. */
1147 RTTEST_CHECK_RC(g_hTest, RTSemMutexRequest(g_ahSemMtxes[0], RT_INDEFINITE_WAIT), VINF_SUCCESS);
1148 RTTEST_CHECK_RC(g_hTest, RTSemMutexRequest(g_ahSemMtxes[1], RT_INDEFINITE_WAIT), VINF_SUCCESS);
1149 RTTEST_CHECK_RC(g_hTest, RTSemMutexRequest(g_ahSemMtxes[2], RT_INDEFINITE_WAIT), VINF_SUCCESS);
1150 RTTEST_CHECK_RC(g_hTest, RTSemMutexRequest(g_ahSemMtxes[3], RT_INDEFINITE_WAIT), VINF_SUCCESS);
1151
1152 /* Now, leave and re-enter the critsects in a way that should break the
1153 order and check that we get the appropriate response. */
1154 int rc;
1155 RTTEST_CHECK_RC(g_hTest, RTSemMutexRelease(g_ahSemMtxes[0]), VINF_SUCCESS);
1156 RTTEST_CHECK_RC(g_hTest, rc = RTSemMutexRequest(g_ahSemMtxes[0], RT_INDEFINITE_WAIT), VERR_SEM_LV_WRONG_ORDER);
1157 if (RT_SUCCESS(rc))
1158 RTTEST_CHECK_RC(g_hTest, RTSemMutexRelease(g_ahSemMtxes[0]), VINF_SUCCESS);
1159
1160 /* Check that recursion isn't subject to order checks. */
1161 RTTEST_CHECK_RC(g_hTest, rc = RTSemMutexRequest(g_ahSemMtxes[1], RT_INDEFINITE_WAIT), VINF_SUCCESS);
1162 if (RT_SUCCESS(rc))
1163 RTTEST_CHECK_RC(g_hTest, RTSemMutexRelease(g_ahSemMtxes[1]), VINF_SUCCESS);
1164
1165 /* Enable strict release order for class 2 and check that violations
1166 are caught - including recursion. */
1167 RTTEST_CHECK_RC(g_hTest, RTLockValidatorClassEnforceStrictReleaseOrder(g_ahClasses[2], true), VINF_SUCCESS);
1168
1169 RTTEST_CHECK_RC(g_hTest, RTSemMutexRequest(g_ahSemMtxes[2], RT_INDEFINITE_WAIT), VINF_SUCCESS); /* start recursion */
1170 RTTEST_CHECK_RC(g_hTest, RTSemMutexRequest(g_ahSemMtxes[3], RT_INDEFINITE_WAIT), VINF_SUCCESS);
1171 RTTEST_CHECK_RC(g_hTest, RTSemMutexRelease(g_ahSemMtxes[2]), VERR_SEM_LV_WRONG_RELEASE_ORDER);
1172 RTTEST_CHECK_RC(g_hTest, RTSemMutexRelease(g_ahSemMtxes[3]), VINF_SUCCESS);
1173 RTTEST_CHECK_RC(g_hTest, RTSemMutexRelease(g_ahSemMtxes[2]), VINF_SUCCESS); /* end recursion */
1174
1175 RTTEST_CHECK_RC(g_hTest, RTSemMutexRelease(g_ahSemMtxes[2]), VERR_SEM_LV_WRONG_RELEASE_ORDER);
1176 RTTEST_CHECK_RC(g_hTest, RTSemMutexRelease(g_ahSemMtxes[1]), VINF_SUCCESS);
1177 RTTEST_CHECK_RC(g_hTest, RTSemMutexRelease(g_ahSemMtxes[3]), VINF_SUCCESS);
1178 RTTEST_CHECK_RC(g_hTest, RTSemMutexRelease(g_ahSemMtxes[2]), VINF_SUCCESS);
1179
1180 /* clean up */
1181 for (int i = 4 - 1; i >= 0; i--)
1182 {
1183 RTTEST_CHECK(g_hTest, RTLockValidatorClassRelease(g_ahClasses[i]) == 1);
1184 g_ahClasses[i] = NIL_RTLOCKVALCLASS;
1185 RTTEST_CHECK_RC_RETV(g_hTest, RTSemMutexDestroy(g_ahSemMtxes[i]), VINF_SUCCESS);
1186 }
1187}
1188
1189
1190
1191
1192static const char *testCheckIfLockValidationIsCompiledIn(void)
1193{
1194 RTCRITSECT CritSect;
1195 RTTEST_CHECK_RC_OK_RET(g_hTest, RTCritSectInit(&CritSect), "");
1196 RTTEST_CHECK_RC_OK_RET(g_hTest, RTCritSectEnter(&CritSect), "");
1197 bool fRet = CritSect.pValidatorRec
1198 && CritSect.pValidatorRec->hThread == RTThreadSelf();
1199 RTTEST_CHECK_RC_OK_RET(g_hTest, RTCritSectLeave(&CritSect), "");
1200 RTTEST_CHECK_RC_OK_RET(g_hTest, RTCritSectDelete(&CritSect), "");
1201 if (!fRet)
1202 return "Lock validation is not enabled for critical sections";
1203
1204 /* deadlock detection for RTSemRW */
1205 RTSEMRW hSemRW;
1206 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemRWCreateEx(&hSemRW, 0 /*fFlags*/, NIL_RTLOCKVALCLASS,
1207 RTLOCKVAL_SUB_CLASS_NONE, "RTSemRW-1"), NULL);
1208 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemRWRequestRead(hSemRW, 50), "");
1209 int rc = RTSemRWRequestWrite(hSemRW, 1);
1210 RTTEST_CHECK_RET(g_hTest, RT_FAILURE_NP(rc), "");
1211 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemRWReleaseRead(hSemRW), "");
1212 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemRWDestroy(hSemRW), "");
1213 if (rc != VERR_SEM_LV_ILLEGAL_UPGRADE)
1214 return "Deadlock detection is not enabled for the read/write semaphores";
1215
1216 /* lock order for RTSemRW */
1217 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemRWCreateEx(&hSemRW, 0 /*fFlags*/,
1218 RTLockValidatorClassCreateUnique(RT_SRC_POS, NULL),
1219 RTLOCKVAL_SUB_CLASS_NONE, "RTSemRW-2"), "");
1220 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemRWRequestRead(hSemRW, 50), "");
1221 rc = RTSemRWRequestWrite(hSemRW, 1);
1222 RTTEST_CHECK_RET(g_hTest, RT_FAILURE_NP(rc), "");
1223 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemRWReleaseRead(hSemRW), "");
1224 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemRWDestroy(hSemRW), "");
1225 if (rc != VERR_SEM_LV_WRONG_ORDER)
1226 {
1227 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "%Rrc\n", rc);
1228 return "Lock order validation is not enabled for the read/write semaphores";
1229 }
1230
1231 /* lock order for RTSemMutex */
1232 RTSEMMUTEX hSemMtx1;
1233 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemMutexCreateEx(&hSemMtx1, 0 /*fFlags*/,
1234 RTLockValidatorClassCreateUnique(RT_SRC_POS, NULL),
1235 RTLOCKVAL_SUB_CLASS_NONE, "RTSemMtx-1"), "");
1236 RTSEMMUTEX hSemMtx2;
1237 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemMutexCreateEx(&hSemMtx2, 0 /*fFlags*/,
1238 RTLockValidatorClassCreateUnique(RT_SRC_POS, NULL),
1239 RTLOCKVAL_SUB_CLASS_NONE, "RTSemMtx-2"), "");
1240 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemMutexRequest(hSemMtx1, 50), "");
1241 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemMutexRequest(hSemMtx2, 50), "");
1242 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemMutexRelease(hSemMtx2), "");
1243 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemMutexRelease(hSemMtx1), "");
1244
1245 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemMutexRequest(hSemMtx2, 50), "");
1246 rc = RTSemMutexRequest(hSemMtx1, 50);
1247 RTTEST_CHECK_RET(g_hTest, RT_FAILURE_NP(rc), "");
1248 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemMutexRelease(hSemMtx2), "");
1249 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemMutexDestroy(hSemMtx2), ""); hSemMtx2 = NIL_RTSEMMUTEX;
1250 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemMutexDestroy(hSemMtx1), ""); hSemMtx1 = NIL_RTSEMMUTEX;
1251 if (rc != VERR_SEM_LV_WRONG_ORDER)
1252 return "Lock order validation is not enabled for the mutex semaphores";
1253
1254 /* signaller checks on event sems. */
1255 RTSEMEVENT hSemEvt;
1256 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemEventCreate(&hSemEvt), "");
1257 RTSemEventSetSignaller(hSemEvt, RTThreadSelf());
1258 RTSemEventSetSignaller(hSemEvt, NIL_RTTHREAD);
1259 rc = RTSemEventSignal(hSemEvt);
1260 RTTEST_CHECK_RET(g_hTest, RT_FAILURE_NP(rc), "");
1261 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemEventDestroy(hSemEvt), "");
1262 if (rc != VERR_SEM_LV_NOT_SIGNALLER)
1263 return "Signalling checks are not enabled for the event semaphores";
1264
1265 /* signaller checks on multiple release event sems. */
1266 RTSEMEVENTMULTI hSemEvtMulti;
1267 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemEventMultiCreate(&hSemEvtMulti), "");
1268 RTSemEventMultiSetSignaller(hSemEvtMulti, RTThreadSelf());
1269 RTSemEventMultiSetSignaller(hSemEvtMulti, NIL_RTTHREAD);
1270 rc = RTSemEventMultiSignal(hSemEvtMulti);
1271 RTTEST_CHECK_RET(g_hTest, RT_FAILURE_NP(rc), "");
1272 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemEventMultiDestroy(hSemEvtMulti), "");
1273 if (rc != VERR_SEM_LV_NOT_SIGNALLER)
1274 return "Signalling checks are not enabled for the multiple release event semaphores";
1275
1276 /* we're good */
1277 return NULL;
1278}
1279
1280
1281int main()
1282{
1283 /*
1284 * Init.
1285 */
1286 int rc = RTTestInitAndCreate("tstRTLockValidator", &g_hTest);
1287 if (rc)
1288 return rc;
1289 RTTestBanner(g_hTest);
1290
1291 RTLockValidatorSetEnabled(true);
1292 RTLockValidatorSetMayPanic(false);
1293 RTLockValidatorSetQuiet(true);
1294 const char *pszWhyDisabled = testCheckIfLockValidationIsCompiledIn();
1295 if (pszWhyDisabled)
1296 return RTTestErrorCount(g_hTest) > 0
1297 ? RTTestSummaryAndDestroy(g_hTest)
1298 : RTTestSkipAndDestroy(g_hTest, pszWhyDisabled);
1299 RTLockValidatorSetQuiet(false);
1300
1301 bool fTestDd = true;
1302 bool fTestLo = true;
1303
1304 /*
1305 * Some initial tests with verbose output (all single pass).
1306 */
1307 if (fTestDd)
1308 {
1309 testDd1(3, 0);
1310 testDd2(1, 0);
1311 testDd2(3, 0);
1312 testDd5(3, 0);
1313 testDd6(3, 0);
1314 testDd7(3, 0);
1315 }
1316 if (fTestLo)
1317 {
1318 testLo1();
1319 testLo2();
1320 testLo3();
1321 testLo4();
1322 }
1323
1324
1325 /*
1326 * If successful, perform more thorough testing without noisy output.
1327 */
1328 if (RTTestErrorCount(g_hTest) == 0)
1329 {
1330 RTLockValidatorSetQuiet(true);
1331
1332 if (fTestDd)
1333 {
1334 testDd1( 2, SECS_SIMPLE_TEST);
1335 testDd1( 3, SECS_SIMPLE_TEST);
1336 testDd1( 7, SECS_SIMPLE_TEST);
1337 testDd1(10, SECS_SIMPLE_TEST);
1338 testDd1(15, SECS_SIMPLE_TEST);
1339 testDd1(30, SECS_SIMPLE_TEST);
1340
1341 testDd2( 1, SECS_SIMPLE_TEST);
1342 testDd2( 2, SECS_SIMPLE_TEST);
1343 testDd2( 3, SECS_SIMPLE_TEST);
1344 testDd2( 7, SECS_SIMPLE_TEST);
1345 testDd2(10, SECS_SIMPLE_TEST);
1346 testDd2(15, SECS_SIMPLE_TEST);
1347 testDd2(30, SECS_SIMPLE_TEST);
1348
1349 testDd3( 2, SECS_SIMPLE_TEST);
1350 testDd3(10, SECS_SIMPLE_TEST);
1351
1352 testDd4( 2, SECS_RACE_TEST);
1353 testDd4( 6, SECS_RACE_TEST);
1354 testDd4(10, SECS_RACE_TEST);
1355 testDd4(30, SECS_RACE_TEST);
1356
1357 testDd5( 2, SECS_RACE_TEST);
1358 testDd5( 3, SECS_RACE_TEST);
1359 testDd5( 7, SECS_RACE_TEST);
1360 testDd5(10, SECS_RACE_TEST);
1361 testDd5(15, SECS_RACE_TEST);
1362 testDd5(30, SECS_RACE_TEST);
1363
1364 testDd6( 2, SECS_SIMPLE_TEST);
1365 testDd6( 3, SECS_SIMPLE_TEST);
1366 testDd6( 7, SECS_SIMPLE_TEST);
1367 testDd6(10, SECS_SIMPLE_TEST);
1368 testDd6(15, SECS_SIMPLE_TEST);
1369 testDd6(30, SECS_SIMPLE_TEST);
1370
1371 testDd7( 2, SECS_SIMPLE_TEST);
1372 testDd7( 3, SECS_SIMPLE_TEST);
1373 testDd7( 7, SECS_SIMPLE_TEST);
1374 testDd7(10, SECS_SIMPLE_TEST);
1375 testDd7(15, SECS_SIMPLE_TEST);
1376 testDd7(30, SECS_SIMPLE_TEST);
1377 }
1378 }
1379
1380 return RTTestSummaryAndDestroy(g_hTest);
1381}
1382
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette