VirtualBox

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

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

tstRTLockValidator: Added a simple mutex deadlock to the testcase.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 21.1 KB
Line 
1/* $Id: tstRTLockValidator.cpp 25626 2010-01-03 15:24:13Z 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];
60
61/** When to stop testing. */
62static uint64_t g_NanoTSStop;
63/** The number of deadlocks. */
64static uint32_t volatile g_cDeadlocks;
65/** The number of loops. */
66static uint32_t volatile g_cLoops;
67
68
69/**
70 * Spin until someone else has taken ownership of the critical section.
71 *
72 * @returns true on success, false on abort.
73 * @param pCritSect The critical section.
74 */
75static bool testWaitForCritSectToBeOwned(PRTCRITSECT pCritSect)
76{
77 unsigned iLoop = 0;
78 while (!RTCritSectIsOwned(pCritSect))
79 {
80 if (!RTCritSectIsInitialized(pCritSect))
81 return false;
82 RTThreadSleep(g_fDoNotSpin ? 3600*1000 : iLoop > 256 ? 1 : 0);
83 iLoop++;
84 }
85 return true;
86}
87
88
89/**
90 * Spin until someone else has taken ownership (any kind) of the read-write
91 * semaphore.
92 *
93 * @returns true on success, false on abort.
94 * @param hSemRW The read-write semaphore.
95 */
96static bool testWaitForSemRWToBeOwned(RTSEMRW hSemRW)
97{
98 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
99 unsigned iLoop = 0;
100 for (;;)
101 {
102 if (RTSemRWGetWriteRecursion(hSemRW) > 0)
103 return true;
104 if (RTSemRWGetReadCount(hSemRW) > 0)
105 return true;
106 RTThreadSleep(g_fDoNotSpin ? 3600*1000 : iLoop > 256 ? 1 : 0);
107 iLoop++;
108 }
109 return true;
110}
111
112
113/**
114 * Spin until someone else has taken ownership of the mutex semaphore.
115 *
116 * @returns true on success, false on abort.
117 * @param hSemMutex The mutex sempahore.
118 */
119static bool testWaitForSemMutexToBeOwned(RTSEMMUTEX hSemMutex)
120{
121 unsigned iLoop = 0;
122 while (!RTSemMutexIsOwned(hSemMutex))
123 {
124 RTThreadSleep(g_fDoNotSpin ? 3600*1000 : iLoop > 256 ? 1 : 0);
125 iLoop++;
126 }
127 return true;
128}
129
130
131/**
132 * Waits for a thread to enter a sleeping state.
133 *
134 * @returns true on success, false on abort.
135 * @param hThread The thread.
136 * @param enmDesiredState The desired thread sleep state.
137 * @param pvLock The lock it should be sleeping on.
138 */
139static bool testWaitForThreadToSleep(RTTHREAD hThread, RTTHREADSTATE enmDesiredState, void *pvLock)
140{
141 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
142 for (unsigned iLoop = 0; ; iLoop++)
143 {
144 RTTHREADSTATE enmState = RTThreadGetState(hThread);
145 if (RTTHREAD_IS_SLEEPING(enmState))
146 {
147 if ( enmState == enmDesiredState
148 && ( !pvLock
149 || ( pvLock == RTLockValidatorQueryBlocking(hThread)
150 && !RTLockValidatorIsBlockedThreadInValidator(hThread) )
151 )
152 )
153 return true;
154 }
155 else if ( enmState != RTTHREADSTATE_RUNNING
156 && enmState != RTTHREADSTATE_INITIALIZING)
157 return false;
158 RTThreadSleep(g_fDoNotSpin ? 3600*1000 : iLoop > 256 ? 1 : 0);
159 }
160}
161
162
163/**
164 * Waits for all the other threads to enter sleeping states.
165 *
166 * @returns VINF_SUCCESS on success, VERR_INTERNAL_ERROR on failure.
167 * @param enmDesiredState The desired thread sleep state.
168 * @param cWaitOn The distance to the lock they'll be waiting on,
169 * the lock type is derived from the desired state.
170 * UINT32_MAX means no special lock.
171 */
172static int testWaitForAllOtherThreadsToSleep(RTTHREADSTATE enmDesiredState, uint32_t cWaitOn)
173{
174 RTTHREAD hThreadSelf = RTThreadSelf();
175 for (uint32_t i = 0; i < g_cThreads; i++)
176 {
177 RTTHREAD hThread = g_ahThreads[i];
178 if ( hThread != NIL_RTTHREAD
179 && hThread != hThreadSelf)
180 {
181 void *pvLock = NULL;
182 if (cWaitOn != UINT32_MAX)
183 {
184 uint32_t j = (i + cWaitOn) % g_cThreads;
185 switch (enmDesiredState)
186 {
187 case RTTHREADSTATE_CRITSECT: pvLock = &g_aCritSects[j]; break;
188 case RTTHREADSTATE_RW_WRITE:
189 case RTTHREADSTATE_RW_READ: pvLock = g_ahSemRWs[j]; break;
190 case RTTHREADSTATE_MUTEX: pvLock = g_ahSemMtxes[j]; break;
191 default: break;
192 }
193 }
194 bool fRet = testWaitForThreadToSleep(hThread, enmDesiredState, pvLock);
195 if (!fRet)
196 return VERR_INTERNAL_ERROR;
197 }
198 }
199 RTThreadSleep(4); /* fudge factor */
200 return VINF_SUCCESS;
201}
202
203
204/**
205 * Worker that starts the threads.
206 *
207 * @returns Same as RTThreadCreate.
208 * @param cThreads The number of threads to start.
209 * @param pfnThread Thread function.
210 */
211static int testStartThreads(uint32_t cThreads, PFNRTTHREAD pfnThread)
212{
213 uint32_t i;
214 for (i = 0; i < RT_ELEMENTS(g_ahThreads); i++)
215 g_ahThreads[i] = NIL_RTTHREAD;
216
217 for (i = 0; i < cThreads; i++)
218 RTTEST_CHECK_RC_OK_RET(g_hTest,
219 RTThreadCreateF(&g_ahThreads[i], pfnThread, (void *)(uintptr_t)i, 0,
220 RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "thread-%02u", i),
221 rcCheck);
222 return VINF_SUCCESS;
223}
224
225
226/**
227 * Worker that waits for the threads to complete.
228 *
229 * @param cMillies How long to wait for each.
230 * @param fStopOnError Whether to stop on error and heed the thread
231 * return status.
232 */
233static void testWaitForThreads(uint32_t cMillies, bool fStopOnError)
234{
235 uint32_t i = RT_ELEMENTS(g_ahThreads);
236 while (i-- > 0)
237 if (g_ahThreads[i] != NIL_RTTHREAD)
238 {
239 int rcThread;
240 int rc2;
241 RTTEST_CHECK_RC_OK(g_hTest, rc2 = RTThreadWait(g_ahThreads[i], cMillies, &rcThread));
242 if (RT_SUCCESS(rc2))
243 g_ahThreads[i] = NIL_RTTHREAD;
244 if (fStopOnError && (RT_FAILURE(rc2) || RT_FAILURE(rcThread)))
245 return;
246 }
247}
248
249
250static void testIt(uint32_t cThreads, uint32_t cPasses, uint32_t cSecs, PFNRTTHREAD pfnThread, const char *pszName)
251{
252 if (cSecs)
253 RTTestSubF(g_hTest, "%s, %u threads, %u secs", pszName, cThreads, cSecs * cPasses);
254 else
255 RTTestSubF(g_hTest, "%s, %u threads, %u passes", pszName, cThreads, cPasses);
256
257 RTTEST_CHECK_RETV(g_hTest, RT_ELEMENTS(g_ahThreads) >= cThreads);
258 RTTEST_CHECK_RETV(g_hTest, RT_ELEMENTS(g_aCritSects) >= cThreads);
259
260 g_cThreads = cThreads;
261
262 for (uint32_t i = 0; i < cThreads; i++)
263 {
264 RTTEST_CHECK_RC_RETV(g_hTest, RTCritSectInit(&g_aCritSects[i]), VINF_SUCCESS);
265 RTTEST_CHECK_RC_RETV(g_hTest, RTSemRWCreate(&g_ahSemRWs[i]), VINF_SUCCESS);
266 RTTEST_CHECK_RC_RETV(g_hTest, RTSemMutexCreate(&g_ahSemMtxes[i]), VINF_SUCCESS);
267 }
268
269 uint32_t cLoops = 0;
270 uint32_t cDeadlocks = 0;
271 uint32_t cErrors = RTTestErrorCount(g_hTest);
272 for (uint32_t iPass = 0; iPass < cPasses && RTTestErrorCount(g_hTest) == cErrors; iPass++)
273 {
274 g_iDeadlockThread = (cThreads - 1 + iPass) % cThreads;
275 g_cLoops = 0;
276 g_cDeadlocks = 0;
277 g_NanoTSStop = cSecs ? RTTimeNanoTS() + cSecs * UINT64_C(1000000000) : 0;
278
279 int rc = testStartThreads(cThreads, pfnThread);
280 if (RT_SUCCESS(rc))
281 testWaitForThreads(30*1000 + cSecs*1000, true);
282
283 RTTEST_CHECK(g_hTest, !cSecs || g_cLoops > 0);
284 cLoops += g_cLoops;
285 RTTEST_CHECK(g_hTest, !cSecs || g_cDeadlocks > 0);
286 cDeadlocks += g_cDeadlocks;
287 }
288
289 for (uint32_t i = 0; i < cThreads; i++)
290 {
291 RTTEST_CHECK_RC(g_hTest, RTCritSectDelete(&g_aCritSects[i]), VINF_SUCCESS);
292 RTTEST_CHECK_RC(g_hTest, RTSemRWDestroy(g_ahSemRWs[i]), VINF_SUCCESS);
293 RTTEST_CHECK_RC(g_hTest, RTSemMutexDestroy(g_ahSemMtxes[i]), VINF_SUCCESS);
294 }
295 testWaitForThreads(10*1000, false);
296
297 if (cSecs)
298 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "cLoops=%u cDeadlocks=%u (%u%%)\n",
299 cLoops, cDeadlocks, cLoops ? cDeadlocks * 100 / cLoops : 0);
300}
301
302
303static DECLCALLBACK(int) test1Thread(RTTHREAD ThreadSelf, void *pvUser)
304{
305 uintptr_t i = (uintptr_t)pvUser;
306 PRTCRITSECT pMine = &g_aCritSects[i];
307 PRTCRITSECT pNext = &g_aCritSects[(i + 1) % g_cThreads];
308
309 RTTEST_CHECK_RC_RET(g_hTest, RTCritSectEnter(pMine), VINF_SUCCESS, rcCheck);
310 if (i & 1)
311 RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(pMine), VINF_SUCCESS);
312 if (testWaitForCritSectToBeOwned(pNext))
313 {
314 int rc;
315 if (i != g_iDeadlockThread)
316 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(pNext), VINF_SUCCESS);
317 else
318 {
319 RTTEST_CHECK_RC_OK(g_hTest, rc = testWaitForAllOtherThreadsToSleep(RTTHREADSTATE_CRITSECT, 1));
320 if (RT_SUCCESS(rc))
321 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(pNext), VERR_SEM_LV_DEADLOCK);
322 }
323 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
324 if (RT_SUCCESS(rc))
325 RTTEST_CHECK_RC(g_hTest, rc = RTCritSectLeave(pNext), VINF_SUCCESS);
326 }
327 if (i & 1)
328 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(pMine), VINF_SUCCESS);
329 RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(pMine), VINF_SUCCESS);
330 return VINF_SUCCESS;
331}
332
333
334static void test1(uint32_t cThreads, uint32_t cPasses)
335{
336 testIt(cThreads, cPasses, 0, test1Thread, "critsect");
337}
338
339
340static DECLCALLBACK(int) test2Thread(RTTHREAD ThreadSelf, void *pvUser)
341{
342 uintptr_t i = (uintptr_t)pvUser;
343 RTSEMRW hMine = g_ahSemRWs[i];
344 RTSEMRW hNext = g_ahSemRWs[(i + 1) % g_cThreads];
345 int rc;
346
347 if (i & 1)
348 {
349 RTTEST_CHECK_RC_RET(g_hTest, RTSemRWRequestWrite(hMine, RT_INDEFINITE_WAIT), VINF_SUCCESS, rcCheck);
350 if ((i & 3) == 3)
351 RTTEST_CHECK_RC(g_hTest, RTSemRWRequestWrite(hMine, RT_INDEFINITE_WAIT), VINF_SUCCESS);
352 }
353 else
354 RTTEST_CHECK_RC_RET(g_hTest, RTSemRWRequestRead(hMine, RT_INDEFINITE_WAIT), VINF_SUCCESS, rcCheck);
355 if (testWaitForSemRWToBeOwned(hNext))
356 {
357 if (i != g_iDeadlockThread)
358 RTTEST_CHECK_RC(g_hTest, rc = RTSemRWRequestWrite(hNext, RT_INDEFINITE_WAIT), VINF_SUCCESS);
359 else
360 {
361 RTTEST_CHECK_RC_OK(g_hTest, rc = testWaitForAllOtherThreadsToSleep(RTTHREADSTATE_RW_WRITE, 1));
362 if (RT_SUCCESS(rc))
363 {
364 if (g_cThreads > 1)
365 RTTEST_CHECK_RC(g_hTest, rc = RTSemRWRequestWrite(hNext, RT_INDEFINITE_WAIT), VERR_SEM_LV_DEADLOCK);
366 else
367 RTTEST_CHECK_RC(g_hTest, rc = RTSemRWRequestWrite(hNext, RT_INDEFINITE_WAIT), VERR_SEM_LV_ILLEGAL_UPGRADE);
368 }
369 }
370 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
371 if (RT_SUCCESS(rc))
372 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(hNext), VINF_SUCCESS);
373 }
374 if (i & 1)
375 {
376 if ((i & 3) == 3)
377 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(hMine), VINF_SUCCESS);
378 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(hMine), VINF_SUCCESS);
379 }
380 else
381 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseRead(hMine), VINF_SUCCESS);
382 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
383 return VINF_SUCCESS;
384}
385
386
387static void test2(uint32_t cThreads, uint32_t cPasses)
388{
389 testIt(cThreads, cPasses, 0, test2Thread, "read-write");
390}
391
392
393static DECLCALLBACK(int) test3Thread(RTTHREAD ThreadSelf, void *pvUser)
394{
395 uintptr_t i = (uintptr_t)pvUser;
396 RTSEMRW hMine = g_ahSemRWs[i];
397 RTSEMRW hNext = g_ahSemRWs[(i + 1) % g_cThreads];
398 int rc;
399
400 if (i & 1)
401 RTTEST_CHECK_RC_RET(g_hTest, RTSemRWRequestWrite(hMine, RT_INDEFINITE_WAIT), VINF_SUCCESS, rcCheck);
402 else
403 RTTEST_CHECK_RC_RET(g_hTest, RTSemRWRequestRead(hMine, RT_INDEFINITE_WAIT), VINF_SUCCESS, rcCheck);
404 if (testWaitForSemRWToBeOwned(hNext))
405 {
406 do
407 {
408 rc = RTSemRWRequestWrite(hNext, 60*1000);
409 if (rc != VINF_SUCCESS && rc != VERR_SEM_LV_DEADLOCK && rc != VERR_SEM_LV_ILLEGAL_UPGRADE)
410 {
411 RTTestFailed(g_hTest, "#%u: RTSemRWRequestWrite -> %Rrc\n", i, rc);
412 break;
413 }
414 if (RT_SUCCESS(rc))
415 {
416 RTTEST_CHECK_RC(g_hTest, rc = RTSemRWReleaseWrite(hNext), VINF_SUCCESS);
417 if (RT_FAILURE(rc))
418 break;
419 }
420 else
421 ASMAtomicIncU32(&g_cDeadlocks);
422 ASMAtomicIncU32(&g_cLoops);
423 } while (RTTimeNanoTS() < g_NanoTSStop);
424 }
425 if (i & 1)
426 RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(hMine), VINF_SUCCESS);
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 test3(uint32_t cThreads, uint32_t cPasses, uint32_t cSecs)
435{
436 testIt(cThreads, cPasses, cSecs, test3Thread, "read-write race");
437}
438
439
440static DECLCALLBACK(int) test4Thread(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
446 do
447 {
448 int rc1 = (i & 1 ? RTSemRWRequestWrite : RTSemRWRequestRead)(hMine, 60*1000); /* ugly ;-) */
449 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
450 if (rc1 != VINF_SUCCESS && rc1 != VERR_SEM_LV_DEADLOCK && rc1 != VERR_SEM_LV_ILLEGAL_UPGRADE)
451 {
452 RTTestFailed(g_hTest, "#%u: RTSemRWRequest%s(hMine,) -> %Rrc\n", i, i & 1 ? "Write" : "read", rc1);
453 break;
454 }
455 if (RT_SUCCESS(rc1))
456 {
457 for (unsigned iInner = 0; iInner < 4; iInner++)
458 {
459 int rc2 = RTSemRWRequestWrite(hNext, 60*1000);
460 if (rc2 != VINF_SUCCESS && rc2 != VERR_SEM_LV_DEADLOCK && rc2 != VERR_SEM_LV_ILLEGAL_UPGRADE)
461 {
462 RTTestFailed(g_hTest, "#%u: RTSemRWRequestWrite -> %Rrc\n", i, rc2);
463 break;
464 }
465 if (RT_SUCCESS(rc2))
466 {
467 RTTEST_CHECK_RC(g_hTest, rc2 = RTSemRWReleaseWrite(hNext), VINF_SUCCESS);
468 if (RT_FAILURE(rc2))
469 break;
470 }
471 else
472 ASMAtomicIncU32(&g_cDeadlocks);
473 ASMAtomicIncU32(&g_cLoops);
474 }
475
476 RTTEST_CHECK_RC(g_hTest, rc1 = (i & 1 ? RTSemRWReleaseWrite : RTSemRWReleaseRead)(hMine), VINF_SUCCESS);
477 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
478 if (RT_FAILURE(rc1))
479 break;
480 }
481 else
482 ASMAtomicIncU32(&g_cDeadlocks);
483 ASMAtomicIncU32(&g_cLoops);
484 } while (RTTimeNanoTS() < g_NanoTSStop);
485
486 return VINF_SUCCESS;
487}
488
489
490static void test4(uint32_t cThreads, uint32_t cPasses, uint32_t cSecs)
491{
492 testIt(cThreads, cPasses, cSecs, test4Thread, "read-write race v2");
493}
494
495
496static DECLCALLBACK(int) test5Thread(RTTHREAD ThreadSelf, void *pvUser)
497{
498 uintptr_t i = (uintptr_t)pvUser;
499 RTSEMMUTEX hMine = g_ahSemMtxes[i];
500 RTSEMMUTEX hNext = g_ahSemMtxes[(i + 1) % g_cThreads];
501
502 RTTEST_CHECK_RC_RET(g_hTest, RTSemMutexRequest(hMine, RT_INDEFINITE_WAIT), VINF_SUCCESS, rcCheck);
503 if (i & 1)
504 RTTEST_CHECK_RC(g_hTest, RTSemMutexRequest(hMine, RT_INDEFINITE_WAIT), VINF_SUCCESS);
505 if (testWaitForSemMutexToBeOwned(hNext))
506 {
507 int rc;
508 if (i != g_iDeadlockThread)
509 RTTEST_CHECK_RC(g_hTest, rc = RTSemMutexRequest(hNext, RT_INDEFINITE_WAIT), VINF_SUCCESS);
510 else
511 {
512 RTTEST_CHECK_RC_OK(g_hTest, rc = testWaitForAllOtherThreadsToSleep(RTTHREADSTATE_MUTEX, 1));
513 if (RT_SUCCESS(rc))
514 RTTEST_CHECK_RC(g_hTest, rc = RTSemMutexRequest(hNext, RT_INDEFINITE_WAIT), VERR_SEM_LV_DEADLOCK);
515 }
516 RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
517 if (RT_SUCCESS(rc))
518 RTTEST_CHECK_RC(g_hTest, rc = RTSemMutexRelease(hNext), VINF_SUCCESS);
519 }
520 if (i & 1)
521 RTTEST_CHECK_RC(g_hTest, RTSemMutexRelease(hMine), VINF_SUCCESS);
522 RTTEST_CHECK_RC(g_hTest, RTSemMutexRelease(hMine), VINF_SUCCESS);
523 return VINF_SUCCESS;
524}
525
526
527static void test5(uint32_t cThreads, uint32_t cPasses)
528{
529 testIt(cThreads, cPasses, 0, test5Thread, "mutex");
530}
531
532
533static bool testIsLockValidationCompiledIn(void)
534{
535 RTCRITSECT CritSect;
536 RTTEST_CHECK_RC_OK_RET(g_hTest, RTCritSectInit(&CritSect), false);
537 RTTEST_CHECK_RC_OK_RET(g_hTest, RTCritSectEnter(&CritSect), false);
538 bool fRet = CritSect.pValidatorRec
539 && CritSect.pValidatorRec->hThread == RTThreadSelf();
540 RTTEST_CHECK_RC_OK_RET(g_hTest, RTCritSectLeave(&CritSect), false);
541 RTTEST_CHECK_RC_OK_RET(g_hTest, RTCritSectDelete(&CritSect), false);
542
543 RTSEMRW hSemRW;
544 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemRWCreate(&hSemRW), false);
545 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemRWRequestRead(hSemRW, 50), false);
546 int rc = RTSemRWRequestWrite(hSemRW, 1);
547 if (rc != VERR_SEM_LV_ILLEGAL_UPGRADE)
548 fRet = false;
549 RTTEST_CHECK_RET(g_hTest, RT_FAILURE_NP(rc), false);
550 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemRWReleaseRead(hSemRW), false);
551 RTTEST_CHECK_RC_OK_RET(g_hTest, RTSemRWDestroy(hSemRW), false);
552
553 return fRet;
554}
555
556
557int main()
558{
559 /*
560 * Init.
561 */
562 int rc = RTTestInitAndCreate("tstRTLockValidator", &g_hTest);
563 if (rc)
564 return rc;
565 RTTestBanner(g_hTest);
566
567 RTLockValidatorSetEnabled(true);
568 RTLockValidatorSetMayPanic(false);
569 RTLockValidatorSetQuiet(true);
570 if (!testIsLockValidationCompiledIn())
571 return RTTestErrorCount(g_hTest) > 0
572 ? RTTestSummaryAndDestroy(g_hTest)
573 : RTTestSkipAndDestroy(g_hTest, "deadlock detection is not compiled in");
574 RTLockValidatorSetQuiet(false);
575
576 /*
577 * Some initial tests with verbose output.
578 */
579#if 0
580 test1(3, 1);
581 test2(1, 1);
582 test2(3, 1);
583#endif
584 test5(3, 1);
585
586 /*
587 * More thorough testing without noisy output.
588 */
589 RTLockValidatorSetQuiet(true);
590#if 0
591 test1( 2, 256); /* 256 * 4ms = 1s (approx); 4ms == fudge factor */
592 test1( 3, 256);
593 test1( 7, 256);
594 test1(10, 256);
595 test1(15, 256);
596 test1(30, 256);
597
598 test2( 1, 256);
599 test2( 2, 256);
600 test2( 3, 256);
601 test2( 7, 256);
602 test2(10, 256);
603 test2(15, 256);
604 test2(30, 256);
605
606 test3( 2, 1, 2);
607 test3(10, 1, 2);
608
609 test4( 2, 1, 2);
610 test4( 6, 1, 2);
611 test4(10, 1, 10);
612 test4(30, 1, 10);
613#endif
614
615 test5( 2, 256);
616 test5( 3, 256);
617 test5( 7, 256);
618 test5(10, 256);
619 test5(15, 256);
620 test5(30, 256);
621
622 return RTTestSummaryAndDestroy(g_hTest);
623}
624
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