VirtualBox

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

Last change on this file since 2333 was 1, checked in by vboxsync, 55 years ago

import

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