VirtualBox

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

Last change on this file since 6677 was 5999, checked in by vboxsync, 17 years ago

The Giant CDDL Dual-License Header Change.

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