VirtualBox

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

Last change on this file since 62477 was 62477, checked in by vboxsync, 8 years ago

(C) 2016

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 60.2 KB
Line 
1/* $Id: tstRTLockValidator.cpp 62477 2016-07-22 18:27:37Z vboxsync $ */
2/** @file
3 * IPRT Testcase - RTLockValidator.
4 */
5
6/*
7 * Copyright (C) 2006-2016 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
426 RTTEST_CHECK_RC_RET(g_hTest, RTCritSectEnter(pMine), VINF_SUCCESS, rcCheck);
427 if (!(i & 1))
428 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(pMine), VINF_SUCCESS);
429 if (RT_SUCCESS(testWaitForCritSectToBeOwned(pNext)))
430 {
431 int rc;
432 if (i != g_iDeadlockThread)
433 {
434 testThreadBlocking();
435 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(pNext), VINF_SUCCESS);
436 }
437 else
438 {
439 RTTEST_CHECK_RC_OK(g_hTest, rc = testWaitForAllOtherThreadsToSleep(RTTHREADSTATE_CRITSECT, 1));
440 if (RT_SUCCESS(rc))
441 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(pNext), VERR_SEM_LV_DEADLOCK);
442 }
443 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
444 if (RT_SUCCESS(rc))
445 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectLeave(pNext), VINF_SUCCESS);
446 }
447 if (!(i & 1))
448 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(pMine), VINF_SUCCESS);
449 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(pMine), VINF_SUCCESS);
450 return VINF_SUCCESS;
451}
452
453
454static void testDd1(uint32_t cThreads, uint32_t cSecs)
455{
456 testIt(cThreads, cSecs, false, testDd1Thread, "deadlock, critsect");
457}
458
459
460static DECLCALLBACK(int) testDd2Thread(RTTHREAD ThreadSelf, void *pvUser)
461{
462 uintptr_t i = (uintptr_t)pvUser;
463 RTSEMRW hMine = g_ahSemRWs[i];
464 RTSEMRW hNext = g_ahSemRWs[(i + 1) % g_cThreads];
465 int rc;
466
467 if (i & 1)
468 {
469 RTTEST_CHECK_RC_RET(g_hTest, RTSemRWRequestWrite(hMine, RT_INDEFINITE_WAIT), VINF_SUCCESS, rcCheck);
470 if ((i & 3) == 3)
471 RTTEST_CHECK_RC(g_hTest, RTSemRWRequestWrite(hMine, RT_INDEFINITE_WAIT), VINF_SUCCESS);
472 }
473 else
474 RTTEST_CHECK_RC_RET(g_hTest, RTSemRWRequestRead(hMine, RT_INDEFINITE_WAIT), VINF_SUCCESS, rcCheck);
475 if (RT_SUCCESS(testWaitForSemRWToBeOwned(hNext)))
476 {
477 if (i != g_iDeadlockThread)
478 {
479 testThreadBlocking();
480 RTTEST_CHECK_RC(g_hTest, rc = RTSemRWRequestWrite(hNext, RT_INDEFINITE_WAIT), VINF_SUCCESS);
481 }
482 else
483 {
484 RTTEST_CHECK_RC_OK(g_hTest, rc = testWaitForAllOtherThreadsToSleep(RTTHREADSTATE_RW_WRITE, 1));
485 if (RT_SUCCESS(rc))
486 {
487 if (g_cThreads > 1)
488 RTTEST_CHECK_RC(g_hTest, rc = RTSemRWRequestWrite(hNext, RT_INDEFINITE_WAIT), VERR_SEM_LV_DEADLOCK);
489 else
490 RTTEST_CHECK_RC(g_hTest, rc = RTSemRWRequestWrite(hNext, RT_INDEFINITE_WAIT), VERR_SEM_LV_ILLEGAL_UPGRADE);
491 }
492 }
493 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
494 if (RT_SUCCESS(rc))
495 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(hNext), VINF_SUCCESS);
496 }
497 if (i & 1)
498 {
499 if ((i & 3) == 3)
500 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(hMine), VINF_SUCCESS);
501 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(hMine), VINF_SUCCESS);
502 }
503 else
504 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseRead(hMine), VINF_SUCCESS);
505 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
506 return VINF_SUCCESS;
507}
508
509
510static void testDd2(uint32_t cThreads, uint32_t cSecs)
511{
512 testIt(cThreads, cSecs, false, testDd2Thread, "deadlock, read-write");
513}
514
515
516static DECLCALLBACK(int) testDd3Thread(RTTHREAD ThreadSelf, void *pvUser)
517{
518 uintptr_t i = (uintptr_t)pvUser;
519 RTSEMRW hMine = g_ahSemRWs[i];
520 RTSEMRW hNext = g_ahSemRWs[(i + 1) % g_cThreads];
521 int rc;
522
523 if (i & 1)
524 RTTEST_CHECK_RC_RET(g_hTest, RTSemRWRequestWrite(hMine, RT_INDEFINITE_WAIT), VINF_SUCCESS, rcCheck);
525 else
526 RTTEST_CHECK_RC_RET(g_hTest, RTSemRWRequestRead(hMine, RT_INDEFINITE_WAIT), VINF_SUCCESS, rcCheck);
527 if (RT_SUCCESS(testWaitForSemRWToBeOwned(hNext)))
528 {
529 do
530 {
531 rc = RTSemRWRequestWrite(hNext, TEST_SMALL_TIMEOUT);
532 if (rc != VINF_SUCCESS && rc != VERR_SEM_LV_DEADLOCK && rc != VERR_SEM_LV_ILLEGAL_UPGRADE)
533 {
534 RTTestFailed(g_hTest, "#%u: RTSemRWRequestWrite -> %Rrc\n", i, rc);
535 break;
536 }
537 if (RT_SUCCESS(rc))
538 {
539 RTTEST_CHECK_RC(g_hTest, rc = RTSemRWReleaseWrite(hNext), VINF_SUCCESS);
540 if (RT_FAILURE(rc))
541 break;
542 }
543 else
544 ASMAtomicIncU32(&g_cDeadlocks);
545 ASMAtomicIncU32(&g_cLoops);
546 } while (RTTimeNanoTS() < g_NanoTSStop);
547 }
548 if (i & 1)
549 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(hMine), VINF_SUCCESS);
550 else
551 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseRead(hMine), VINF_SUCCESS);
552 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
553 return VINF_SUCCESS;
554}
555
556
557static void testDd3(uint32_t cThreads, uint32_t cSecs)
558{
559 testIt(cThreads, cSecs, true, testDd3Thread, "deadlock, read-write race");
560}
561
562
563static DECLCALLBACK(int) testDd4Thread(RTTHREAD ThreadSelf, void *pvUser)
564{
565 uintptr_t i = (uintptr_t)pvUser;
566 RTSEMRW hMine = g_ahSemRWs[i];
567 RTSEMRW hNext = g_ahSemRWs[(i + 1) % g_cThreads];
568
569 do
570 {
571 int rc1 = (i & 1 ? RTSemRWRequestWrite : RTSemRWRequestRead)(hMine, TEST_SMALL_TIMEOUT); /* ugly ;-) */
572 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
573 if (rc1 != VINF_SUCCESS && rc1 != VERR_SEM_LV_DEADLOCK && rc1 != VERR_SEM_LV_ILLEGAL_UPGRADE)
574 {
575 RTTestFailed(g_hTest, "#%u: RTSemRWRequest%s(hMine,) -> %Rrc\n", i, i & 1 ? "Write" : "read", rc1);
576 break;
577 }
578 if (RT_SUCCESS(rc1))
579 {
580 for (unsigned iInner = 0; iInner < 4; iInner++)
581 {
582 int rc2 = RTSemRWRequestWrite(hNext, TEST_SMALL_TIMEOUT);
583 if (rc2 != VINF_SUCCESS && rc2 != VERR_SEM_LV_DEADLOCK && rc2 != VERR_SEM_LV_ILLEGAL_UPGRADE)
584 {
585 RTTestFailed(g_hTest, "#%u: RTSemRWRequestWrite -> %Rrc\n", i, rc2);
586 break;
587 }
588 if (RT_SUCCESS(rc2))
589 {
590 RTTEST_CHECK_RC(g_hTest, rc2 = RTSemRWReleaseWrite(hNext), VINF_SUCCESS);
591 if (RT_FAILURE(rc2))
592 break;
593 }
594 else
595 ASMAtomicIncU32(&g_cDeadlocks);
596 ASMAtomicIncU32(&g_cLoops);
597 }
598
599 RTTEST_CHECK_RC(g_hTest, rc1 = (i & 1 ? RTSemRWReleaseWrite : RTSemRWReleaseRead)(hMine), VINF_SUCCESS);
600 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
601 if (RT_FAILURE(rc1))
602 break;
603 }
604 else
605 ASMAtomicIncU32(&g_cDeadlocks);
606 ASMAtomicIncU32(&g_cLoops);
607 } while (RTTimeNanoTS() < g_NanoTSStop);
608
609 return VINF_SUCCESS;
610}
611
612
613static void testDd4(uint32_t cThreads, uint32_t cSecs)
614{
615 testIt(cThreads, cSecs, true, testDd4Thread, "deadlock, read-write race v2");
616}
617
618
619static DECLCALLBACK(int) testDd5Thread(RTTHREAD ThreadSelf, void *pvUser)
620{
621 uintptr_t i = (uintptr_t)pvUser;
622 RTSEMMUTEX hMine = g_ahSemMtxes[i];
623 RTSEMMUTEX hNext = g_ahSemMtxes[(i + 1) % g_cThreads];
624
625 RTTEST_CHECK_RC_RET(g_hTest, RTSemMutexRequest(hMine, RT_INDEFINITE_WAIT), VINF_SUCCESS, rcCheck);
626 if (i & 1)
627 RTTEST_CHECK_RC(g_hTest, RTSemMutexRequest(hMine, RT_INDEFINITE_WAIT), VINF_SUCCESS);
628 if (RT_SUCCESS(testWaitForSemMutexToBeOwned(hNext)))
629 {
630 int rc;
631 if (i != g_iDeadlockThread)
632 {
633 testThreadBlocking();
634 RTTEST_CHECK_RC(g_hTest, rc = RTSemMutexRequest(hNext, RT_INDEFINITE_WAIT), VINF_SUCCESS);
635 }
636 else
637 {
638 RTTEST_CHECK_RC_OK(g_hTest, rc = testWaitForAllOtherThreadsToSleep(RTTHREADSTATE_MUTEX, 1));
639 if (RT_SUCCESS(rc))
640 RTTEST_CHECK_RC(g_hTest, rc = RTSemMutexRequest(hNext, RT_INDEFINITE_WAIT), VERR_SEM_LV_DEADLOCK);
641 }
642 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
643 if (RT_SUCCESS(rc))
644 RTTEST_CHECK_RC(g_hTest, rc = RTSemMutexRelease(hNext), VINF_SUCCESS);
645 }
646 if (i & 1)
647 RTTEST_CHECK_RC(g_hTest, RTSemMutexRelease(hMine), VINF_SUCCESS);
648 RTTEST_CHECK_RC(g_hTest, RTSemMutexRelease(hMine), VINF_SUCCESS);
649 return VINF_SUCCESS;
650}
651
652
653static void testDd5(uint32_t cThreads, uint32_t cSecs)
654{
655 testIt(cThreads, cSecs, false, testDd5Thread, "deadlock, mutex");
656}
657
658
659static DECLCALLBACK(int) testDd6Thread(RTTHREAD ThreadSelf, void *pvUser)
660{
661 uintptr_t i = (uintptr_t)pvUser;
662 PRTCRITSECT pMine = &g_aCritSects[i];
663 PRTCRITSECT pNext = &g_aCritSects[(i + 1) % g_cThreads];
664
665 RTTEST_CHECK_RC_RET(g_hTest, RTCritSectEnter(pMine), VINF_SUCCESS, rcCheck);
666 if (i & 1)
667 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(pMine), VINF_SUCCESS);
668 if (RT_SUCCESS(testWaitForCritSectToBeOwned(pNext)))
669 {
670 int rc;
671 if (i != g_iDeadlockThread)
672 {
673 testThreadBlocking();
674 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(pNext), VINF_SUCCESS);
675 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
676 if (RT_SUCCESS(rc))
677 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectLeave(pNext), VINF_SUCCESS);
678 }
679 else
680 {
681 RTTEST_CHECK_RC_OK(g_hTest, rc = testWaitForAllOtherThreadsToSleep(RTTHREADSTATE_CRITSECT, 1));
682 if (RT_SUCCESS(rc))
683 {
684 RTSemEventSetSignaller(g_hSemEvt, g_ahThreads[0]);
685 for (uint32_t iThread = 1; iThread < g_cThreads; iThread++)
686 RTSemEventAddSignaller(g_hSemEvt, g_ahThreads[iThread]);
687 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
688 RTTEST_CHECK_RC(g_hTest, RTSemEventWait(g_hSemEvt, TEST_SMALL_TIMEOUT), VERR_SEM_LV_DEADLOCK);
689 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
690 RTTEST_CHECK_RC(g_hTest, RTSemEventSignal(g_hSemEvt), VINF_SUCCESS);
691 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
692 RTTEST_CHECK_RC(g_hTest, RTSemEventWait(g_hSemEvt, TEST_SMALL_TIMEOUT), VINF_SUCCESS);
693 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
694 RTSemEventSetSignaller(g_hSemEvt, NIL_RTTHREAD);
695 }
696 }
697 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
698 }
699 if (i & 1)
700 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(pMine), VINF_SUCCESS);
701 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(pMine), VINF_SUCCESS);
702 return VINF_SUCCESS;
703}
704
705
706static void testDd6(uint32_t cThreads, uint32_t cSecs)
707{
708 testIt(cThreads, cSecs, false, testDd6Thread, "deadlock, event");
709}
710
711
712static DECLCALLBACK(int) testDd7Thread(RTTHREAD ThreadSelf, void *pvUser)
713{
714 uintptr_t i = (uintptr_t)pvUser;
715 PRTCRITSECT pMine = &g_aCritSects[i];
716 PRTCRITSECT pNext = &g_aCritSects[(i + 1) % g_cThreads];
717
718 RTTEST_CHECK_RC_RET(g_hTest, RTCritSectEnter(pMine), VINF_SUCCESS, rcCheck);
719 if (i & 1)
720 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(pMine), VINF_SUCCESS);
721 if (RT_SUCCESS(testWaitForCritSectToBeOwned(pNext)))
722 {
723 int rc;
724 if (i != g_iDeadlockThread)
725 {
726 testThreadBlocking();
727 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(pNext), VINF_SUCCESS);
728 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
729 if (RT_SUCCESS(rc))
730 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectLeave(pNext), VINF_SUCCESS);
731 }
732 else
733 {
734 RTTEST_CHECK_RC_OK(g_hTest, rc = testWaitForAllOtherThreadsToSleep(RTTHREADSTATE_CRITSECT, 1));
735 if (RT_SUCCESS(rc))
736 {
737 RTSemEventMultiSetSignaller(g_hSemEvtMulti, g_ahThreads[0]);
738 for (uint32_t iThread = 1; iThread < g_cThreads; iThread++)
739 RTSemEventMultiAddSignaller(g_hSemEvtMulti, g_ahThreads[iThread]);
740 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
741 RTTEST_CHECK_RC(g_hTest, RTSemEventMultiReset(g_hSemEvtMulti), VINF_SUCCESS);
742 RTTEST_CHECK_RC(g_hTest, RTSemEventMultiWait(g_hSemEvtMulti, TEST_SMALL_TIMEOUT), VERR_SEM_LV_DEADLOCK);
743 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
744 RTTEST_CHECK_RC(g_hTest, RTSemEventMultiSignal(g_hSemEvtMulti), VINF_SUCCESS);
745 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
746 RTTEST_CHECK_RC(g_hTest, RTSemEventMultiWait(g_hSemEvtMulti, TEST_SMALL_TIMEOUT), VINF_SUCCESS);
747 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
748 RTSemEventMultiSetSignaller(g_hSemEvtMulti, NIL_RTTHREAD);
749 }
750 }
751 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
752 }
753 if (i & 1)
754 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(pMine), VINF_SUCCESS);
755 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(pMine), VINF_SUCCESS);
756 return VINF_SUCCESS;
757}
758
759
760static void testDd7(uint32_t cThreads, uint32_t cSecs)
761{
762 testIt(cThreads, cSecs, false, testDd7Thread, "deadlock, event multi");
763}
764
765
766static void testLo1(void)
767{
768 RTTestSub(g_hTest, "locking order basics");
769
770 /* Initialize the critsections, the first 4 has their own classes, the rest
771 use the same class and relies on the sub-class mechanism for ordering. */
772 for (unsigned i = 0; i < RT_ELEMENTS(g_ahClasses); i++)
773 {
774 if (i <= 3)
775 {
776 RTTEST_CHECK_RC_RETV(g_hTest, RTLockValidatorClassCreate(&g_ahClasses[i], true /*fAutodidact*/, RT_SRC_POS, "testLo1-%u", i), VINF_SUCCESS);
777 RTTEST_CHECK_RC_RETV(g_hTest, RTCritSectInitEx(&g_aCritSects[i], 0, g_ahClasses[i], RTLOCKVAL_SUB_CLASS_NONE, "RTCritSectLO-Auto"), VINF_SUCCESS);
778 RTTEST_CHECK_RETV(g_hTest, RTLockValidatorClassRetain(g_ahClasses[i]) == 3);
779 RTTEST_CHECK_RETV(g_hTest, RTLockValidatorClassRelease(g_ahClasses[i]) == 2);
780 }
781 else
782 {
783 g_ahClasses[i] = RTLockValidatorClassForSrcPos(RT_SRC_POS, "testLo1-%u", i);
784 RTTEST_CHECK_RETV(g_hTest, g_ahClasses[i] != NIL_RTLOCKVALCLASS);
785 RTTEST_CHECK_RETV(g_hTest, i == 4 || g_ahClasses[i] == g_ahClasses[i - 1]);
786 if (i == 4)
787 RTTEST_CHECK_RC_RETV(g_hTest, RTCritSectInitEx(&g_aCritSects[i], 0, g_ahClasses[i], RTLOCKVAL_SUB_CLASS_NONE, "RTCritSectLO-None"), VINF_SUCCESS);
788 else if (i == 5)
789 RTTEST_CHECK_RC_RETV(g_hTest, RTCritSectInitEx(&g_aCritSects[i], 0, g_ahClasses[i], RTLOCKVAL_SUB_CLASS_ANY, "RTCritSectLO-Any"), VINF_SUCCESS);
790 else
791 RTTEST_CHECK_RC_RETV(g_hTest, RTCritSectInitEx(&g_aCritSects[i], 0, g_ahClasses[i], RTLOCKVAL_SUB_CLASS_USER + i, "RTCritSectLO-User"), VINF_SUCCESS);
792
793 RTTEST_CHECK_RETV(g_hTest, RTLockValidatorClassRetain(g_ahClasses[i]) == 1 + (i - 4 + 1) * 2); /* released in cleanup. */
794 }
795 }
796
797 /* Enter the first 4 critsects in ascending order and thereby defining
798 this as a valid lock order. */
799 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[0]), VINF_SUCCESS);
800 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[1]), VINF_SUCCESS);
801 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[2]), VINF_SUCCESS);
802 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[3]), VINF_SUCCESS);
803
804 /* Now, leave and re-enter the critsects in a way that should break the
805 order and check that we get the appropriate response. */
806 int rc;
807 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[0]), VINF_SUCCESS);
808 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(&g_aCritSects[0]), VERR_SEM_LV_WRONG_ORDER);
809 if (RT_SUCCESS(rc))
810 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[0]), VINF_SUCCESS);
811
812 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[1]), VINF_SUCCESS);
813 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(&g_aCritSects[1]), VERR_SEM_LV_WRONG_ORDER);
814 if (RT_SUCCESS(rc))
815 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[1]), VINF_SUCCESS);
816
817 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[2]), VINF_SUCCESS);
818 RTTEST_CHECK_RC(g_hTest, rc= RTCritSectEnter(&g_aCritSects[2]), VERR_SEM_LV_WRONG_ORDER);
819 if (RT_SUCCESS(rc))
820 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[2]), VINF_SUCCESS);
821
822 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[3]), VINF_SUCCESS);
823
824 /* Check that recursion isn't subject to order checks. */
825 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[0]), VINF_SUCCESS);
826 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[1]), VINF_SUCCESS);
827 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[2]), VINF_SUCCESS);
828 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[3]), VINF_SUCCESS);
829 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(&g_aCritSects[0]), VINF_SUCCESS);
830 if (RT_SUCCESS(rc))
831 {
832 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[0]), VINF_SUCCESS);
833 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[3]), VINF_SUCCESS);
834 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[2]), VINF_SUCCESS);
835 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[1]), VINF_SUCCESS);
836
837 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[3]), VINF_SUCCESS);
838 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[2]), VINF_SUCCESS);
839 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[1]), VINF_SUCCESS);
840 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[0]), VINF_SUCCESS);
841 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[0]), VINF_SUCCESS);
842 }
843 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[3]), VINF_SUCCESS);
844 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[2]), VINF_SUCCESS);
845 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[1]), VINF_SUCCESS);
846 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[0]), VINF_SUCCESS);
847
848 /* Enable strict release order for class 2 and check that violations
849 are caught. */
850 RTTEST_CHECK_RC(g_hTest, RTLockValidatorClassEnforceStrictReleaseOrder(g_ahClasses[2], true), VINF_SUCCESS);
851
852 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[0]), VINF_SUCCESS);
853 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[1]), VINF_SUCCESS);
854 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[2]), VINF_SUCCESS);
855 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[3]), VINF_SUCCESS);
856
857 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectLeave(&g_aCritSects[2]), VERR_SEM_LV_WRONG_RELEASE_ORDER);
858 if (RT_FAILURE(rc))
859 {
860 /* applies to recursions as well */
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 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[2]), VERR_SEM_LV_WRONG_RELEASE_ORDER);
864 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[3]), VINF_SUCCESS);
865 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[2]), VINF_SUCCESS);
866 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[2]), VERR_SEM_LV_WRONG_RELEASE_ORDER);
867 }
868 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[0]), VINF_SUCCESS);
869 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[1]), VINF_SUCCESS);
870 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[3]), VINF_SUCCESS);
871 if (RT_FAILURE(rc))
872 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[2]), VINF_SUCCESS);
873
874 /* Test that sub-class order works (4 = NONE, 5 = ANY, 6+ = USER). */
875 uint32_t cErrorsBefore = RTTestErrorCount(g_hTest);
876 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[7]), VINF_SUCCESS);
877
878 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(&g_aCritSects[4]), VERR_SEM_LV_WRONG_ORDER);
879 if (RT_SUCCESS(rc))
880 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[4]), VINF_SUCCESS);
881
882 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(&g_aCritSects[5]), VINF_SUCCESS);
883 if (RT_SUCCESS(rc))
884 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[5]), VINF_SUCCESS);
885
886 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(&g_aCritSects[8]), VINF_SUCCESS);
887 if (RT_SUCCESS(rc))
888 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[8]), VINF_SUCCESS);
889
890 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(&g_aCritSects[6]), VERR_SEM_LV_WRONG_ORDER);
891 if (RT_SUCCESS(rc))
892 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[6]), VINF_SUCCESS);
893
894 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(&g_aCritSects[7]), VINF_SUCCESS);
895 if (RT_SUCCESS(rc))
896 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[7]), VINF_SUCCESS);
897 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[7]), VINF_SUCCESS);
898
899 /* Check that NONE trumps both ANY and USER. */
900 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[4]), VINF_SUCCESS);
901
902 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(&g_aCritSects[5]), VERR_SEM_LV_WRONG_ORDER);
903 if (RT_SUCCESS(rc))
904 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[5]), VINF_SUCCESS);
905
906 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(&g_aCritSects[6]), VERR_SEM_LV_WRONG_ORDER);
907 if (RT_SUCCESS(rc))
908 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[6]), VINF_SUCCESS);
909
910 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[4]), VINF_SUCCESS);
911
912 /* Take all the locks using sub-classes. */
913 if (cErrorsBefore == RTTestErrorCount(g_hTest))
914 {
915 bool fSavedQuiet = RTLockValidatorSetQuiet(true);
916 for (uint32_t i = 6; i < RT_ELEMENTS(g_aCritSects); i++)
917 {
918 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[i]), VINF_SUCCESS);
919 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[4]), VERR_SEM_LV_WRONG_ORDER);
920 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[5]), VINF_SUCCESS);
921 }
922 for (uint32_t i = 6; i < RT_ELEMENTS(g_aCritSects); i++)
923 {
924 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[i]), VINF_SUCCESS);
925 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[5]), VINF_SUCCESS);
926 }
927 RTLockValidatorSetQuiet(fSavedQuiet);
928 }
929
930 /* Work up some hash statistics and trigger a violation to show them. */
931 for (uint32_t i = 0; i < 10240; i++)
932 {
933 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[0]), VINF_SUCCESS);
934 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[1]), VINF_SUCCESS);
935 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[2]), VINF_SUCCESS);
936 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[3]), VINF_SUCCESS);
937 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[5]), VINF_SUCCESS);
938
939 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[5]), VINF_SUCCESS);
940 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[3]), VINF_SUCCESS);
941 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[2]), VINF_SUCCESS);
942 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[1]), VINF_SUCCESS);
943 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[0]), VINF_SUCCESS);
944 }
945 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[5]), VINF_SUCCESS);
946 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[3]), VERR_SEM_LV_WRONG_ORDER);
947 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[5]), VINF_SUCCESS);
948
949 /* clean up */
950 //for (int i = RT_ELEMENTS(g_ahClasses) - 1; i >= 0; i--)
951 for (unsigned i = 0; i < RT_ELEMENTS(g_ahClasses); i++)
952 {
953 uint32_t c;
954 if (i <= 3)
955 RTTEST_CHECK_MSG(g_hTest, (c = RTLockValidatorClassRelease(g_ahClasses[i])) == 5 - i,
956 (g_hTest, "c=%u i=%u\n", c, i));
957 else
958 {
959 uint32_t cExpect = 1 + (RT_ELEMENTS(g_ahClasses) - i) * 2 - 1;
960 RTTEST_CHECK_MSG(g_hTest, (c = RTLockValidatorClassRelease(g_ahClasses[i])) == cExpect,
961 (g_hTest, "c=%u e=%u i=%u\n", c, cExpect, i));
962 }
963 g_ahClasses[i] = NIL_RTLOCKVALCLASS;
964 RTTEST_CHECK_RC_RETV(g_hTest, RTCritSectDelete(&g_aCritSects[i]), VINF_SUCCESS);
965 }
966}
967
968
969static void testLo2(void)
970{
971 RTTestSub(g_hTest, "locking order, critsect");
972
973 /* Initialize the critsection with all different classes */
974 for (unsigned i = 0; i < 4; i++)
975 {
976 RTTEST_CHECK_RC_RETV(g_hTest, RTLockValidatorClassCreate(&g_ahClasses[i], true /*fAutodidact*/, RT_SRC_POS, "testLo2-%u", i), VINF_SUCCESS);
977 RTTEST_CHECK_RC_RETV(g_hTest, RTCritSectInitEx(&g_aCritSects[i], 0, g_ahClasses[i], RTLOCKVAL_SUB_CLASS_NONE, "RTCritSectLO"), VINF_SUCCESS);
978 RTTEST_CHECK_RETV(g_hTest, RTLockValidatorClassRetain(g_ahClasses[i]) == 3);
979 RTTEST_CHECK_RETV(g_hTest, RTLockValidatorClassRelease(g_ahClasses[i]) == 2);
980 }
981
982 /* Check the sub-class API.*/
983 RTTEST_CHECK(g_hTest, RTCritSectSetSubClass(&g_aCritSects[0], RTLOCKVAL_SUB_CLASS_ANY) == RTLOCKVAL_SUB_CLASS_NONE);
984 RTTEST_CHECK(g_hTest, RTCritSectSetSubClass(&g_aCritSects[0], RTLOCKVAL_SUB_CLASS_NONE) == RTLOCKVAL_SUB_CLASS_ANY);
985
986 /* Enter the first 4 critsects in ascending order and thereby defining
987 this as a valid lock order. */
988 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[0]), VINF_SUCCESS);
989 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[1]), VINF_SUCCESS);
990 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[2]), VINF_SUCCESS);
991 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[3]), VINF_SUCCESS);
992
993 /* Now, leave and re-enter the critsects in a way that should break the
994 order and check that we get the appropriate response. */
995 int rc;
996 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[0]), VINF_SUCCESS);
997 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(&g_aCritSects[0]), VERR_SEM_LV_WRONG_ORDER);
998 if (RT_SUCCESS(rc))
999 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[0]), VINF_SUCCESS);
1000
1001 /* Check that recursion isn't subject to order checks. */
1002 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(&g_aCritSects[1]), VINF_SUCCESS);
1003 if (RT_SUCCESS(rc))
1004 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[1]), VINF_SUCCESS);
1005
1006 /* Enable strict release order for class 2 and check that violations
1007 are caught - including recursion. */
1008 RTTEST_CHECK_RC(g_hTest, RTLockValidatorClassEnforceStrictReleaseOrder(g_ahClasses[2], true), VINF_SUCCESS);
1009 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[2]), VINF_SUCCESS); /* start recursion */
1010 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[3]), VINF_SUCCESS);
1011 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[2]), VERR_SEM_LV_WRONG_RELEASE_ORDER);
1012 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[3]), VINF_SUCCESS);
1013 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[2]), VINF_SUCCESS); /* end recursion */
1014 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[2]), VERR_SEM_LV_WRONG_RELEASE_ORDER);
1015 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[1]), VINF_SUCCESS);
1016 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[3]), VINF_SUCCESS);
1017 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[2]), VINF_SUCCESS);
1018
1019 /* clean up */
1020 for (int i = 4 - 1; i >= 0; i--)
1021 {
1022 RTTEST_CHECK(g_hTest, RTLockValidatorClassRelease(g_ahClasses[i]) == 1);
1023 g_ahClasses[i] = NIL_RTLOCKVALCLASS;
1024 RTTEST_CHECK_RC_RETV(g_hTest, RTCritSectDelete(&g_aCritSects[i]), VINF_SUCCESS);
1025 }
1026}
1027
1028
1029static void testLo3(void)
1030{
1031 RTTestSub(g_hTest, "locking order, read-write");
1032
1033 /* Initialize the critsection with all different classes */
1034 for (unsigned i = 0; i < 6; i++)
1035 {
1036 RTTEST_CHECK_RC_RETV(g_hTest, RTLockValidatorClassCreate(&g_ahClasses[i], true /*fAutodidact*/, RT_SRC_POS, "testLo3-%u", i), VINF_SUCCESS);
1037 RTTEST_CHECK_RC_RETV(g_hTest, RTSemRWCreateEx(&g_ahSemRWs[i], 0, g_ahClasses[i], RTLOCKVAL_SUB_CLASS_NONE, "hSemRW-Lo3-%u", i), VINF_SUCCESS);
1038 RTTEST_CHECK_RETV(g_hTest, RTLockValidatorClassRetain(g_ahClasses[i]) == 4);
1039 RTTEST_CHECK_RETV(g_hTest, RTLockValidatorClassRelease(g_ahClasses[i]) == 3);
1040 }
1041
1042 /* Check the sub-class API.*/
1043 RTTEST_CHECK(g_hTest, RTSemRWSetSubClass(g_ahSemRWs[0], RTLOCKVAL_SUB_CLASS_ANY) == RTLOCKVAL_SUB_CLASS_NONE);
1044 RTTEST_CHECK(g_hTest, RTSemRWSetSubClass(g_ahSemRWs[0], RTLOCKVAL_SUB_CLASS_NONE) == RTLOCKVAL_SUB_CLASS_ANY);
1045
1046 /* Enter the first 4 critsects in ascending order and thereby defining
1047 this as a valid lock order. */
1048 RTTEST_CHECK_RC(g_hTest, RTSemRWRequestWrite(g_ahSemRWs[0], RT_INDEFINITE_WAIT), VINF_SUCCESS);
1049 RTTEST_CHECK_RC(g_hTest, RTSemRWRequestRead( g_ahSemRWs[1], RT_INDEFINITE_WAIT), VINF_SUCCESS);
1050 RTTEST_CHECK_RC(g_hTest, RTSemRWRequestRead( g_ahSemRWs[2], RT_INDEFINITE_WAIT), VINF_SUCCESS);
1051 RTTEST_CHECK_RC(g_hTest, RTSemRWRequestWrite(g_ahSemRWs[3], RT_INDEFINITE_WAIT), VINF_SUCCESS);
1052 RTTEST_CHECK_RC(g_hTest, RTSemRWRequestWrite(g_ahSemRWs[4], RT_INDEFINITE_WAIT), VINF_SUCCESS);
1053 RTTEST_CHECK_RC(g_hTest, RTSemRWRequestWrite(g_ahSemRWs[5], RT_INDEFINITE_WAIT), VINF_SUCCESS);
1054
1055 /* Now, leave and re-enter the critsects in a way that should break the
1056 order and check that we get the appropriate response. */
1057 int rc;
1058 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(g_ahSemRWs[0]), VINF_SUCCESS);
1059 RTTEST_CHECK_RC(g_hTest, rc = RTSemRWRequestWrite(g_ahSemRWs[0], RT_INDEFINITE_WAIT), VERR_SEM_LV_WRONG_ORDER);
1060 if (RT_SUCCESS(rc))
1061 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(g_ahSemRWs[0]), VINF_SUCCESS);
1062
1063 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseRead(g_ahSemRWs[1]), VINF_SUCCESS);
1064 RTTEST_CHECK_RC(g_hTest, rc = RTSemRWRequestRead(g_ahSemRWs[1], RT_INDEFINITE_WAIT), VERR_SEM_LV_WRONG_ORDER);
1065 if (RT_SUCCESS(rc))
1066 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseRead(g_ahSemRWs[1]), VINF_SUCCESS);
1067
1068 /* Check that recursion isn't subject to order checks. */
1069 RTTEST_CHECK_RC(g_hTest, rc = RTSemRWRequestRead(g_ahSemRWs[2], RT_INDEFINITE_WAIT), VINF_SUCCESS);
1070 if (RT_SUCCESS(rc))
1071 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseRead(g_ahSemRWs[2]), VINF_SUCCESS);
1072 RTTEST_CHECK(g_hTest, RTSemRWGetReadCount(g_ahSemRWs[2]) == 1);
1073
1074 RTTEST_CHECK_RC(g_hTest, rc = RTSemRWRequestWrite(g_ahSemRWs[3], RT_INDEFINITE_WAIT), VINF_SUCCESS);
1075 if (RT_SUCCESS(rc))
1076 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(g_ahSemRWs[3]), VINF_SUCCESS);
1077 RTTEST_CHECK(g_hTest, RTSemRWGetWriteRecursion(g_ahSemRWs[3]) == 1);
1078
1079 /* Enable strict release order for class 2 and 3, then check that violations
1080 are caught - including recursion. */
1081 RTTEST_CHECK_RC(g_hTest, RTLockValidatorClassEnforceStrictReleaseOrder(g_ahClasses[2], true), VINF_SUCCESS);
1082 RTTEST_CHECK_RC(g_hTest, RTLockValidatorClassEnforceStrictReleaseOrder(g_ahClasses[3], true), VINF_SUCCESS);
1083
1084 RTTEST_CHECK_RC(g_hTest, RTSemRWRequestRead( g_ahSemRWs[2], RT_INDEFINITE_WAIT), VINF_SUCCESS); /* start recursion */
1085 RTTEST_CHECK( g_hTest, RTSemRWGetReadCount(g_ahSemRWs[2]) == 2);
1086 RTTEST_CHECK_RC(g_hTest, RTSemRWRequestWrite(g_ahSemRWs[3], RT_INDEFINITE_WAIT), VINF_SUCCESS);
1087 RTTEST_CHECK( g_hTest, RTSemRWGetWriteRecursion(g_ahSemRWs[3]) == 2);
1088 RTTEST_CHECK_RC(g_hTest, RTSemRWRequestRead( g_ahSemRWs[4], RT_INDEFINITE_WAIT), VINF_SUCCESS); /* (mixed) */
1089
1090 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseRead( g_ahSemRWs[2]), VERR_SEM_LV_WRONG_RELEASE_ORDER);
1091 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(g_ahSemRWs[3]), VERR_SEM_LV_WRONG_RELEASE_ORDER);
1092 RTTEST_CHECK( g_hTest, RTSemRWGetWriteRecursion(g_ahSemRWs[3]) == 2);
1093 RTTEST_CHECK( g_hTest, RTSemRWGetReadCount(g_ahSemRWs[2]) == 2);
1094 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseRead( g_ahSemRWs[4]), VINF_SUCCESS);
1095 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(g_ahSemRWs[3]), VINF_SUCCESS);
1096 RTTEST_CHECK( g_hTest, RTSemRWGetWriteRecursion(g_ahSemRWs[3]) == 1);
1097 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseRead( g_ahSemRWs[2]), VINF_SUCCESS); /* end recursion */
1098 RTTEST_CHECK( g_hTest, RTSemRWGetReadCount(g_ahSemRWs[2]) == 1);
1099
1100 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseRead( g_ahSemRWs[2]), VERR_SEM_LV_WRONG_RELEASE_ORDER);
1101 RTTEST_CHECK(g_hTest, RTSemRWGetReadCount(g_ahSemRWs[2]) == 1);
1102 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(g_ahSemRWs[3]), VERR_SEM_LV_WRONG_RELEASE_ORDER);
1103 RTTEST_CHECK(g_hTest, RTSemRWGetWriteRecursion(g_ahSemRWs[3]) == 1);
1104 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(g_ahSemRWs[5]), VINF_SUCCESS);
1105 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(g_ahSemRWs[4]), VINF_SUCCESS);
1106 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(g_ahSemRWs[3]), VINF_SUCCESS);
1107 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseRead( g_ahSemRWs[2]), VINF_SUCCESS);
1108
1109 /* clean up */
1110 for (int i = 6 - 1; i >= 0; i--)
1111 {
1112 uint32_t c;
1113 RTTEST_CHECK_MSG(g_hTest, (c = RTLockValidatorClassRelease(g_ahClasses[i])) == 2, (g_hTest, "c=%u i=%u\n", c, i));
1114 g_ahClasses[i] = NIL_RTLOCKVALCLASS;
1115 RTTEST_CHECK_RC_RETV(g_hTest, RTSemRWDestroy(g_ahSemRWs[i]), VINF_SUCCESS);
1116 g_ahSemRWs[i] = NIL_RTSEMRW;
1117 }
1118}
1119
1120
1121static void testLo4(void)
1122{
1123 RTTestSub(g_hTest, "locking order, mutex");
1124
1125 /* Initialize the critsection with all different classes */
1126 for (unsigned i = 0; i < 4; i++)
1127 {
1128 RTTEST_CHECK_RC_RETV(g_hTest, RTLockValidatorClassCreate(&g_ahClasses[i], true /*fAutodidact*/, RT_SRC_POS, "testLo4-%u", i), VINF_SUCCESS);
1129 RTTEST_CHECK_RC_RETV(g_hTest, RTSemMutexCreateEx(&g_ahSemMtxes[i], 0, g_ahClasses[i], RTLOCKVAL_SUB_CLASS_NONE, "RTSemMutexLo4-%u", i), VINF_SUCCESS);
1130 RTTEST_CHECK_RETV(g_hTest, RTLockValidatorClassRetain(g_ahClasses[i]) == 3);
1131 RTTEST_CHECK_RETV(g_hTest, RTLockValidatorClassRelease(g_ahClasses[i]) == 2);
1132 }
1133
1134 /* Check the sub-class API.*/
1135 RTTEST_CHECK(g_hTest, RTSemMutexSetSubClass(g_ahSemMtxes[0], RTLOCKVAL_SUB_CLASS_ANY) == RTLOCKVAL_SUB_CLASS_NONE);
1136 RTTEST_CHECK(g_hTest, RTSemMutexSetSubClass(g_ahSemMtxes[0], RTLOCKVAL_SUB_CLASS_NONE) == RTLOCKVAL_SUB_CLASS_ANY);
1137
1138 /* Enter the first 4 critsects in ascending order and thereby defining
1139 this as a valid lock order. */
1140 RTTEST_CHECK_RC(g_hTest, RTSemMutexRequest(g_ahSemMtxes[0], RT_INDEFINITE_WAIT), VINF_SUCCESS);
1141 RTTEST_CHECK_RC(g_hTest, RTSemMutexRequest(g_ahSemMtxes[1], RT_INDEFINITE_WAIT), VINF_SUCCESS);
1142 RTTEST_CHECK_RC(g_hTest, RTSemMutexRequest(g_ahSemMtxes[2], RT_INDEFINITE_WAIT), VINF_SUCCESS);
1143 RTTEST_CHECK_RC(g_hTest, RTSemMutexRequest(g_ahSemMtxes[3], RT_INDEFINITE_WAIT), VINF_SUCCESS);
1144
1145 /* Now, leave and re-enter the critsects in a way that should break the
1146 order and check that we get the appropriate response. */
1147 int rc;
1148 RTTEST_CHECK_RC(g_hTest, RTSemMutexRelease(g_ahSemMtxes[0]), VINF_SUCCESS);
1149 RTTEST_CHECK_RC(g_hTest, rc = RTSemMutexRequest(g_ahSemMtxes[0], RT_INDEFINITE_WAIT), VERR_SEM_LV_WRONG_ORDER);
1150 if (RT_SUCCESS(rc))
1151 RTTEST_CHECK_RC(g_hTest, RTSemMutexRelease(g_ahSemMtxes[0]), VINF_SUCCESS);
1152
1153 /* Check that recursion isn't subject to order checks. */
1154 RTTEST_CHECK_RC(g_hTest, rc = RTSemMutexRequest(g_ahSemMtxes[1], RT_INDEFINITE_WAIT), VINF_SUCCESS);
1155 if (RT_SUCCESS(rc))
1156 RTTEST_CHECK_RC(g_hTest, RTSemMutexRelease(g_ahSemMtxes[1]), VINF_SUCCESS);
1157
1158 /* Enable strict release order for class 2 and check that violations
1159 are caught - including recursion. */
1160 RTTEST_CHECK_RC(g_hTest, RTLockValidatorClassEnforceStrictReleaseOrder(g_ahClasses[2], true), VINF_SUCCESS);
1161
1162 RTTEST_CHECK_RC(g_hTest, RTSemMutexRequest(g_ahSemMtxes[2], RT_INDEFINITE_WAIT), VINF_SUCCESS); /* start recursion */
1163 RTTEST_CHECK_RC(g_hTest, RTSemMutexRequest(g_ahSemMtxes[3], RT_INDEFINITE_WAIT), VINF_SUCCESS);
1164 RTTEST_CHECK_RC(g_hTest, RTSemMutexRelease(g_ahSemMtxes[2]), VERR_SEM_LV_WRONG_RELEASE_ORDER);
1165 RTTEST_CHECK_RC(g_hTest, RTSemMutexRelease(g_ahSemMtxes[3]), VINF_SUCCESS);
1166 RTTEST_CHECK_RC(g_hTest, RTSemMutexRelease(g_ahSemMtxes[2]), VINF_SUCCESS); /* end recursion */
1167
1168 RTTEST_CHECK_RC(g_hTest, RTSemMutexRelease(g_ahSemMtxes[2]), VERR_SEM_LV_WRONG_RELEASE_ORDER);
1169 RTTEST_CHECK_RC(g_hTest, RTSemMutexRelease(g_ahSemMtxes[1]), VINF_SUCCESS);
1170 RTTEST_CHECK_RC(g_hTest, RTSemMutexRelease(g_ahSemMtxes[3]), VINF_SUCCESS);
1171 RTTEST_CHECK_RC(g_hTest, RTSemMutexRelease(g_ahSemMtxes[2]), VINF_SUCCESS);
1172
1173 /* clean up */
1174 for (int i = 4 - 1; i >= 0; i--)
1175 {
1176 RTTEST_CHECK(g_hTest, RTLockValidatorClassRelease(g_ahClasses[i]) == 1);
1177 g_ahClasses[i] = NIL_RTLOCKVALCLASS;
1178 RTTEST_CHECK_RC_RETV(g_hTest, RTSemMutexDestroy(g_ahSemMtxes[i]), VINF_SUCCESS);
1179 }
1180}
1181
1182
1183
1184
1185static const char *testCheckIfLockValidationIsCompiledIn(void)
1186{
1187 RTCRITSECT CritSect;
1188 RTTEST_CHECK_RC_OK_RET(g_hTest, RTCritSectInit(&CritSect), "");
1189 RTTEST_CHECK_RC_OK_RET(g_hTest, RTCritSectEnter(&CritSect), "");
1190 bool fRet = CritSect.pValidatorRec
1191 && CritSect.pValidatorRec->hThread == RTThreadSelf();
1192 RTTEST_CHECK_RC_OK_RET(g_hTest, RTCritSectLeave(&CritSect), "");
1193 RTTEST_CHECK_RC_OK_RET(g_hTest, RTCritSectDelete(&CritSect), "");
1194 if (!fRet)
1195 return "Lock validation is not enabled for critical sections";
1196
1197 /* deadlock detection for RTSemRW */
1198 RTSEMRW hSemRW;
1199 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemRWCreateEx(&hSemRW, 0 /*fFlags*/, NIL_RTLOCKVALCLASS,
1200 RTLOCKVAL_SUB_CLASS_NONE, "RTSemRW-1"), NULL);
1201 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemRWRequestRead(hSemRW, 50), "");
1202 int rc = RTSemRWRequestWrite(hSemRW, 1);
1203 RTTEST_CHECK_RET(g_hTest, RT_FAILURE_NP(rc), "");
1204 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemRWReleaseRead(hSemRW), "");
1205 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemRWDestroy(hSemRW), "");
1206 if (rc != VERR_SEM_LV_ILLEGAL_UPGRADE)
1207 return "Deadlock detection is not enabled for the read/write semaphores";
1208
1209 /* lock order for RTSemRW */
1210 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemRWCreateEx(&hSemRW, 0 /*fFlags*/,
1211 RTLockValidatorClassCreateUnique(RT_SRC_POS, NULL),
1212 RTLOCKVAL_SUB_CLASS_NONE, "RTSemRW-2"), "");
1213 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemRWRequestRead(hSemRW, 50), "");
1214 rc = RTSemRWRequestWrite(hSemRW, 1);
1215 RTTEST_CHECK_RET(g_hTest, RT_FAILURE_NP(rc), "");
1216 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemRWReleaseRead(hSemRW), "");
1217 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemRWDestroy(hSemRW), "");
1218 if (rc != VERR_SEM_LV_WRONG_ORDER)
1219 {
1220 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "%Rrc\n", rc);
1221 return "Lock order validation is not enabled for the read/write semaphores";
1222 }
1223
1224 /* lock order for RTSemMutex */
1225 RTSEMMUTEX hSemMtx1;
1226 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemMutexCreateEx(&hSemMtx1, 0 /*fFlags*/,
1227 RTLockValidatorClassCreateUnique(RT_SRC_POS, NULL),
1228 RTLOCKVAL_SUB_CLASS_NONE, "RTSemMtx-1"), "");
1229 RTSEMMUTEX hSemMtx2;
1230 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemMutexCreateEx(&hSemMtx2, 0 /*fFlags*/,
1231 RTLockValidatorClassCreateUnique(RT_SRC_POS, NULL),
1232 RTLOCKVAL_SUB_CLASS_NONE, "RTSemMtx-2"), "");
1233 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemMutexRequest(hSemMtx1, 50), "");
1234 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemMutexRequest(hSemMtx2, 50), "");
1235 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemMutexRelease(hSemMtx2), "");
1236 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemMutexRelease(hSemMtx1), "");
1237
1238 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemMutexRequest(hSemMtx2, 50), "");
1239 rc = RTSemMutexRequest(hSemMtx1, 50);
1240 RTTEST_CHECK_RET(g_hTest, RT_FAILURE_NP(rc), "");
1241 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemMutexRelease(hSemMtx2), "");
1242 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemMutexDestroy(hSemMtx2), ""); hSemMtx2 = NIL_RTSEMMUTEX;
1243 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemMutexDestroy(hSemMtx1), ""); hSemMtx1 = NIL_RTSEMMUTEX;
1244 if (rc != VERR_SEM_LV_WRONG_ORDER)
1245 return "Lock order validation is not enabled for the mutex semaphores";
1246
1247 /* signaller checks on event sems. */
1248 RTSEMEVENT hSemEvt;
1249 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemEventCreate(&hSemEvt), "");
1250 RTSemEventSetSignaller(hSemEvt, RTThreadSelf());
1251 RTSemEventSetSignaller(hSemEvt, NIL_RTTHREAD);
1252 rc = RTSemEventSignal(hSemEvt);
1253 RTTEST_CHECK_RET(g_hTest, RT_FAILURE_NP(rc), "");
1254 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemEventDestroy(hSemEvt), "");
1255 if (rc != VERR_SEM_LV_NOT_SIGNALLER)
1256 return "Signalling checks are not enabled for the event semaphores";
1257
1258 /* signaller checks on multiple release event sems. */
1259 RTSEMEVENTMULTI hSemEvtMulti;
1260 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemEventMultiCreate(&hSemEvtMulti), "");
1261 RTSemEventMultiSetSignaller(hSemEvtMulti, RTThreadSelf());
1262 RTSemEventMultiSetSignaller(hSemEvtMulti, NIL_RTTHREAD);
1263 rc = RTSemEventMultiSignal(hSemEvtMulti);
1264 RTTEST_CHECK_RET(g_hTest, RT_FAILURE_NP(rc), "");
1265 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemEventMultiDestroy(hSemEvtMulti), "");
1266 if (rc != VERR_SEM_LV_NOT_SIGNALLER)
1267 return "Signalling checks are not enabled for the multiple release event semaphores";
1268
1269 /* we're good */
1270 return NULL;
1271}
1272
1273
1274int main()
1275{
1276 /*
1277 * Init.
1278 */
1279 int rc = RTTestInitAndCreate("tstRTLockValidator", &g_hTest);
1280 if (rc)
1281 return rc;
1282 RTTestBanner(g_hTest);
1283
1284 RTLockValidatorSetEnabled(true);
1285 RTLockValidatorSetMayPanic(false);
1286 RTLockValidatorSetQuiet(true);
1287 const char *pszWhyDisabled = testCheckIfLockValidationIsCompiledIn();
1288 if (pszWhyDisabled)
1289 return RTTestErrorCount(g_hTest) > 0
1290 ? RTTestSummaryAndDestroy(g_hTest)
1291 : RTTestSkipAndDestroy(g_hTest, pszWhyDisabled);
1292 RTLockValidatorSetQuiet(false);
1293
1294 bool fTestDd = true;
1295 bool fTestLo = true;
1296
1297 /*
1298 * Some initial tests with verbose output (all single pass).
1299 */
1300 if (fTestDd)
1301 {
1302 testDd1(3, 0);
1303 testDd2(1, 0);
1304 testDd2(3, 0);
1305 testDd5(3, 0);
1306 testDd6(3, 0);
1307 testDd7(3, 0);
1308 }
1309 if (fTestLo)
1310 {
1311 testLo1();
1312 testLo2();
1313 testLo3();
1314 testLo4();
1315 }
1316
1317
1318 /*
1319 * If successful, perform more thorough testing without noisy output.
1320 */
1321 if (RTTestErrorCount(g_hTest) == 0)
1322 {
1323 RTLockValidatorSetQuiet(true);
1324
1325 if (fTestDd)
1326 {
1327 testDd1( 2, SECS_SIMPLE_TEST);
1328 testDd1( 3, SECS_SIMPLE_TEST);
1329 testDd1( 7, SECS_SIMPLE_TEST);
1330 testDd1(10, SECS_SIMPLE_TEST);
1331 testDd1(15, SECS_SIMPLE_TEST);
1332 testDd1(30, SECS_SIMPLE_TEST);
1333
1334 testDd2( 1, SECS_SIMPLE_TEST);
1335 testDd2( 2, SECS_SIMPLE_TEST);
1336 testDd2( 3, SECS_SIMPLE_TEST);
1337 testDd2( 7, SECS_SIMPLE_TEST);
1338 testDd2(10, SECS_SIMPLE_TEST);
1339 testDd2(15, SECS_SIMPLE_TEST);
1340 testDd2(30, SECS_SIMPLE_TEST);
1341
1342 testDd3( 2, SECS_SIMPLE_TEST);
1343 testDd3(10, SECS_SIMPLE_TEST);
1344
1345 testDd4( 2, SECS_RACE_TEST);
1346 testDd4( 6, SECS_RACE_TEST);
1347 testDd4(10, SECS_RACE_TEST);
1348 testDd4(30, SECS_RACE_TEST);
1349
1350 testDd5( 2, SECS_RACE_TEST);
1351 testDd5( 3, SECS_RACE_TEST);
1352 testDd5( 7, SECS_RACE_TEST);
1353 testDd5(10, SECS_RACE_TEST);
1354 testDd5(15, SECS_RACE_TEST);
1355 testDd5(30, SECS_RACE_TEST);
1356
1357 testDd6( 2, SECS_SIMPLE_TEST);
1358 testDd6( 3, SECS_SIMPLE_TEST);
1359 testDd6( 7, SECS_SIMPLE_TEST);
1360 testDd6(10, SECS_SIMPLE_TEST);
1361 testDd6(15, SECS_SIMPLE_TEST);
1362 testDd6(30, SECS_SIMPLE_TEST);
1363
1364 testDd7( 2, SECS_SIMPLE_TEST);
1365 testDd7( 3, SECS_SIMPLE_TEST);
1366 testDd7( 7, SECS_SIMPLE_TEST);
1367 testDd7(10, SECS_SIMPLE_TEST);
1368 testDd7(15, SECS_SIMPLE_TEST);
1369 testDd7(30, SECS_SIMPLE_TEST);
1370 }
1371 }
1372
1373 return RTTestSummaryAndDestroy(g_hTest);
1374}
1375
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