VirtualBox

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

Last change on this file since 5197 was 4071, checked in by vboxsync, 17 years ago

Biggest check-in ever. New source code headers for all (C) innotek files.

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