VirtualBox

source: vbox/trunk/src/VBox/Runtime/testcase/tstCritSect.cpp@ 12912

Last change on this file since 12912 was 8245, checked in by vboxsync, 17 years ago

rebranding: IPRT files again.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 18.1 KB
Line 
1/* $Id: tstCritSect.cpp 8245 2008-04-21 17:24:28Z vboxsync $ */
2/** @file
3 * IPRT Testcase - Critical Sections.
4 */
5
6/*
7 * Copyright (C) 2006-2007 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#ifdef TRY_WIN32_CRIT
36# include <Windows.h>
37#endif
38#include <iprt/critsect.h>
39#include <iprt/lock.h>
40#include <iprt/thread.h>
41#include <iprt/log.h>
42#include <iprt/semaphore.h>
43#include <iprt/asm.h>
44#include <iprt/runtime.h>
45#include <iprt/time.h>
46#include <iprt/assert.h>
47#include <iprt/string.h>
48#include <iprt/err.h>
49
50#include <stdio.h>
51#include <stdlib.h>
52
53#ifndef TRY_WIN32_CRIT
54#define LOCKERS(sect) ((sect).cLockers)
55#else
56/* This is for comparing with the "real thing". */
57#define RTCRITSECT CRITICAL_SECTION
58#define PRTCRITSECT LPCRITICAL_SECTION
59#define LOCKERS(sect) (*(LONG volatile *)&(sect).LockCount)
60
61inline int RTCritSectInit(PCRITICAL_SECTION pCritSect)
62{
63 InitializeCriticalSection(pCritSect);
64 return VINF_SUCCESS;
65}
66
67#undef RTCritSectEnter
68inline int RTCritSectEnter(PCRITICAL_SECTION pCritSect)
69{
70 EnterCriticalSection(pCritSect);
71 return VINF_SUCCESS;
72}
73
74inline int RTCritSectLeave(PCRITICAL_SECTION pCritSect)
75{
76 LeaveCriticalSection(pCritSect);
77 return VINF_SUCCESS;
78}
79
80inline int RTCritSectDelete(PCRITICAL_SECTION pCritSect)
81{
82 DeleteCriticalSection(pCritSect);
83 return VINF_SUCCESS;
84}
85#endif
86
87/*******************************************************************************
88* Structures and Typedefs *
89*******************************************************************************/
90/**
91 * Arguments to ThreadTest1().
92 */
93typedef struct THREADTEST1ARGS
94{
95 /** The critical section. */
96 PRTCRITSECT pCritSect;
97 /** The thread ordinal. */
98 uint32_t iThread;
99 /** Pointer to the release counter. */
100 uint32_t volatile *pu32Release;
101} THREADTEST1ARGS, *PTHREADTEST1ARGS;
102
103
104/**
105 * Arguments to ThreadTest2().
106 */
107typedef struct THREADTEST2ARGS
108{
109 /** The critical section. */
110 PRTCRITSECT pCritSect;
111 /** The thread ordinal. */
112 uint32_t iThread;
113 /** Pointer to the release counter. */
114 uint32_t volatile *pu32Release;
115 /** Pointer to the alone indicator. */
116 uint32_t volatile *pu32Alone;
117 /** Pointer to the previous thread variable. */
118 uint32_t volatile *pu32Prev;
119 /** Pointer to the sequential enters counter. */
120 uint32_t volatile *pcSeq;
121 /** Pointer to the reordered enters counter. */
122 uint32_t volatile *pcReordered;
123 /** Pointer to the variable counting running threads. */
124 uint32_t volatile *pcThreadRunning;
125 /** Number of times this thread was inside the section. */
126 uint32_t volatile cTimes;
127 /** The number of threads. */
128 uint32_t cThreads;
129 /** Number of iterations (sum of all threads). */
130 uint32_t cIterations;
131 /** Yield while inside the section. */
132 unsigned cCheckLoops;
133 /** Signal this when done. */
134 RTSEMEVENT EventDone;
135} THREADTEST2ARGS, *PTHREADTEST2ARGS;
136
137
138/*******************************************************************************
139* Global Variables *
140*******************************************************************************/
141/** Error counter. */
142static volatile uint32_t g_cErrors = 0;
143
144/**
145 * Thread which goes to sleep on the critsect and checks that it's released in the right order.
146 */
147static DECLCALLBACK(int) ThreadTest1(RTTHREAD ThreadSelf, void *pvArg)
148{
149 PTHREADTEST1ARGS pArgs = (PTHREADTEST1ARGS)pvArg;
150 Log2(("ThreadTest1: Start - iThread=%d ThreadSelf=%p\n", pArgs->iThread, ThreadSelf));
151
152 /*
153 * Enter it.
154 */
155 int rc = RTCritSectEnter(pArgs->pCritSect);
156 if (RT_FAILURE(rc))
157 {
158 printf("tstCritSect: FATAL FAILURE - thread %d: RTCritSectEnter -> %d\n", pArgs->iThread, rc);
159 ASMAtomicIncU32(&g_cErrors);
160 exit(g_cErrors);
161 return 1;
162 }
163
164 /*
165 * Check release order.
166 */
167 if (*pArgs->pu32Release != pArgs->iThread)
168 {
169 printf("tstCritSect: FAILURE - thread %d: released as number %d\n", pArgs->iThread, *pArgs->pu32Release);
170 ASMAtomicIncU32(&g_cErrors);
171 }
172 ASMAtomicIncU32(pArgs->pu32Release);
173
174 /*
175 * Leave it.
176 */
177 rc = RTCritSectLeave(pArgs->pCritSect);
178 if (RT_FAILURE(rc))
179 {
180 printf("tstCritSect: FATAL FAILURE - thread %d: RTCritSectEnter -> %d\n", pArgs->iThread, rc);
181 ASMAtomicIncU32(&g_cErrors);
182 exit(g_cErrors);
183 return 1;
184 }
185
186 Log2(("ThreadTest1: End - iThread=%d ThreadSelf=%p\n", pArgs->iThread, ThreadSelf));
187 return 0;
188}
189
190
191int Test1(unsigned cThreads)
192{
193 /*
194 * Create a critical section.
195 */
196 RTCRITSECT CritSect;
197 int rc = RTCritSectInit(&CritSect);
198 if (RT_FAILURE(rc))
199 {
200 printf("tstCritSect: FATAL FAILURE - RTCritSectInit -> %d\n", rc);
201 return 1;
202 }
203
204 /*
205 * Enter, leave and enter again.
206 */
207 rc = RTCritSectEnter(&CritSect);
208 if (RT_FAILURE(rc))
209 {
210 printf("tstCritSect: FATAL FAILURE - RTCritSectEnter -> %d\n", rc);
211 return 1;
212 }
213 rc = RTCritSectLeave(&CritSect);
214 if (RT_FAILURE(rc))
215 {
216 printf("tstCritSect: FATAL FAILURE - RTCritSectLeave -> %d\n", rc);
217 return 1;
218 }
219 rc = RTCritSectEnter(&CritSect);
220 if (RT_FAILURE(rc))
221 {
222 printf("tstCritSect: FATAL FAILURE - RTCritSectEnter -> %d (2nd)\n", rc);
223 return 1;
224 }
225
226 /*
227 * Now spawn threads which will go to sleep entering the critsect.
228 */
229 uint32_t u32Release = 0;
230 for (uint32_t iThread = 0; iThread < cThreads; iThread++)
231 {
232 PTHREADTEST1ARGS pArgs = (PTHREADTEST1ARGS)calloc(sizeof(*pArgs), 1);
233 pArgs->iThread = iThread;
234 pArgs->pCritSect = &CritSect;
235 pArgs->pu32Release = &u32Release;
236 int32_t iLock = LOCKERS(CritSect);
237 char szThread[17];
238 RTStrPrintf(szThread, sizeof(szThread), "T%d", iThread);
239 RTTHREAD Thread;
240 rc = RTThreadCreate(&Thread, ThreadTest1, pArgs, 0, RTTHREADTYPE_DEFAULT, 0, szThread);
241 if (RT_FAILURE(rc))
242 {
243 printf("tstCritSect: FATAL FAILURE - RTThreadCreate -> %d\n", rc);
244 exit(1);
245 }
246 /* wait for it to get into waiting. */
247 while (LOCKERS(CritSect) == iLock)
248 RTThreadSleep(10);
249 RTThreadSleep(20);
250 }
251
252 /*
253 * Now we'll release the threads and wait for all of them to quit.
254 */
255 u32Release = 0;
256 rc = RTCritSectLeave(&CritSect);
257 if (RT_FAILURE(rc))
258 {
259 printf("tstCritSect: FATAL FAILURE - RTCritSectLeave -> %d (2nd)\n", rc);
260 return 1;
261 }
262 while (u32Release < cThreads)
263 RTThreadSleep(10);
264
265 rc = RTCritSectDelete(&CritSect);
266 if (RT_FAILURE(rc))
267 {
268 printf("tstCritSect: FAILURE - RTCritSectDelete -> %d\n", rc);
269 ASMAtomicIncU32(&g_cErrors);
270 }
271
272 return 0;
273}
274
275
276
277/**
278 * Thread which goes to sleep on the critsect and checks
279 * that it's released along and in the right order. This is done a number of times.
280 *
281 */
282static DECLCALLBACK(int) ThreadTest2(RTTHREAD ThreadSelf, void *pvArg)
283{
284 PTHREADTEST2ARGS pArgs = (PTHREADTEST2ARGS)pvArg;
285 Log2(("ThreadTest2: Start - iThread=%d ThreadSelf=%p\n", pArgs->iThread, ThreadSelf));
286 uint64_t u64TSStart = 0;
287 ASMAtomicIncU32(pArgs->pcThreadRunning);
288
289 for (unsigned i = 0; *pArgs->pu32Release < pArgs->cIterations; i++)
290 {
291 /*
292 * Enter it.
293 */
294 int rc = RTCritSectEnter(pArgs->pCritSect);
295 if (RT_FAILURE(rc))
296 {
297 printf("tstCritSect: FATAL FAILURE - Test 2 - thread %d, iteration %d: RTCritSectEnter -> %d\n", pArgs->iThread, i, rc);
298 ASMAtomicIncU32(&g_cErrors);
299 exit(g_cErrors);
300 return 1;
301 }
302 if (!u64TSStart)
303 u64TSStart = RTTimeNanoTS();
304
305 #if 0 /* We just check for sequences. */
306 /*
307 * Check release order.
308 */
309 if ((*pArgs->pu32Release % pArgs->cThreads) != pArgs->iThread)
310 {
311 printf("tstCritSect: FAILURE - Test 2 - thread %d, iteration %d: released as number %d (%d)\n",
312 pArgs->iThread, i, *pArgs->pu32Release % pArgs->cThreads, *pArgs->pu32Release);
313 ASMAtomicIncU32(&g_cErrors);
314 }
315 else
316 printf("tstCritSect: SUCCESS - Test 2 - thread %d, iteration %d: released as number %d (%d)\n",
317 pArgs->iThread, i, *pArgs->pu32Release % pArgs->cThreads, *pArgs->pu32Release);
318 #endif
319 pArgs->cTimes++;
320 ASMAtomicIncU32(pArgs->pu32Release);
321
322 /*
323 * Check distribution every now and again.
324 */
325#if 0
326 if (!(*pArgs->pu32Release % 879))
327 {
328 uint32_t u32Perfect = *pArgs->pu32Release / pArgs->cThreads;
329 for (int iThread = 0 ; iThread < (int)pArgs->cThreads; iThread++)
330 {
331 int cDiff = pArgs[iThread - pArgs->iThread].cTimes - u32Perfect;
332 if ((unsigned)RT_ABS(cDiff) > RT_MAX(u32Perfect / 10000, 2))
333 {
334 printf("tstCritSect: FAILURE - bad distribution thread %d u32Perfect=%d cTimes=%d cDiff=%d (runtime)\n",
335 iThread, u32Perfect, pArgs[iThread - pArgs->iThread].cTimes, cDiff);
336 ASMAtomicIncU32(&g_cErrors);
337 }
338 }
339 }
340#endif
341 /*
342 * Check alone and make sure we stay inside here a while
343 * so the other guys can get ready.
344 */
345 uint32_t u32;
346 for (u32 = 0; u32 < pArgs->cCheckLoops; u32++)
347 {
348 if (*pArgs->pu32Alone != ~0U)
349 {
350 printf("tstCritSect: FATAL FAILURE - Test 2 - thread %d, iteration %d: not alone!!!\n", pArgs->iThread, i);
351 AssertReleaseMsgFailed(("Not alone!\n"));
352 ASMAtomicIncU32(&g_cErrors);
353 exit(g_cErrors);
354 return 1;
355 }
356 }
357 ASMAtomicCmpXchgU32(pArgs->pu32Alone, pArgs->iThread, ~0);
358 for (u32 = 0; u32 < pArgs->cCheckLoops; u32++)
359 {
360 if (*pArgs->pu32Alone != pArgs->iThread)
361 {
362 printf("tstCritSect: FATAL FAILURE - Test 2 - thread %d, iteration %d: not alone!!!\n", pArgs->iThread, i);
363 AssertReleaseMsgFailed(("Not alone!\n"));
364 ASMAtomicIncU32(&g_cErrors);
365 exit(g_cErrors);
366 return 1;
367 }
368 }
369 ASMAtomicXchgU32(pArgs->pu32Alone, ~0);
370
371 /*
372 * Check for sequences.
373 */
374 if (*pArgs->pu32Prev == pArgs->iThread && pArgs->cThreads > 1)
375 ASMAtomicIncU32(pArgs->pcSeq);
376 else if ((*pArgs->pu32Prev + 1) % pArgs->cThreads != pArgs->iThread)
377 ASMAtomicIncU32(pArgs->pcReordered);
378 ASMAtomicXchgU32(pArgs->pu32Prev, pArgs->iThread);
379
380 /*
381 * Leave it.
382 */
383 rc = RTCritSectLeave(pArgs->pCritSect);
384 if (RT_FAILURE(rc))
385 {
386 printf("tstCritSect: FATAL FAILURE - Test 2 - thread %d, iteration %d: RTCritSectEnter -> %d\n", pArgs->iThread, i, rc);
387 ASMAtomicIncU32(&g_cErrors);
388 exit(g_cErrors);
389 return 1;
390 }
391 }
392
393 uint64_t u64TSEnd = RTTimeNanoTS(); NOREF(u64TSEnd);
394 ASMAtomicDecU32(pArgs->pcThreadRunning);
395 RTSemEventSignal(pArgs->EventDone);
396 Log2(("ThreadTest2: End - iThread=%d ThreadSelf=%p time=%lld\n", pArgs->iThread, ThreadSelf, u64TSEnd - u64TSStart));
397 return 0;
398}
399
400int Test2(unsigned cThreads, unsigned cIterations, unsigned cCheckLoops)
401{
402 printf("tstCritSect: Test2 - cThread=%d cIterations=%d cCheckLoops=%d...\n", cThreads, cIterations, cCheckLoops);
403
404 /*
405 * Create a critical section.
406 */
407 RTCRITSECT CritSect;
408 int rc = RTCritSectInit(&CritSect);
409 if (RT_FAILURE(rc))
410 {
411 printf("tstCritSect: FATAL FAILURE - Test 2 - RTCritSectInit -> %d\n", rc);
412 return 1;
413 }
414
415 /*
416 * Enter, leave and enter again.
417 */
418 rc = RTCritSectEnter(&CritSect);
419 if (RT_FAILURE(rc))
420 {
421 printf("tstCritSect: FATAL FAILURE - Test 2 - RTCritSectEnter -> %d\n", rc);
422 return 1;
423 }
424 rc = RTCritSectLeave(&CritSect);
425 if (RT_FAILURE(rc))
426 {
427 printf("tstCritSect: FATAL FAILURE - Test 2 - RTCritSectLeave -> %d\n", rc);
428 return 1;
429 }
430 rc = RTCritSectEnter(&CritSect);
431 if (RT_FAILURE(rc))
432 {
433 printf("tstCritSect: FATAL FAILURE - Test 2 - RTCritSectEnter -> %d (2nd)\n", rc);
434 return 1;
435 }
436
437 /*
438 * Now spawn threads which will go to sleep entering the critsect.
439 */
440 PTHREADTEST2ARGS paArgs = (PTHREADTEST2ARGS)calloc(sizeof(THREADTEST2ARGS), cThreads);
441 RTSEMEVENT EventDone;
442 rc = RTSemEventCreate(&EventDone);
443 uint32_t volatile u32Release = 0;
444 uint32_t volatile u32Alone = ~0;
445 uint32_t volatile u32Prev = ~0;
446 uint32_t volatile cSeq = 0;
447 uint32_t volatile cReordered = 0;
448 uint32_t volatile cThreadRunning = 0;
449 unsigned iThread;
450 for (iThread = 0; iThread < cThreads; iThread++)
451 {
452 paArgs[iThread].iThread = iThread;
453 paArgs[iThread].pCritSect = &CritSect;
454 paArgs[iThread].pu32Release = &u32Release;
455 paArgs[iThread].pu32Alone = &u32Alone;
456 paArgs[iThread].pu32Prev = &u32Prev;
457 paArgs[iThread].pcSeq = &cSeq;
458 paArgs[iThread].pcReordered = &cReordered;
459 paArgs[iThread].pcThreadRunning = &cThreadRunning;
460 paArgs[iThread].cTimes = 0;
461 paArgs[iThread].cThreads = cThreads;
462 paArgs[iThread].cIterations = cIterations;
463 paArgs[iThread].cCheckLoops = cCheckLoops;
464 paArgs[iThread].EventDone = EventDone;
465 int32_t iLock = LOCKERS(CritSect);
466 char szThread[17];
467 RTStrPrintf(szThread, sizeof(szThread), "T%d", iThread);
468 RTTHREAD Thread;
469 rc = RTThreadCreate(&Thread, ThreadTest2, &paArgs[iThread], 0, RTTHREADTYPE_DEFAULT, 0, szThread);
470 if (RT_FAILURE(rc))
471 {
472 printf("tstCritSect: FATAL FAILURE - Test 2 - RTThreadCreate -> %d\n", rc);
473 exit(1);
474 }
475 /* wait for it to get into waiting. */
476 while (LOCKERS(CritSect) == iLock)
477 RTThreadSleep(10);
478 RTThreadSleep(20);
479 }
480 printf("tstCritSect: Test2 - threads created...\n");
481
482 /*
483 * Now we'll release the threads and wait for all of them to quit.
484 */
485 u32Release = 0;
486 uint64_t u64TSStart = RTTimeNanoTS();
487 rc = RTCritSectLeave(&CritSect);
488 if (RT_FAILURE(rc))
489 {
490 printf("tstCritSect: FATAL FAILURE - RTCritSectLeave -> %d (2nd)\n", rc);
491 return 1;
492 }
493
494 while (cThreadRunning > 0)
495 RTSemEventWait(EventDone, RT_INDEFINITE_WAIT);
496 uint64_t u64TSEnd = RTTimeNanoTS();
497
498 /*
499 * Clean up and report results.
500 */
501 rc = RTCritSectDelete(&CritSect);
502 if (RT_FAILURE(rc))
503 {
504 printf("tstCritSect: FAILURE - RTCritSectDelete -> %d\n", rc);
505 ASMAtomicIncU32(&g_cErrors);
506 }
507
508 /* sequences */
509 if (cSeq > RT_MAX(u32Release / 10000, 1))
510 {
511 printf("tstCritSect: FAILURE - too many same thread sequences! cSeq=%d\n", cSeq);
512 ASMAtomicIncU32(&g_cErrors);
513 }
514
515 /* distribution caused by sequences / reordering. */
516 unsigned cDiffTotal = 0;
517 uint32_t u32Perfect = (u32Release + cThreads / 2) / cThreads;
518 for (iThread = 0; iThread < cThreads; iThread++)
519 {
520 int cDiff = paArgs[iThread].cTimes - u32Perfect;
521 if ((unsigned)RT_ABS(cDiff) > RT_MAX(u32Perfect / 10000, 2))
522 {
523 printf("tstCritSect: FAILURE - bad distribution thread %d u32Perfect=%d cTimes=%d cDiff=%d\n",
524 iThread, u32Perfect, paArgs[iThread].cTimes, cDiff);
525 ASMAtomicIncU32(&g_cErrors);
526 }
527 cDiffTotal += RT_ABS(cDiff);
528 }
529
530 uint32_t cMillies = (uint32_t)((u64TSEnd - u64TSStart) / 1000000);
531 printf("tstCritSect: Test2 - DONE. %d enter+leave in %dms cSeq=%d cReordered=%d cDiffTotal=%d\n",
532 u32Release, cMillies, cSeq, cReordered, cDiffTotal);
533 return 0;
534}
535
536
537int main(int argc, char *argv[])
538{
539 printf("tstCritSect: TESTING\n");
540
541 int rc = RTR3Init();
542 if (RT_FAILURE(rc))
543 {
544 printf("tstCritSect: FATAL FAILURE - RTR3Init -> %d\n", rc);
545 return 1;
546 }
547
548 printf("tstCritSect: Test1...\n");
549 if (Test1(1))
550 return 1;
551 if (Test1(3))
552 return 1;
553 if (Test1(10))
554 return 1;
555 if (Test1(63))
556 return 1;
557 if (Test2(1, 200000, 1000))
558 return 1;
559 if (Test2(2, 200000, 1000))
560 return 1;
561 if (Test2(3, 200000, 1000))
562 return 1;
563 if (Test2(4, 200000, 1000))
564 return 1;
565 if (Test2(5, 200000, 1000))
566 return 1;
567 if (Test2(7, 200000, 1000))
568 return 1;
569 if (Test2(67, 200000, 1000))
570 return 1;
571
572 /*
573 * Summary.
574 */
575 if (!g_cErrors)
576 printf("tstCritSect: SUCCESS\n");
577 else
578 printf("tstCritSect: FAILURE - %d errors\n", g_cErrors);
579
580 return !!g_cErrors;
581}
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