VirtualBox

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

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

iprt,pdmcritsect: Added RTSemEvent[Set|Add|Remove]Signaller so that we can validate who is signalling an event if we like and, more importantly, detect deadlocks involving event semaphores. More attempts at dealing with the races (and bugs) in the all-other-threads-blocking detection in tstRTLockValidator.cpp, adding RTThreadGetReallySleeping and RTThreadGetNativeState in the process.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 26.2 KB
Line 
1/* $Id: tstRTLockValidator.cpp 25638 2010-01-04 16:08:04Z 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.215389.xyz. 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* Global Variables *
48*******************************************************************************/
49/** The testcase handle. */
50static RTTEST g_hTest;
51/** Flip this in the debugger to get some peace to single step wild code. */
52bool volatile g_fDoNotSpin = false;
53
54static uint32_t g_cThreads;
55static uint32_t g_iDeadlockThread;
56static RTTHREAD g_ahThreads[32];
57static RTCRITSECT g_aCritSects[32];
58static RTSEMRW g_ahSemRWs[32];
59static RTSEMMUTEX g_ahSemMtxes[32];
60static RTSEMEVENT g_hSemEvt;
61static RTSEMEVENTMULTI g_hSemEvtMulti;
62
63/** Multiple release event semaphore that is signalled by the main thread after
64 * it has started all the threads. */
65static RTSEMEVENTMULTI g_hThreadStarteEvt;
66
67
68/** When to stop testing. */
69static uint64_t g_NanoTSStop;
70/** The number of deadlocks. */
71static uint32_t volatile g_cDeadlocks;
72/** The number of loops. */
73static uint32_t volatile g_cLoops;
74
75
76/**
77 * Spin until someone else has taken ownership of the critical section.
78 *
79 * @returns true on success, false on abort.
80 * @param pCritSect The critical section.
81 */
82static bool testWaitForCritSectToBeOwned(PRTCRITSECT pCritSect)
83{
84 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
85 RTTEST_CHECK_RC_OK(g_hTest, RTSemEventMultiWait(g_hThreadStarteEvt, 10*1000));
86
87 unsigned iLoop = 0;
88 while (!RTCritSectIsOwned(pCritSect))
89 {
90 if (!RTCritSectIsInitialized(pCritSect))
91 return false;
92 RTThreadSleep(g_fDoNotSpin ? 3600*1000 : iLoop > 256 ? 1 : 0);
93 iLoop++;
94 }
95 return true;
96}
97
98
99/**
100 * Spin until someone else has taken ownership (any kind) of the read-write
101 * semaphore.
102 *
103 * @returns true on success, false on abort.
104 * @param hSemRW The read-write semaphore.
105 */
106static bool testWaitForSemRWToBeOwned(RTSEMRW hSemRW)
107{
108 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
109 RTTEST_CHECK_RC_OK(g_hTest, RTSemEventMultiWait(g_hThreadStarteEvt, 10*1000));
110
111 unsigned iLoop = 0;
112 for (;;)
113 {
114 if (RTSemRWGetWriteRecursion(hSemRW) > 0)
115 return true;
116 if (RTSemRWGetReadCount(hSemRW) > 0)
117 return true;
118 RTThreadSleep(g_fDoNotSpin ? 3600*1000 : iLoop > 256 ? 1 : 0);
119 iLoop++;
120 }
121 return true;
122}
123
124
125/**
126 * Spin until someone else has taken ownership of the mutex semaphore.
127 *
128 * @returns true on success, false on abort.
129 * @param hSemMutex The mutex sempahore.
130 */
131static bool testWaitForSemMutexToBeOwned(RTSEMMUTEX hSemMutex)
132{
133 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
134 RTTEST_CHECK_RC_OK(g_hTest, RTSemEventMultiWait(g_hThreadStarteEvt, 10*1000));
135
136 unsigned iLoop = 0;
137 while (!RTSemMutexIsOwned(hSemMutex))
138 {
139 RTThreadSleep(g_fDoNotSpin ? 3600*1000 : iLoop > 256 ? 1 : 0);
140 iLoop++;
141 }
142 return true;
143}
144
145
146/**
147 * Waits for all the other threads to enter sleeping states.
148 *
149 * @returns VINF_SUCCESS on success, VERR_INTERNAL_ERROR on failure.
150 * @param enmDesiredState The desired thread sleep state.
151 * @param cWaitOn The distance to the lock they'll be waiting on,
152 * the lock type is derived from the desired state.
153 * UINT32_MAX means no special lock.
154 */
155static int testWaitForAllOtherThreadsToSleep(RTTHREADSTATE enmDesiredState, uint32_t cWaitOn)
156{
157 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
158 RTTEST_CHECK_RC_OK(g_hTest, RTSemEventMultiWait(g_hThreadStarteEvt, 10*1000));
159
160 RTTHREAD hThreadSelf = RTThreadSelf();
161 for (uint32_t iOuterLoop = 0; ; iOuterLoop++)
162 {
163 uint32_t cMissing = 0;
164 uint32_t cWaitedOn = 0;
165 for (uint32_t i = 0; i < g_cThreads; i++)
166 {
167 RTTHREAD hThread = g_ahThreads[i];
168 if (hThread == NIL_RTTHREAD)
169 cMissing++;
170 else if (hThread != hThreadSelf)
171 {
172 /*
173 * Figure out which lock to wait for.
174 */
175 void *pvLock = NULL;
176 if (cWaitOn != UINT32_MAX)
177 {
178 uint32_t j = (i + cWaitOn) % g_cThreads;
179 switch (enmDesiredState)
180 {
181 case RTTHREADSTATE_CRITSECT: pvLock = &g_aCritSects[j]; break;
182 case RTTHREADSTATE_RW_WRITE:
183 case RTTHREADSTATE_RW_READ: pvLock = g_ahSemRWs[j]; break;
184 case RTTHREADSTATE_MUTEX: pvLock = g_ahSemMtxes[j]; break;
185 default: break;
186 }
187 }
188
189 /*
190 * Wait for this thread.
191 */
192 for (unsigned iLoop = 0; ; iLoop++)
193 {
194 RTTHREADSTATE enmState = RTThreadGetReallySleeping(hThread);
195 if (RTTHREAD_IS_SLEEPING(enmState))
196 {
197 if ( enmState == enmDesiredState
198 && ( !pvLock
199 || ( pvLock == RTLockValidatorQueryBlocking(hThread)
200 && !RTLockValidatorIsBlockedThreadInValidator(hThread) )
201 )
202 && RTThreadGetNativeState(hThread) != RTTHREADNATIVESTATE_RUNNING
203 )
204 break;
205 }
206 else if ( enmState != RTTHREADSTATE_RUNNING
207 && enmState != RTTHREADSTATE_INITIALIZING)
208 return VERR_INTERNAL_ERROR;
209 RTThreadSleep(g_fDoNotSpin ? 3600*1000 : iOuterLoop + iLoop > 256 ? 1 : 0);
210 cWaitedOn++;
211 }
212 }
213 }
214
215 if (!cMissing && !cWaitedOn)
216 break;
217 RTThreadSleep(g_fDoNotSpin ? 3600*1000 : iOuterLoop > 256 ? 1 : 0);
218 }
219
220 RTThreadSleep(0); /* fudge factor */
221 return VINF_SUCCESS;
222}
223
224
225/**
226 * Worker that starts the threads.
227 *
228 * @returns Same as RTThreadCreate.
229 * @param cThreads The number of threads to start.
230 * @param pfnThread Thread function.
231 */
232static int testStartThreads(uint32_t cThreads, PFNRTTHREAD pfnThread)
233{
234 RTSemEventMultiReset(g_hThreadStarteEvt);
235
236 for (uint32_t i = 0; i < RT_ELEMENTS(g_ahThreads); i++)
237 g_ahThreads[i] = NIL_RTTHREAD;
238
239 int rc = VINF_SUCCESS;
240 for (uint32_t i = 0; i < cThreads; i++)
241 {
242 rc = RTThreadCreateF(&g_ahThreads[i], pfnThread, (void *)(uintptr_t)i, 0,
243 RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "thread-%02u", i);
244 RTTEST_CHECK_RC_OK(g_hTest, rc);
245 if (RT_FAILURE(rc))
246 break;
247 }
248
249 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemEventMultiSignal(g_hThreadStarteEvt), rcCheck);
250 return rc;
251}
252
253
254/**
255 * Worker that waits for the threads to complete.
256 *
257 * @param cMillies How long to wait for each.
258 * @param fStopOnError Whether to stop on error and heed the thread
259 * return status.
260 */
261static void testWaitForThreads(uint32_t cMillies, bool fStopOnError)
262{
263 uint32_t i = RT_ELEMENTS(g_ahThreads);
264 while (i-- > 0)
265 if (g_ahThreads[i] != NIL_RTTHREAD)
266 {
267 int rcThread;
268 int rc2;
269 RTTEST_CHECK_RC_OK(g_hTest, rc2 = RTThreadWait(g_ahThreads[i], cMillies, &rcThread));
270 if (RT_SUCCESS(rc2))
271 g_ahThreads[i] = NIL_RTTHREAD;
272 if (fStopOnError && (RT_FAILURE(rc2) || RT_FAILURE(rcThread)))
273 return;
274 }
275}
276
277
278static void testIt(uint32_t cThreads, uint32_t cPasses, uint32_t cSecs, PFNRTTHREAD pfnThread, const char *pszName)
279{
280 /*
281 * Init test.
282 */
283 if (cSecs)
284 RTTestSubF(g_hTest, "%s, %u threads, %u secs", pszName, cThreads, cSecs * cPasses);
285 else
286 RTTestSubF(g_hTest, "%s, %u threads, %u passes", pszName, cThreads, cPasses);
287
288 RTTEST_CHECK_RETV(g_hTest, RT_ELEMENTS(g_ahThreads) >= cThreads);
289 RTTEST_CHECK_RETV(g_hTest, RT_ELEMENTS(g_aCritSects) >= cThreads);
290
291 g_cThreads = cThreads;
292
293 for (uint32_t i = 0; i < cThreads; i++)
294 {
295 RTTEST_CHECK_RC_RETV(g_hTest, RTCritSectInit(&g_aCritSects[i]), VINF_SUCCESS);
296 RTTEST_CHECK_RC_RETV(g_hTest, RTSemRWCreate(&g_ahSemRWs[i]), VINF_SUCCESS);
297 RTTEST_CHECK_RC_RETV(g_hTest, RTSemMutexCreate(&g_ahSemMtxes[i]), VINF_SUCCESS);
298 }
299 RTTEST_CHECK_RC_RETV(g_hTest, RTSemEventCreate(&g_hSemEvt), VINF_SUCCESS);
300 RTTEST_CHECK_RC_RETV(g_hTest, RTSemEventMultiCreate(&g_hSemEvtMulti), VINF_SUCCESS);
301 RTTEST_CHECK_RC_RETV(g_hTest, RTSemEventMultiCreate(&g_hThreadStarteEvt), VINF_SUCCESS);
302
303 /*
304 * The test loop.
305 */
306 uint32_t cLoops = 0;
307 uint32_t cDeadlocks = 0;
308 uint32_t cErrors = RTTestErrorCount(g_hTest);
309 for (uint32_t iPass = 0; iPass < cPasses && RTTestErrorCount(g_hTest) == cErrors; iPass++)
310 {
311 g_iDeadlockThread = (cThreads - 1 + iPass) % cThreads;
312 g_cLoops = 0;
313 g_cDeadlocks = 0;
314 g_NanoTSStop = cSecs ? RTTimeNanoTS() + cSecs * UINT64_C(1000000000) : 0;
315
316 int rc = testStartThreads(cThreads, pfnThread);
317 if (RT_SUCCESS(rc))
318 testWaitForThreads(30*1000 + cSecs*1000, true);
319
320 RTTEST_CHECK(g_hTest, !cSecs || g_cLoops > 0);
321 cLoops += g_cLoops;
322 RTTEST_CHECK(g_hTest, !cSecs || g_cDeadlocks > 0);
323 cDeadlocks += g_cDeadlocks;
324 }
325
326 /*
327 * Cleanup.
328 */
329 for (uint32_t i = 0; i < cThreads; i++)
330 {
331 RTTEST_CHECK_RC(g_hTest, RTCritSectDelete(&g_aCritSects[i]), VINF_SUCCESS);
332 RTTEST_CHECK_RC(g_hTest, RTSemRWDestroy(g_ahSemRWs[i]), VINF_SUCCESS);
333 RTTEST_CHECK_RC(g_hTest, RTSemMutexDestroy(g_ahSemMtxes[i]), VINF_SUCCESS);
334 }
335 RTTEST_CHECK_RC(g_hTest, RTSemEventDestroy(g_hSemEvt), VINF_SUCCESS);
336 RTTEST_CHECK_RC(g_hTest, RTSemEventMultiDestroy(g_hSemEvtMulti), VINF_SUCCESS);
337 RTTEST_CHECK_RC(g_hTest, RTSemEventMultiDestroy(g_hThreadStarteEvt), VINF_SUCCESS);
338
339 testWaitForThreads(10*1000, false);
340
341 /*
342 * Print results if applicable.
343 */
344 if (cSecs)
345 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "cLoops=%u cDeadlocks=%u (%u%%)\n",
346 cLoops, cDeadlocks, cLoops ? cDeadlocks * 100 / cLoops : 0);
347}
348
349
350static DECLCALLBACK(int) test1Thread(RTTHREAD ThreadSelf, void *pvUser)
351{
352 uintptr_t i = (uintptr_t)pvUser;
353 PRTCRITSECT pMine = &g_aCritSects[i];
354 PRTCRITSECT pNext = &g_aCritSects[(i + 1) % g_cThreads];
355
356 RTTEST_CHECK_RC_RET(g_hTest, RTCritSectEnter(pMine), VINF_SUCCESS, rcCheck);
357 if (i & 1)
358 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(pMine), VINF_SUCCESS);
359 if (testWaitForCritSectToBeOwned(pNext))
360 {
361 int rc;
362 if (i != g_iDeadlockThread)
363 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(pNext), VINF_SUCCESS);
364 else
365 {
366 RTTEST_CHECK_RC_OK(g_hTest, rc = testWaitForAllOtherThreadsToSleep(RTTHREADSTATE_CRITSECT, 1));
367 if (RT_SUCCESS(rc))
368 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(pNext), VERR_SEM_LV_DEADLOCK);
369 }
370 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
371 if (RT_SUCCESS(rc))
372 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectLeave(pNext), VINF_SUCCESS);
373 }
374 if (i & 1)
375 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(pMine), VINF_SUCCESS);
376 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(pMine), VINF_SUCCESS);
377 return VINF_SUCCESS;
378}
379
380
381static void test1(uint32_t cThreads, uint32_t cPasses)
382{
383 testIt(cThreads, cPasses, 0, test1Thread, "critsect");
384}
385
386
387static DECLCALLBACK(int) test2Thread(RTTHREAD ThreadSelf, void *pvUser)
388{
389 uintptr_t i = (uintptr_t)pvUser;
390 RTSEMRW hMine = g_ahSemRWs[i];
391 RTSEMRW hNext = g_ahSemRWs[(i + 1) % g_cThreads];
392 int rc;
393
394 if (i & 1)
395 {
396 RTTEST_CHECK_RC_RET(g_hTest, RTSemRWRequestWrite(hMine, RT_INDEFINITE_WAIT), VINF_SUCCESS, rcCheck);
397 if ((i & 3) == 3)
398 RTTEST_CHECK_RC(g_hTest, RTSemRWRequestWrite(hMine, RT_INDEFINITE_WAIT), VINF_SUCCESS);
399 }
400 else
401 RTTEST_CHECK_RC_RET(g_hTest, RTSemRWRequestRead(hMine, RT_INDEFINITE_WAIT), VINF_SUCCESS, rcCheck);
402 if (testWaitForSemRWToBeOwned(hNext))
403 {
404 if (i != g_iDeadlockThread)
405 RTTEST_CHECK_RC(g_hTest, rc = RTSemRWRequestWrite(hNext, RT_INDEFINITE_WAIT), VINF_SUCCESS);
406 else
407 {
408 RTTEST_CHECK_RC_OK(g_hTest, rc = testWaitForAllOtherThreadsToSleep(RTTHREADSTATE_RW_WRITE, 1));
409 if (RT_SUCCESS(rc))
410 {
411 if (g_cThreads > 1)
412 RTTEST_CHECK_RC(g_hTest, rc = RTSemRWRequestWrite(hNext, RT_INDEFINITE_WAIT), VERR_SEM_LV_DEADLOCK);
413 else
414 RTTEST_CHECK_RC(g_hTest, rc = RTSemRWRequestWrite(hNext, RT_INDEFINITE_WAIT), VERR_SEM_LV_ILLEGAL_UPGRADE);
415 }
416 }
417 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
418 if (RT_SUCCESS(rc))
419 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(hNext), VINF_SUCCESS);
420 }
421 if (i & 1)
422 {
423 if ((i & 3) == 3)
424 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(hMine), VINF_SUCCESS);
425 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(hMine), VINF_SUCCESS);
426 }
427 else
428 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseRead(hMine), VINF_SUCCESS);
429 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
430 return VINF_SUCCESS;
431}
432
433
434static void test2(uint32_t cThreads, uint32_t cPasses)
435{
436 testIt(cThreads, cPasses, 0, test2Thread, "read-write");
437}
438
439
440static DECLCALLBACK(int) test3Thread(RTTHREAD ThreadSelf, void *pvUser)
441{
442 uintptr_t i = (uintptr_t)pvUser;
443 RTSEMRW hMine = g_ahSemRWs[i];
444 RTSEMRW hNext = g_ahSemRWs[(i + 1) % g_cThreads];
445 int rc;
446
447 if (i & 1)
448 RTTEST_CHECK_RC_RET(g_hTest, RTSemRWRequestWrite(hMine, RT_INDEFINITE_WAIT), VINF_SUCCESS, rcCheck);
449 else
450 RTTEST_CHECK_RC_RET(g_hTest, RTSemRWRequestRead(hMine, RT_INDEFINITE_WAIT), VINF_SUCCESS, rcCheck);
451 if (testWaitForSemRWToBeOwned(hNext))
452 {
453 do
454 {
455 rc = RTSemRWRequestWrite(hNext, 60*1000);
456 if (rc != VINF_SUCCESS && rc != VERR_SEM_LV_DEADLOCK && rc != VERR_SEM_LV_ILLEGAL_UPGRADE)
457 {
458 RTTestFailed(g_hTest, "#%u: RTSemRWRequestWrite -> %Rrc\n", i, rc);
459 break;
460 }
461 if (RT_SUCCESS(rc))
462 {
463 RTTEST_CHECK_RC(g_hTest, rc = RTSemRWReleaseWrite(hNext), VINF_SUCCESS);
464 if (RT_FAILURE(rc))
465 break;
466 }
467 else
468 ASMAtomicIncU32(&g_cDeadlocks);
469 ASMAtomicIncU32(&g_cLoops);
470 } while (RTTimeNanoTS() < g_NanoTSStop);
471 }
472 if (i & 1)
473 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(hMine), VINF_SUCCESS);
474 else
475 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseRead(hMine), VINF_SUCCESS);
476 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
477 return VINF_SUCCESS;
478}
479
480
481static void test3(uint32_t cThreads, uint32_t cPasses, uint32_t cSecs)
482{
483 testIt(cThreads, cPasses, cSecs, test3Thread, "read-write race");
484}
485
486
487static DECLCALLBACK(int) test4Thread(RTTHREAD ThreadSelf, void *pvUser)
488{
489 uintptr_t i = (uintptr_t)pvUser;
490 RTSEMRW hMine = g_ahSemRWs[i];
491 RTSEMRW hNext = g_ahSemRWs[(i + 1) % g_cThreads];
492
493 do
494 {
495 int rc1 = (i & 1 ? RTSemRWRequestWrite : RTSemRWRequestRead)(hMine, 60*1000); /* ugly ;-) */
496 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
497 if (rc1 != VINF_SUCCESS && rc1 != VERR_SEM_LV_DEADLOCK && rc1 != VERR_SEM_LV_ILLEGAL_UPGRADE)
498 {
499 RTTestFailed(g_hTest, "#%u: RTSemRWRequest%s(hMine,) -> %Rrc\n", i, i & 1 ? "Write" : "read", rc1);
500 break;
501 }
502 if (RT_SUCCESS(rc1))
503 {
504 for (unsigned iInner = 0; iInner < 4; iInner++)
505 {
506 int rc2 = RTSemRWRequestWrite(hNext, 60*1000);
507 if (rc2 != VINF_SUCCESS && rc2 != VERR_SEM_LV_DEADLOCK && rc2 != VERR_SEM_LV_ILLEGAL_UPGRADE)
508 {
509 RTTestFailed(g_hTest, "#%u: RTSemRWRequestWrite -> %Rrc\n", i, rc2);
510 break;
511 }
512 if (RT_SUCCESS(rc2))
513 {
514 RTTEST_CHECK_RC(g_hTest, rc2 = RTSemRWReleaseWrite(hNext), VINF_SUCCESS);
515 if (RT_FAILURE(rc2))
516 break;
517 }
518 else
519 ASMAtomicIncU32(&g_cDeadlocks);
520 ASMAtomicIncU32(&g_cLoops);
521 }
522
523 RTTEST_CHECK_RC(g_hTest, rc1 = (i & 1 ? RTSemRWReleaseWrite : RTSemRWReleaseRead)(hMine), VINF_SUCCESS);
524 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
525 if (RT_FAILURE(rc1))
526 break;
527 }
528 else
529 ASMAtomicIncU32(&g_cDeadlocks);
530 ASMAtomicIncU32(&g_cLoops);
531 } while (RTTimeNanoTS() < g_NanoTSStop);
532
533 return VINF_SUCCESS;
534}
535
536
537static void test4(uint32_t cThreads, uint32_t cPasses, uint32_t cSecs)
538{
539 testIt(cThreads, cPasses, cSecs, test4Thread, "read-write race v2");
540}
541
542
543static DECLCALLBACK(int) test5Thread(RTTHREAD ThreadSelf, void *pvUser)
544{
545 uintptr_t i = (uintptr_t)pvUser;
546 RTSEMMUTEX hMine = g_ahSemMtxes[i];
547 RTSEMMUTEX hNext = g_ahSemMtxes[(i + 1) % g_cThreads];
548
549 RTTEST_CHECK_RC_RET(g_hTest, RTSemMutexRequest(hMine, RT_INDEFINITE_WAIT), VINF_SUCCESS, rcCheck);
550 if (i & 1)
551 RTTEST_CHECK_RC(g_hTest, RTSemMutexRequest(hMine, RT_INDEFINITE_WAIT), VINF_SUCCESS);
552 if (testWaitForSemMutexToBeOwned(hNext))
553 {
554 int rc;
555 if (i != g_iDeadlockThread)
556 RTTEST_CHECK_RC(g_hTest, rc = RTSemMutexRequest(hNext, RT_INDEFINITE_WAIT), VINF_SUCCESS);
557 else
558 {
559 RTTEST_CHECK_RC_OK(g_hTest, rc = testWaitForAllOtherThreadsToSleep(RTTHREADSTATE_MUTEX, 1));
560 if (RT_SUCCESS(rc))
561 RTTEST_CHECK_RC(g_hTest, rc = RTSemMutexRequest(hNext, RT_INDEFINITE_WAIT), VERR_SEM_LV_DEADLOCK);
562 }
563 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
564 if (RT_SUCCESS(rc))
565 RTTEST_CHECK_RC(g_hTest, rc = RTSemMutexRelease(hNext), VINF_SUCCESS);
566 }
567 if (i & 1)
568 RTTEST_CHECK_RC(g_hTest, RTSemMutexRelease(hMine), VINF_SUCCESS);
569 RTTEST_CHECK_RC(g_hTest, RTSemMutexRelease(hMine), VINF_SUCCESS);
570 return VINF_SUCCESS;
571}
572
573
574static void test5(uint32_t cThreads, uint32_t cPasses)
575{
576 testIt(cThreads, cPasses, 0, test5Thread, "mutex");
577}
578
579
580static DECLCALLBACK(int) test6Thread(RTTHREAD ThreadSelf, void *pvUser)
581{
582 uintptr_t i = (uintptr_t)pvUser;
583 PRTCRITSECT pMine = &g_aCritSects[i];
584 PRTCRITSECT pNext = &g_aCritSects[(i + 1) % g_cThreads];
585
586 RTTEST_CHECK_RC_RET(g_hTest, RTCritSectEnter(pMine), VINF_SUCCESS, rcCheck);
587 if (i & 1)
588 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(pMine), VINF_SUCCESS);
589 if (testWaitForCritSectToBeOwned(pNext))
590 {
591 int rc;
592 if (i != g_iDeadlockThread)
593 {
594 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(pNext), VINF_SUCCESS);
595 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
596 if (RT_SUCCESS(rc))
597 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectLeave(pNext), VINF_SUCCESS);
598 }
599 else
600 {
601 RTTEST_CHECK_RC_OK(g_hTest, rc = testWaitForAllOtherThreadsToSleep(RTTHREADSTATE_CRITSECT, 1));
602 if (RT_SUCCESS(rc))
603 {
604 RTSemEventSetSignaller(g_hSemEvt, g_ahThreads[0]);
605 for (uint32_t iThread = 1; iThread < g_cThreads; iThread++)
606 RTSemEventAddSignaller(g_hSemEvt, g_ahThreads[iThread]);
607 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
608 RTTEST_CHECK_RC(g_hTest, RTSemEventWait(g_hSemEvt, 10*1000), VERR_SEM_LV_DEADLOCK);
609 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
610 RTTEST_CHECK_RC(g_hTest, RTSemEventSignal(g_hSemEvt), VINF_SUCCESS);
611 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
612 RTTEST_CHECK_RC(g_hTest, RTSemEventWait(g_hSemEvt, 10*1000), VINF_SUCCESS);
613 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
614 RTSemEventSetSignaller(g_hSemEvt, NIL_RTTHREAD);
615 }
616 }
617 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
618 }
619 if (i & 1)
620 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(pMine), VINF_SUCCESS);
621 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(pMine), VINF_SUCCESS);
622 return VINF_SUCCESS;
623}
624
625
626static void test6(uint32_t cThreads, uint32_t cPasses)
627{
628 testIt(cThreads, cPasses, 0, test6Thread, "event");
629}
630
631
632static bool testIsLockValidationCompiledIn(void)
633{
634 RTCRITSECT CritSect;
635 RTTEST_CHECK_RC_OK_RET(g_hTest, RTCritSectInit(&CritSect), false);
636 RTTEST_CHECK_RC_OK_RET(g_hTest, RTCritSectEnter(&CritSect), false);
637 bool fRet = CritSect.pValidatorRec
638 && CritSect.pValidatorRec->hThread == RTThreadSelf();
639 RTTEST_CHECK_RC_OK_RET(g_hTest, RTCritSectLeave(&CritSect), false);
640 RTTEST_CHECK_RC_OK_RET(g_hTest, RTCritSectDelete(&CritSect), false);
641
642 RTSEMRW hSemRW;
643 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemRWCreate(&hSemRW), false);
644 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemRWRequestRead(hSemRW, 50), false);
645 int rc = RTSemRWRequestWrite(hSemRW, 1);
646 if (rc != VERR_SEM_LV_ILLEGAL_UPGRADE)
647 fRet = false;
648 RTTEST_CHECK_RET(g_hTest, RT_FAILURE_NP(rc), false);
649 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemRWReleaseRead(hSemRW), false);
650 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemRWDestroy(hSemRW), false);
651
652#if 0 /** @todo detect it on RTSemMutex... */
653 RTSEMMUTEX hSemMtx;
654 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemMutexCreate(&hSemRW), false);
655 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemMutexRequest(hSemRW, 50), false);
656 /*??*/
657 RTTEST_CHECK_RET(g_hTest, RT_FAILURE_NP(rc), false);
658 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemRWRelease(hSemRW), false);
659 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemRWDestroy(hSemRW), false);
660#endif
661
662 RTSEMEVENT hSemEvt;
663 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemEventCreate(&hSemEvt), false);
664 RTSemEventSetSignaller(hSemEvt, RTThreadSelf());
665 RTSemEventSetSignaller(hSemEvt, NIL_RTTHREAD);
666 rc = RTSemEventSignal(hSemEvt);
667 if (rc != VERR_SEM_LV_NOT_SIGNALLER)
668 fRet = false;
669 RTTEST_CHECK_RET(g_hTest, RT_FAILURE_NP(rc), false);
670 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemEventDestroy(hSemEvt), false);
671
672 return fRet;
673}
674
675
676int main()
677{
678 /*
679 * Init.
680 */
681 int rc = RTTestInitAndCreate("tstRTLockValidator", &g_hTest);
682 if (rc)
683 return rc;
684 RTTestBanner(g_hTest);
685
686 RTLockValidatorSetEnabled(true);
687 RTLockValidatorSetMayPanic(false);
688 RTLockValidatorSetQuiet(true);
689 if (!testIsLockValidationCompiledIn())
690 return RTTestErrorCount(g_hTest) > 0
691 ? RTTestSummaryAndDestroy(g_hTest)
692 : RTTestSkipAndDestroy(g_hTest, "deadlock detection is not compiled in");
693 RTLockValidatorSetQuiet(false);
694
695 /*
696 * Some initial tests with verbose output.
697 */
698#if 1
699 test1(3, 1);
700 test2(1, 1);
701 test2(3, 1);
702 test5(3, 1);
703 test6(3, 1);
704#endif
705
706 /*
707 * More thorough testing without noisy output.
708 */
709 RTLockValidatorSetQuiet(true);
710 test1( 2, 256); /* 256 * 4ms = 1s (approx); 4ms == fudge factor */
711 test1( 3, 256);
712 test1( 7, 256);
713 test1(10, 256);
714 test1(15, 256);
715 test1(30, 256);
716
717#if 1
718 test2( 1, 256);
719 test2( 2, 256);
720 test2( 3, 256);
721 test2( 7, 256);
722 test2(10, 256);
723 test2(15, 256);
724 test2(30, 256);
725
726 test3( 2, 1, 2);
727 test3(10, 1, 2);
728
729 test4( 2, 1, 2);
730 test4( 6, 1, 2);
731 test4(10, 1, 10);
732 test4(30, 1, 10);
733
734 test5( 2, 256);
735 test5( 3, 256);
736 test5( 7, 256);
737 test5(10, 256);
738 test5(15, 256);
739 test5(30, 256);
740#endif
741
742 test6( 2, 256);
743 test6( 3, 256);
744 test6( 7, 256);
745 test6(10, 256);
746 test6(15, 256);
747 test6(30, 256);
748
749 return RTTestSummaryAndDestroy(g_hTest);
750}
751
Note: See TracBrowser for help on using the repository browser.

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