VirtualBox

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

Last change on this file since 25690 was 25690, checked in by vboxsync, 15 years ago

iprt/lockvalidator: Record recursion on the lock stack.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 33.2 KB
Line 
1/* $Id: tstRTLockValidator.cpp 25690 2010-01-08 13:20:15Z vboxsync $ */
2/** @file
3 * IPRT Testcase - RTLockValidator.
4 */
5
6/*
7 * Copyright (C) 2006-2009 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31
32/*******************************************************************************
33* Header Files *
34*******************************************************************************/
35#include <iprt/lockvalidator.h>
36
37#include <iprt/asm.h> /* for return addresses */
38#include <iprt/critsect.h>
39#include <iprt/err.h>
40#include <iprt/semaphore.h>
41#include <iprt/test.h>
42#include <iprt/thread.h>
43#include <iprt/time.h>
44
45
46/*******************************************************************************
47* Defined Constants And Macros *
48*******************************************************************************/
49#define SECS_SIMPLE_TEST 1
50#define SECS_RACE_TEST 3
51#define TEST_SMALL_TIMEOUT ( 10*1000)
52#define TEST_LARGE_TIMEOUT ( 60*1000)
53#define TEST_DEBUG_TIMEOUT (3600*1000)
54
55
56/*******************************************************************************
57* Global Variables *
58*******************************************************************************/
59/** The testcase handle. */
60static RTTEST g_hTest;
61/** Flip this in the debugger to get some peace to single step wild code. */
62bool volatile g_fDoNotSpin = false;
63
64/** Set when the main thread wishes to terminate the test. */
65bool volatile g_fShutdown = false;
66/** The number of threads. */
67static uint32_t g_cThreads;
68static uint32_t g_iDeadlockThread;
69static RTTHREAD g_ahThreads[32];
70static RTCRITSECT g_aCritSects[32];
71static RTSEMRW g_ahSemRWs[32];
72static RTSEMMUTEX g_ahSemMtxes[32];
73static RTSEMEVENT g_hSemEvt;
74static RTSEMEVENTMULTI g_hSemEvtMulti;
75
76/** Multiple release event semaphore that is signalled by the main thread after
77 * it has started all the threads. */
78static RTSEMEVENTMULTI g_hThreadsStartedEvt;
79
80/** The number of threads that have called testThreadBlocking */
81static uint32_t volatile g_cThreadsBlocking;
82/** Multiple release event semaphore that is signalled by the last thread to
83 * call testThreadBlocking. testWaitForAllOtherThreadsToSleep waits on this. */
84static RTSEMEVENTMULTI g_hThreadsBlockingEvt;
85
86/** When to stop testing. */
87static uint64_t g_NanoTSStop;
88/** The number of deadlocks. */
89static uint32_t volatile g_cDeadlocks;
90/** The number of loops. */
91static uint32_t volatile g_cLoops;
92
93
94/**
95 * Spin until the callback stops returning VERR_TRY_AGAIN.
96 *
97 * @returns Callback result. VERR_TIMEOUT if too much time elapses.
98 * @param pfnCallback Callback for checking the state.
99 * @param pvWhat Callback parameter.
100 */
101static int testWaitForSomethingToBeOwned(int (*pfnCallback)(void *), void *pvWhat)
102{
103 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
104 RTTEST_CHECK_RC_OK(g_hTest, RTSemEventMultiWait(g_hThreadsStartedEvt, TEST_SMALL_TIMEOUT));
105
106 uint64_t u64StartMS = RTTimeMilliTS();
107 for (unsigned iLoop = 0; ; iLoop++)
108 {
109 RTTEST_CHECK_RET(g_hTest, !g_fShutdown, VERR_INTERNAL_ERROR);
110
111 int rc = pfnCallback(pvWhat);
112 if (rc != VERR_TRY_AGAIN/* && !g_fDoNotSpin*/)
113 {
114 RTTEST_CHECK_RC_OK(g_hTest, rc);
115 return rc;
116 }
117
118 uint64_t cMsElapsed = RTTimeMilliTS() - u64StartMS;
119 if (!g_fDoNotSpin)
120 RTTEST_CHECK_RET(g_hTest, cMsElapsed <= TEST_SMALL_TIMEOUT, VERR_TIMEOUT);
121
122 RTTEST_CHECK_RET(g_hTest, !g_fShutdown, VERR_INTERNAL_ERROR);
123 RTThreadSleep(/*g_fDoNotSpin ? TEST_DEBUG_TIMEOUT :*/ iLoop > 256 ? 1 : 0);
124 }
125}
126
127
128static int testCheckIfCritSectIsOwned(void *pvWhat)
129{
130 PRTCRITSECT pCritSect = (PRTCRITSECT)pvWhat;
131 if (!RTCritSectIsInitialized(pCritSect))
132 return VERR_SEM_DESTROYED;
133 if (RTCritSectIsOwned(pCritSect))
134 return VINF_SUCCESS;
135 return VERR_TRY_AGAIN;
136}
137
138
139static int testWaitForCritSectToBeOwned(PRTCRITSECT pCritSect)
140{
141 return testWaitForSomethingToBeOwned(testCheckIfCritSectIsOwned, pCritSect);
142}
143
144
145static int testCheckIfSemRWIsOwned(void *pvWhat)
146{
147 RTSEMRW hSemRW = (RTSEMRW)pvWhat;
148 if (RTSemRWGetWriteRecursion(hSemRW) > 0)
149 return VINF_SUCCESS;
150 if (RTSemRWGetReadCount(hSemRW) > 0)
151 return VINF_SUCCESS;
152 return VERR_TRY_AGAIN;
153}
154
155static int testWaitForSemRWToBeOwned(RTSEMRW hSemRW)
156{
157 return testWaitForSomethingToBeOwned(testCheckIfSemRWIsOwned, hSemRW);
158}
159
160
161static int testCheckIfSemMutexIsOwned(void *pvWhat)
162{
163 RTSEMMUTEX hSemRW = (RTSEMMUTEX)pvWhat;
164 if (RTSemMutexIsOwned(hSemRW))
165 return VINF_SUCCESS;
166 return VERR_TRY_AGAIN;
167}
168
169static int testWaitForSemMutexToBeOwned(RTSEMMUTEX hSemMutex)
170{
171 return testWaitForSomethingToBeOwned(testCheckIfSemMutexIsOwned, hSemMutex);
172}
173
174
175/**
176 * For reducing spin in testWaitForAllOtherThreadsToSleep.
177 */
178static void testThreadBlocking(void)
179{
180 if (ASMAtomicIncU32(&g_cThreadsBlocking) == g_cThreads)
181 RTTEST_CHECK_RC_OK(g_hTest, RTSemEventMultiSignal(g_hThreadsBlockingEvt));
182}
183
184
185/**
186 * Waits for all the other threads to enter sleeping states.
187 *
188 * @returns VINF_SUCCESS on success, VERR_INTERNAL_ERROR on failure.
189 * @param enmDesiredState The desired thread sleep state.
190 * @param cWaitOn The distance to the lock they'll be waiting on,
191 * the lock type is derived from the desired state.
192 * UINT32_MAX means no special lock.
193 */
194static int testWaitForAllOtherThreadsToSleep(RTTHREADSTATE enmDesiredState, uint32_t cWaitOn)
195{
196 testThreadBlocking();
197 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
198 RTTEST_CHECK_RC_OK(g_hTest, RTSemEventMultiWait(g_hThreadsBlockingEvt, TEST_SMALL_TIMEOUT));
199
200 RTTHREAD hThreadSelf = RTThreadSelf();
201 for (uint32_t iOuterLoop = 0; ; iOuterLoop++)
202 {
203 uint32_t cMissing = 0;
204 uint32_t cWaitedOn = 0;
205 for (uint32_t i = 0; i < g_cThreads; i++)
206 {
207 RTTHREAD hThread = g_ahThreads[i];
208 if (hThread == NIL_RTTHREAD)
209 cMissing++;
210 else if (hThread != hThreadSelf)
211 {
212 /*
213 * Figure out which lock to wait for.
214 */
215 void *pvLock = NULL;
216 if (cWaitOn != UINT32_MAX)
217 {
218 uint32_t j = (i + cWaitOn) % g_cThreads;
219 switch (enmDesiredState)
220 {
221 case RTTHREADSTATE_CRITSECT: pvLock = &g_aCritSects[j]; break;
222 case RTTHREADSTATE_RW_WRITE:
223 case RTTHREADSTATE_RW_READ: pvLock = g_ahSemRWs[j]; break;
224 case RTTHREADSTATE_MUTEX: pvLock = g_ahSemMtxes[j]; break;
225 default: break;
226 }
227 }
228
229 /*
230 * Wait for this thread.
231 */
232 for (unsigned iLoop = 0; ; iLoop++)
233 {
234 RTTHREADSTATE enmState = RTThreadGetReallySleeping(hThread);
235 if (RTTHREAD_IS_SLEEPING(enmState))
236 {
237 if ( enmState == enmDesiredState
238 && ( !pvLock
239 || ( pvLock == RTLockValidatorQueryBlocking(hThread)
240 && !RTLockValidatorIsBlockedThreadInValidator(hThread) )
241 )
242 && RTThreadGetNativeState(hThread) != RTTHREADNATIVESTATE_RUNNING
243 )
244 break;
245 }
246 else if ( enmState != RTTHREADSTATE_RUNNING
247 && enmState != RTTHREADSTATE_INITIALIZING)
248 return VERR_INTERNAL_ERROR;
249 RTTEST_CHECK_RET(g_hTest, !g_fShutdown, VERR_INTERNAL_ERROR);
250 RTThreadSleep(g_fDoNotSpin ? TEST_DEBUG_TIMEOUT : iOuterLoop + iLoop > 256 ? 1 : 0);
251 RTTEST_CHECK_RET(g_hTest, !g_fShutdown, VERR_INTERNAL_ERROR);
252 cWaitedOn++;
253 }
254 }
255 RTTEST_CHECK_RET(g_hTest, !g_fShutdown, VERR_INTERNAL_ERROR);
256 }
257
258 if (!cMissing && !cWaitedOn)
259 break;
260 RTTEST_CHECK_RET(g_hTest, !g_fShutdown, VERR_INTERNAL_ERROR);
261 RTThreadSleep(g_fDoNotSpin ? TEST_DEBUG_TIMEOUT : iOuterLoop > 256 ? 1 : 0);
262 RTTEST_CHECK_RET(g_hTest, !g_fShutdown, VERR_INTERNAL_ERROR);
263 }
264
265 RTThreadSleep(0); /* fudge factor */
266 RTTEST_CHECK_RET(g_hTest, !g_fShutdown, VERR_INTERNAL_ERROR);
267 return VINF_SUCCESS;
268}
269
270
271/**
272 * Worker that starts the threads.
273 *
274 * @returns Same as RTThreadCreate.
275 * @param cThreads The number of threads to start.
276 * @param pfnThread Thread function.
277 */
278static int testStartThreads(uint32_t cThreads, PFNRTTHREAD pfnThread)
279{
280 RTSemEventMultiReset(g_hThreadsStartedEvt);
281
282 for (uint32_t i = 0; i < RT_ELEMENTS(g_ahThreads); i++)
283 g_ahThreads[i] = NIL_RTTHREAD;
284
285 int rc = VINF_SUCCESS;
286 for (uint32_t i = 0; i < cThreads; i++)
287 {
288 rc = RTThreadCreateF(&g_ahThreads[i], pfnThread, (void *)(uintptr_t)i, 0,
289 RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "thread-%02u", i);
290 RTTEST_CHECK_RC_OK(g_hTest, rc);
291 if (RT_FAILURE(rc))
292 break;
293 }
294
295 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemEventMultiSignal(g_hThreadsStartedEvt), rcCheck);
296 return rc;
297}
298
299
300/**
301 * Worker that waits for the threads to complete.
302 *
303 * @param cMillies How long to wait for each.
304 * @param fStopOnError Whether to stop on error and heed the thread
305 * return status.
306 */
307static void testWaitForThreads(uint32_t cMillies, bool fStopOnError)
308{
309 uint32_t i = RT_ELEMENTS(g_ahThreads);
310 while (i-- > 0)
311 if (g_ahThreads[i] != NIL_RTTHREAD)
312 {
313 int rcThread;
314 int rc2;
315 RTTEST_CHECK_RC_OK(g_hTest, rc2 = RTThreadWait(g_ahThreads[i], cMillies, &rcThread));
316 if (RT_SUCCESS(rc2))
317 g_ahThreads[i] = NIL_RTTHREAD;
318 if (fStopOnError && (RT_FAILURE(rc2) || RT_FAILURE(rcThread)))
319 return;
320 }
321}
322
323
324static void testIt(uint32_t cThreads, uint32_t cSecs, bool fLoops, PFNRTTHREAD pfnThread, const char *pszName)
325{
326 /*
327 * Init test.
328 */
329 if (cSecs > 0)
330 RTTestSubF(g_hTest, "%s, %u threads, %u secs", pszName, cThreads, cSecs);
331 else
332 RTTestSubF(g_hTest, "%s, %u threads, single pass", pszName, cThreads);
333
334 RTTEST_CHECK_RETV(g_hTest, RT_ELEMENTS(g_ahThreads) >= cThreads);
335 RTTEST_CHECK_RETV(g_hTest, RT_ELEMENTS(g_aCritSects) >= cThreads);
336
337 g_cThreads = cThreads;
338 g_fShutdown = false;
339
340 for (uint32_t i = 0; i < cThreads; i++)
341 {
342 RTTEST_CHECK_RC_RETV(g_hTest, RTCritSectInit(&g_aCritSects[i]), VINF_SUCCESS);
343 RTTEST_CHECK_RC_RETV(g_hTest, RTSemRWCreate(&g_ahSemRWs[i]), VINF_SUCCESS);
344 RTTEST_CHECK_RC_RETV(g_hTest, RTSemMutexCreate(&g_ahSemMtxes[i]), 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) test1Thread(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 test1(uint32_t cThreads, uint32_t cSecs)
455{
456 testIt(cThreads, cSecs, false, test1Thread, "critsect");
457}
458
459
460static DECLCALLBACK(int) test2Thread(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 test2(uint32_t cThreads, uint32_t cSecs)
511{
512 testIt(cThreads, cSecs, false, test2Thread, "read-write");
513}
514
515
516static DECLCALLBACK(int) test3Thread(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 test3(uint32_t cThreads, uint32_t cSecs)
558{
559 testIt(cThreads, cSecs, true, test3Thread, "read-write race");
560}
561
562
563static DECLCALLBACK(int) test4Thread(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 test4(uint32_t cThreads, uint32_t cSecs)
614{
615 testIt(cThreads, cSecs, true, test4Thread, "read-write race v2");
616}
617
618
619static DECLCALLBACK(int) test5Thread(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 test5(uint32_t cThreads, uint32_t cSecs)
654{
655 testIt(cThreads, cSecs, false, test5Thread, "mutex");
656}
657
658
659static DECLCALLBACK(int) test6Thread(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 test6(uint32_t cThreads, uint32_t cSecs)
707{
708 testIt(cThreads, cSecs, false, test6Thread, "event");
709}
710
711
712static DECLCALLBACK(int) test7Thread(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 test7(uint32_t cThreads, uint32_t cSecs)
761{
762 testIt(cThreads, cSecs, false, test7Thread, "event multi");
763}
764
765
766static bool testIsLockValidationCompiledIn(void)
767{
768 RTCRITSECT CritSect;
769 RTTEST_CHECK_RC_OK_RET(g_hTest, RTCritSectInit(&CritSect), false);
770 RTTEST_CHECK_RC_OK_RET(g_hTest, RTCritSectEnter(&CritSect), false);
771 bool fRet = CritSect.pValidatorRec
772 && CritSect.pValidatorRec->hThread == RTThreadSelf();
773 RTTEST_CHECK_RC_OK_RET(g_hTest, RTCritSectLeave(&CritSect), false);
774 RTTEST_CHECK_RC_OK_RET(g_hTest, RTCritSectDelete(&CritSect), false);
775
776 RTSEMRW hSemRW;
777 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemRWCreate(&hSemRW), false);
778 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemRWRequestRead(hSemRW, 50), false);
779 int rc = RTSemRWRequestWrite(hSemRW, 1);
780 if (rc != VERR_SEM_LV_ILLEGAL_UPGRADE)
781 fRet = false;
782 RTTEST_CHECK_RET(g_hTest, RT_FAILURE_NP(rc), false);
783 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemRWReleaseRead(hSemRW), false);
784 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemRWDestroy(hSemRW), false);
785
786#if 0 /** @todo detect it on RTSemMutex... */
787 RTSEMMUTEX hSemMtx;
788 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemMutexCreate(&hSemRW), false);
789 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemMutexRequest(hSemRW, 50), false);
790 /*??*/
791 RTTEST_CHECK_RET(g_hTest, RT_FAILURE_NP(rc), false);
792 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemRWRelease(hSemRW), false);
793 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemRWDestroy(hSemRW), false);
794#endif
795
796 RTSEMEVENT hSemEvt;
797 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemEventCreate(&hSemEvt), false);
798 RTSemEventSetSignaller(hSemEvt, RTThreadSelf());
799 RTSemEventSetSignaller(hSemEvt, NIL_RTTHREAD);
800 rc = RTSemEventSignal(hSemEvt);
801 if (rc != VERR_SEM_LV_NOT_SIGNALLER)
802 fRet = false;
803 RTTEST_CHECK_RET(g_hTest, RT_FAILURE_NP(rc), false);
804 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemEventDestroy(hSemEvt), false);
805
806 RTSEMEVENTMULTI hSemEvtMulti;
807 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemEventMultiCreate(&hSemEvtMulti), false);
808 RTSemEventMultiSetSignaller(hSemEvtMulti, RTThreadSelf());
809 RTSemEventMultiSetSignaller(hSemEvtMulti, NIL_RTTHREAD);
810 rc = RTSemEventMultiSignal(hSemEvtMulti);
811 if (rc != VERR_SEM_LV_NOT_SIGNALLER)
812 fRet = false;
813 RTTEST_CHECK_RET(g_hTest, RT_FAILURE_NP(rc), false);
814 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemEventMultiDestroy(hSemEvtMulti), false);
815
816 return fRet;
817}
818
819
820int main()
821{
822 /*
823 * Init.
824 */
825 int rc = RTTestInitAndCreate("tstRTLockValidator", &g_hTest);
826 if (rc)
827 return rc;
828 RTTestBanner(g_hTest);
829
830 RTLockValidatorSetEnabled(true);
831 RTLockValidatorSetMayPanic(false);
832 RTLockValidatorSetQuiet(true);
833 if (!testIsLockValidationCompiledIn())
834 return RTTestErrorCount(g_hTest) > 0
835 ? RTTestSummaryAndDestroy(g_hTest)
836 : RTTestSkipAndDestroy(g_hTest, "deadlock detection is not compiled in");
837 RTLockValidatorSetQuiet(false);
838
839 /*
840 * Some initial tests with verbose output (all single pass).
841 */
842 test1(3, 0);
843 test2(1, 0);
844 test2(3, 0);
845 test5(3, 0);
846 test6(3, 0);
847 test7(3, 0);
848
849 /*
850 * If successful, perform more thorough testing without noisy output.
851 */
852 if (RTTestErrorCount(g_hTest) == 0)
853 {
854 RTLockValidatorSetQuiet(true);
855
856 test1( 2, SECS_SIMPLE_TEST);
857 test1( 3, SECS_SIMPLE_TEST);
858 test1( 7, SECS_SIMPLE_TEST);
859 test1(10, SECS_SIMPLE_TEST);
860 test1(15, SECS_SIMPLE_TEST);
861 test1(30, SECS_SIMPLE_TEST);
862
863 test2( 1, SECS_SIMPLE_TEST);
864 test2( 2, SECS_SIMPLE_TEST);
865 test2( 3, SECS_SIMPLE_TEST);
866 test2( 7, SECS_SIMPLE_TEST);
867 test2(10, SECS_SIMPLE_TEST);
868 test2(15, SECS_SIMPLE_TEST);
869 test2(30, SECS_SIMPLE_TEST);
870
871 test3( 2, SECS_SIMPLE_TEST);
872 test3(10, SECS_SIMPLE_TEST);
873
874 test4( 2, SECS_RACE_TEST);
875 test4( 6, SECS_RACE_TEST);
876 test4(10, SECS_RACE_TEST);
877 test4(30, SECS_RACE_TEST);
878
879 test5( 2, SECS_RACE_TEST);
880 test5( 3, SECS_RACE_TEST);
881 test5( 7, SECS_RACE_TEST);
882 test5(10, SECS_RACE_TEST);
883 test5(15, SECS_RACE_TEST);
884 test5(30, SECS_RACE_TEST);
885
886 test6( 2, SECS_SIMPLE_TEST);
887 test6( 3, SECS_SIMPLE_TEST);
888 test6( 7, SECS_SIMPLE_TEST);
889 test6(10, SECS_SIMPLE_TEST);
890 test6(15, SECS_SIMPLE_TEST);
891 test6(30, SECS_SIMPLE_TEST);
892
893 test7( 2, SECS_SIMPLE_TEST);
894 test7( 3, SECS_SIMPLE_TEST);
895 test7( 7, SECS_SIMPLE_TEST);
896 test7(10, SECS_SIMPLE_TEST);
897 test7(15, SECS_SIMPLE_TEST);
898 test7(30, SECS_SIMPLE_TEST);
899 }
900
901 return RTTestSummaryAndDestroy(g_hTest);
902}
903
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