|
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 /*********************************************************************** |
|
7 ** 1996 - Netscape Communications Corporation |
|
8 ** |
|
9 ** Name: cvar2.c |
|
10 ** |
|
11 ** Description: Simple test creates several local and global threads; |
|
12 ** half use a single,shared condvar, and the |
|
13 ** other half have their own condvar. The main thread then loops |
|
14 ** notifying them to wakeup. |
|
15 ** |
|
16 ** Modification History: |
|
17 ** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. |
|
18 ** The debug mode will print all of the printfs associated with this test. |
|
19 ** The regress mode will be the default mode. Since the regress tool limits |
|
20 ** the output to a one line status:PASS or FAIL,all of the printf statements |
|
21 ** have been handled with an if (debug_mode) statement. |
|
22 ***********************************************************************/ |
|
23 |
|
24 #include "nspr.h" |
|
25 #include "plerror.h" |
|
26 #include "plgetopt.h" |
|
27 |
|
28 #include <stdio.h> |
|
29 #include <stdlib.h> |
|
30 #include <string.h> |
|
31 |
|
32 int _debug_on = 0; |
|
33 #define DPRINTF(arg) if (_debug_on) printf arg |
|
34 |
|
35 #define DEFAULT_COUNT 100 |
|
36 #define DEFAULT_THREADS 5 |
|
37 PRInt32 count = DEFAULT_COUNT; |
|
38 |
|
39 typedef struct threadinfo { |
|
40 PRThread *thread; |
|
41 PRInt32 id; |
|
42 PRBool internal; |
|
43 PRInt32 *tcount; |
|
44 PRLock *lock; |
|
45 PRCondVar *cvar; |
|
46 PRIntervalTime timeout; |
|
47 PRInt32 loops; |
|
48 |
|
49 PRLock *exitlock; |
|
50 PRCondVar *exitcvar; |
|
51 PRInt32 *exitcount; |
|
52 } threadinfo; |
|
53 |
|
54 /* |
|
55 ** Make exitcount, tcount static. for Win16. |
|
56 */ |
|
57 static PRInt32 exitcount=0; |
|
58 static PRInt32 tcount=0; |
|
59 |
|
60 |
|
61 /* Thread that gets notified; many threads share the same condvar */ |
|
62 void PR_CALLBACK |
|
63 SharedCondVarThread(void *_info) |
|
64 { |
|
65 threadinfo *info = (threadinfo *)_info; |
|
66 PRInt32 index; |
|
67 |
|
68 for (index=0; index<info->loops; index++) { |
|
69 PR_Lock(info->lock); |
|
70 if (*info->tcount == 0) |
|
71 PR_WaitCondVar(info->cvar, info->timeout); |
|
72 #if 0 |
|
73 printf("shared thread %ld notified in loop %ld\n", info->id, index); |
|
74 #endif |
|
75 (*info->tcount)--; |
|
76 PR_Unlock(info->lock); |
|
77 |
|
78 PR_Lock(info->exitlock); |
|
79 (*info->exitcount)++; |
|
80 PR_NotifyCondVar(info->exitcvar); |
|
81 PR_Unlock(info->exitlock); |
|
82 } |
|
83 #if 0 |
|
84 printf("shared thread %ld terminating\n", info->id); |
|
85 #endif |
|
86 } |
|
87 |
|
88 /* Thread that gets notified; no other threads use the same condvar */ |
|
89 void PR_CALLBACK |
|
90 PrivateCondVarThread(void *_info) |
|
91 { |
|
92 threadinfo *info = (threadinfo *)_info; |
|
93 PRInt32 index; |
|
94 |
|
95 for (index=0; index<info->loops; index++) { |
|
96 PR_Lock(info->lock); |
|
97 if (*info->tcount == 0) { |
|
98 DPRINTF(("PrivateCondVarThread: thread 0x%lx waiting on cvar = 0x%lx\n", |
|
99 PR_GetCurrentThread(), info->cvar)); |
|
100 PR_WaitCondVar(info->cvar, info->timeout); |
|
101 } |
|
102 #if 0 |
|
103 printf("solo thread %ld notified in loop %ld\n", info->id, index); |
|
104 #endif |
|
105 (*info->tcount)--; |
|
106 PR_Unlock(info->lock); |
|
107 |
|
108 PR_Lock(info->exitlock); |
|
109 (*info->exitcount)++; |
|
110 PR_NotifyCondVar(info->exitcvar); |
|
111 DPRINTF(("PrivateCondVarThread: thread 0x%lx notified exitcvar = 0x%lx cnt = %ld\n", |
|
112 PR_GetCurrentThread(), info->exitcvar,(*info->exitcount))); |
|
113 PR_Unlock(info->exitlock); |
|
114 } |
|
115 #if 0 |
|
116 printf("solo thread %ld terminating\n", info->id); |
|
117 #endif |
|
118 } |
|
119 |
|
120 void |
|
121 CreateTestThread(threadinfo *info, |
|
122 PRInt32 id, |
|
123 PRLock *lock, |
|
124 PRCondVar *cvar, |
|
125 PRInt32 loops, |
|
126 PRIntervalTime timeout, |
|
127 PRInt32 *tcount, |
|
128 PRLock *exitlock, |
|
129 PRCondVar *exitcvar, |
|
130 PRInt32 *exitcount, |
|
131 PRBool shared, |
|
132 PRThreadScope scope) |
|
133 { |
|
134 info->id = id; |
|
135 info->internal = (shared) ? PR_FALSE : PR_TRUE; |
|
136 info->lock = lock; |
|
137 info->cvar = cvar; |
|
138 info->loops = loops; |
|
139 info->timeout = timeout; |
|
140 info->tcount = tcount; |
|
141 info->exitlock = exitlock; |
|
142 info->exitcvar = exitcvar; |
|
143 info->exitcount = exitcount; |
|
144 info->thread = PR_CreateThread( |
|
145 PR_USER_THREAD, |
|
146 shared?SharedCondVarThread:PrivateCondVarThread, |
|
147 info, |
|
148 PR_PRIORITY_NORMAL, |
|
149 scope, |
|
150 PR_JOINABLE_THREAD, |
|
151 0); |
|
152 if (!info->thread) |
|
153 PL_PrintError("error creating thread\n"); |
|
154 } |
|
155 |
|
156 |
|
157 void |
|
158 CondVarTestSUU(void *_arg) |
|
159 { |
|
160 PRInt32 arg = (PRInt32)_arg; |
|
161 PRInt32 index, loops; |
|
162 threadinfo *list; |
|
163 PRLock *sharedlock; |
|
164 PRCondVar *sharedcvar; |
|
165 PRLock *exitlock; |
|
166 PRCondVar *exitcvar; |
|
167 |
|
168 exitcount=0; |
|
169 tcount=0; |
|
170 list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4)); |
|
171 |
|
172 sharedlock = PR_NewLock(); |
|
173 sharedcvar = PR_NewCondVar(sharedlock); |
|
174 exitlock = PR_NewLock(); |
|
175 exitcvar = PR_NewCondVar(exitlock); |
|
176 |
|
177 /* Create the threads */ |
|
178 for(index=0; index<arg; ) { |
|
179 CreateTestThread(&list[index], |
|
180 index, |
|
181 sharedlock, |
|
182 sharedcvar, |
|
183 count, |
|
184 PR_INTERVAL_NO_TIMEOUT, |
|
185 &tcount, |
|
186 exitlock, |
|
187 exitcvar, |
|
188 &exitcount, |
|
189 PR_TRUE, |
|
190 PR_LOCAL_THREAD); |
|
191 index++; |
|
192 DPRINTF(("CondVarTestSUU: created thread 0x%lx\n",list[index].thread)); |
|
193 } |
|
194 |
|
195 for (loops = 0; loops < count; loops++) { |
|
196 /* Notify the threads */ |
|
197 for(index=0; index<(arg); index++) { |
|
198 PR_Lock(list[index].lock); |
|
199 (*list[index].tcount)++; |
|
200 PR_NotifyCondVar(list[index].cvar); |
|
201 PR_Unlock(list[index].lock); |
|
202 DPRINTF(("PrivateCondVarThread: thread 0x%lx notified cvar = 0x%lx\n", |
|
203 PR_GetCurrentThread(), list[index].cvar)); |
|
204 } |
|
205 |
|
206 /* Wait for threads to finish */ |
|
207 PR_Lock(exitlock); |
|
208 while(exitcount < arg) |
|
209 PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60)); |
|
210 PR_ASSERT(exitcount >= arg); |
|
211 exitcount -= arg; |
|
212 PR_Unlock(exitlock); |
|
213 } |
|
214 |
|
215 /* Join all the threads */ |
|
216 for(index=0; index<(arg); index++) |
|
217 PR_JoinThread(list[index].thread); |
|
218 |
|
219 PR_DestroyCondVar(sharedcvar); |
|
220 PR_DestroyLock(sharedlock); |
|
221 PR_DestroyCondVar(exitcvar); |
|
222 PR_DestroyLock(exitlock); |
|
223 |
|
224 PR_DELETE(list); |
|
225 } |
|
226 |
|
227 void |
|
228 CondVarTestSUK(void *_arg) |
|
229 { |
|
230 PRInt32 arg = (PRInt32)_arg; |
|
231 PRInt32 index, loops; |
|
232 threadinfo *list; |
|
233 PRLock *sharedlock; |
|
234 PRCondVar *sharedcvar; |
|
235 PRLock *exitlock; |
|
236 PRCondVar *exitcvar; |
|
237 exitcount=0; |
|
238 tcount=0; |
|
239 |
|
240 list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4)); |
|
241 |
|
242 sharedlock = PR_NewLock(); |
|
243 sharedcvar = PR_NewCondVar(sharedlock); |
|
244 exitlock = PR_NewLock(); |
|
245 exitcvar = PR_NewCondVar(exitlock); |
|
246 |
|
247 /* Create the threads */ |
|
248 for(index=0; index<arg; ) { |
|
249 CreateTestThread(&list[index], |
|
250 index, |
|
251 sharedlock, |
|
252 sharedcvar, |
|
253 count, |
|
254 PR_INTERVAL_NO_TIMEOUT, |
|
255 &tcount, |
|
256 exitlock, |
|
257 exitcvar, |
|
258 &exitcount, |
|
259 PR_TRUE, |
|
260 PR_GLOBAL_THREAD); |
|
261 index++; |
|
262 } |
|
263 |
|
264 for (loops = 0; loops < count; loops++) { |
|
265 /* Notify the threads */ |
|
266 for(index=0; index<(arg); index++) { |
|
267 |
|
268 PR_Lock(list[index].lock); |
|
269 (*list[index].tcount)++; |
|
270 PR_NotifyCondVar(list[index].cvar); |
|
271 PR_Unlock(list[index].lock); |
|
272 } |
|
273 |
|
274 #if 0 |
|
275 printf("wait for threads to be done\n"); |
|
276 #endif |
|
277 /* Wait for threads to finish */ |
|
278 PR_Lock(exitlock); |
|
279 while(exitcount < arg) |
|
280 PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60)); |
|
281 PR_ASSERT(exitcount >= arg); |
|
282 exitcount -= arg; |
|
283 PR_Unlock(exitlock); |
|
284 #if 0 |
|
285 printf("threads ready\n"); |
|
286 #endif |
|
287 } |
|
288 |
|
289 /* Join all the threads */ |
|
290 for(index=0; index<(arg); index++) |
|
291 PR_JoinThread(list[index].thread); |
|
292 |
|
293 PR_DestroyCondVar(sharedcvar); |
|
294 PR_DestroyLock(sharedlock); |
|
295 PR_DestroyCondVar(exitcvar); |
|
296 PR_DestroyLock(exitlock); |
|
297 |
|
298 PR_DELETE(list); |
|
299 } |
|
300 |
|
301 void |
|
302 CondVarTestPUU(void *_arg) |
|
303 { |
|
304 PRInt32 arg = (PRInt32)_arg; |
|
305 PRInt32 index, loops; |
|
306 threadinfo *list; |
|
307 PRLock *sharedlock; |
|
308 PRCondVar *sharedcvar; |
|
309 PRLock *exitlock; |
|
310 PRCondVar *exitcvar; |
|
311 PRInt32 *tcount, *saved_tcount; |
|
312 |
|
313 exitcount=0; |
|
314 list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4)); |
|
315 saved_tcount = tcount = (PRInt32 *)PR_CALLOC(sizeof(*tcount) * (arg * 4)); |
|
316 |
|
317 sharedlock = PR_NewLock(); |
|
318 sharedcvar = PR_NewCondVar(sharedlock); |
|
319 exitlock = PR_NewLock(); |
|
320 exitcvar = PR_NewCondVar(exitlock); |
|
321 |
|
322 /* Create the threads */ |
|
323 for(index=0; index<arg; ) { |
|
324 list[index].lock = PR_NewLock(); |
|
325 list[index].cvar = PR_NewCondVar(list[index].lock); |
|
326 CreateTestThread(&list[index], |
|
327 index, |
|
328 list[index].lock, |
|
329 list[index].cvar, |
|
330 count, |
|
331 PR_INTERVAL_NO_TIMEOUT, |
|
332 tcount, |
|
333 exitlock, |
|
334 exitcvar, |
|
335 &exitcount, |
|
336 PR_FALSE, |
|
337 PR_LOCAL_THREAD); |
|
338 |
|
339 DPRINTF(("CondVarTestPUU: created thread 0x%lx\n",list[index].thread)); |
|
340 index++; |
|
341 tcount++; |
|
342 } |
|
343 |
|
344 for (loops = 0; loops < count; loops++) { |
|
345 /* Notify the threads */ |
|
346 for(index=0; index<(arg); index++) { |
|
347 |
|
348 PR_Lock(list[index].lock); |
|
349 (*list[index].tcount)++; |
|
350 PR_NotifyCondVar(list[index].cvar); |
|
351 PR_Unlock(list[index].lock); |
|
352 } |
|
353 |
|
354 PR_Lock(exitlock); |
|
355 /* Wait for threads to finish */ |
|
356 while(exitcount < arg) { |
|
357 DPRINTF(("CondVarTestPUU: thread 0x%lx waiting on exitcvar = 0x%lx cnt = %ld\n", |
|
358 PR_GetCurrentThread(), exitcvar, exitcount)); |
|
359 PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60)); |
|
360 } |
|
361 PR_ASSERT(exitcount >= arg); |
|
362 exitcount -= arg; |
|
363 PR_Unlock(exitlock); |
|
364 } |
|
365 |
|
366 /* Join all the threads */ |
|
367 for(index=0; index<(arg); index++) { |
|
368 DPRINTF(("CondVarTestPUU: joining thread 0x%lx\n",list[index].thread)); |
|
369 PR_JoinThread(list[index].thread); |
|
370 if (list[index].internal) { |
|
371 PR_Lock(list[index].lock); |
|
372 PR_DestroyCondVar(list[index].cvar); |
|
373 PR_Unlock(list[index].lock); |
|
374 PR_DestroyLock(list[index].lock); |
|
375 } |
|
376 } |
|
377 |
|
378 PR_DestroyCondVar(sharedcvar); |
|
379 PR_DestroyLock(sharedlock); |
|
380 PR_DestroyCondVar(exitcvar); |
|
381 PR_DestroyLock(exitlock); |
|
382 |
|
383 PR_DELETE(list); |
|
384 PR_DELETE(saved_tcount); |
|
385 } |
|
386 |
|
387 void |
|
388 CondVarTestPUK(void *_arg) |
|
389 { |
|
390 PRInt32 arg = (PRInt32)_arg; |
|
391 PRInt32 index, loops; |
|
392 threadinfo *list; |
|
393 PRLock *sharedlock; |
|
394 PRCondVar *sharedcvar; |
|
395 PRLock *exitlock; |
|
396 PRCondVar *exitcvar; |
|
397 PRInt32 *tcount, *saved_tcount; |
|
398 |
|
399 exitcount=0; |
|
400 list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4)); |
|
401 saved_tcount = tcount = (PRInt32 *)PR_CALLOC(sizeof(*tcount) * (arg * 4)); |
|
402 |
|
403 sharedlock = PR_NewLock(); |
|
404 sharedcvar = PR_NewCondVar(sharedlock); |
|
405 exitlock = PR_NewLock(); |
|
406 exitcvar = PR_NewCondVar(exitlock); |
|
407 |
|
408 /* Create the threads */ |
|
409 for(index=0; index<arg; ) { |
|
410 list[index].lock = PR_NewLock(); |
|
411 list[index].cvar = PR_NewCondVar(list[index].lock); |
|
412 CreateTestThread(&list[index], |
|
413 index, |
|
414 list[index].lock, |
|
415 list[index].cvar, |
|
416 count, |
|
417 PR_INTERVAL_NO_TIMEOUT, |
|
418 tcount, |
|
419 exitlock, |
|
420 exitcvar, |
|
421 &exitcount, |
|
422 PR_FALSE, |
|
423 PR_GLOBAL_THREAD); |
|
424 |
|
425 index++; |
|
426 tcount++; |
|
427 } |
|
428 |
|
429 for (loops = 0; loops < count; loops++) { |
|
430 /* Notify the threads */ |
|
431 for(index=0; index<(arg); index++) { |
|
432 |
|
433 PR_Lock(list[index].lock); |
|
434 (*list[index].tcount)++; |
|
435 PR_NotifyCondVar(list[index].cvar); |
|
436 PR_Unlock(list[index].lock); |
|
437 } |
|
438 |
|
439 /* Wait for threads to finish */ |
|
440 PR_Lock(exitlock); |
|
441 while(exitcount < arg) |
|
442 PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60)); |
|
443 PR_ASSERT(exitcount >= arg); |
|
444 exitcount -= arg; |
|
445 PR_Unlock(exitlock); |
|
446 } |
|
447 |
|
448 /* Join all the threads */ |
|
449 for(index=0; index<(arg); index++) { |
|
450 PR_JoinThread(list[index].thread); |
|
451 if (list[index].internal) { |
|
452 PR_Lock(list[index].lock); |
|
453 PR_DestroyCondVar(list[index].cvar); |
|
454 PR_Unlock(list[index].lock); |
|
455 PR_DestroyLock(list[index].lock); |
|
456 } |
|
457 } |
|
458 |
|
459 PR_DestroyCondVar(sharedcvar); |
|
460 PR_DestroyLock(sharedlock); |
|
461 PR_DestroyCondVar(exitcvar); |
|
462 PR_DestroyLock(exitlock); |
|
463 |
|
464 PR_DELETE(list); |
|
465 PR_DELETE(saved_tcount); |
|
466 } |
|
467 |
|
468 void |
|
469 CondVarTest(void *_arg) |
|
470 { |
|
471 PRInt32 arg = (PRInt32)_arg; |
|
472 PRInt32 index, loops; |
|
473 threadinfo *list; |
|
474 PRLock *sharedlock; |
|
475 PRCondVar *sharedcvar; |
|
476 PRLock *exitlock; |
|
477 PRCondVar *exitcvar; |
|
478 PRInt32 *ptcount, *saved_ptcount; |
|
479 |
|
480 exitcount=0; |
|
481 tcount=0; |
|
482 list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4)); |
|
483 saved_ptcount = ptcount = (PRInt32 *)PR_CALLOC(sizeof(*ptcount) * (arg * 4)); |
|
484 |
|
485 sharedlock = PR_NewLock(); |
|
486 sharedcvar = PR_NewCondVar(sharedlock); |
|
487 exitlock = PR_NewLock(); |
|
488 exitcvar = PR_NewCondVar(exitlock); |
|
489 |
|
490 /* Create the threads */ |
|
491 for(index=0; index<arg*4; ) { |
|
492 CreateTestThread(&list[index], |
|
493 index, |
|
494 sharedlock, |
|
495 sharedcvar, |
|
496 count, |
|
497 PR_INTERVAL_NO_TIMEOUT, |
|
498 &tcount, |
|
499 exitlock, |
|
500 exitcvar, |
|
501 &exitcount, |
|
502 PR_TRUE, |
|
503 PR_LOCAL_THREAD); |
|
504 |
|
505 index++; |
|
506 CreateTestThread(&list[index], |
|
507 index, |
|
508 sharedlock, |
|
509 sharedcvar, |
|
510 count, |
|
511 PR_INTERVAL_NO_TIMEOUT, |
|
512 &tcount, |
|
513 exitlock, |
|
514 exitcvar, |
|
515 &exitcount, |
|
516 PR_TRUE, |
|
517 PR_GLOBAL_THREAD); |
|
518 |
|
519 index++; |
|
520 list[index].lock = PR_NewLock(); |
|
521 list[index].cvar = PR_NewCondVar(list[index].lock); |
|
522 CreateTestThread(&list[index], |
|
523 index, |
|
524 list[index].lock, |
|
525 list[index].cvar, |
|
526 count, |
|
527 PR_INTERVAL_NO_TIMEOUT, |
|
528 ptcount, |
|
529 exitlock, |
|
530 exitcvar, |
|
531 &exitcount, |
|
532 PR_FALSE, |
|
533 PR_LOCAL_THREAD); |
|
534 index++; |
|
535 ptcount++; |
|
536 list[index].lock = PR_NewLock(); |
|
537 list[index].cvar = PR_NewCondVar(list[index].lock); |
|
538 CreateTestThread(&list[index], |
|
539 index, |
|
540 list[index].lock, |
|
541 list[index].cvar, |
|
542 count, |
|
543 PR_INTERVAL_NO_TIMEOUT, |
|
544 ptcount, |
|
545 exitlock, |
|
546 exitcvar, |
|
547 &exitcount, |
|
548 PR_FALSE, |
|
549 PR_GLOBAL_THREAD); |
|
550 |
|
551 index++; |
|
552 ptcount++; |
|
553 } |
|
554 |
|
555 for (loops = 0; loops < count; loops++) { |
|
556 |
|
557 /* Notify the threads */ |
|
558 for(index=0; index<(arg*4); index++) { |
|
559 PR_Lock(list[index].lock); |
|
560 (*list[index].tcount)++; |
|
561 PR_NotifyCondVar(list[index].cvar); |
|
562 PR_Unlock(list[index].lock); |
|
563 } |
|
564 |
|
565 #if 0 |
|
566 printf("wait for threads done\n"); |
|
567 #endif |
|
568 |
|
569 /* Wait for threads to finish */ |
|
570 PR_Lock(exitlock); |
|
571 while(exitcount < arg*4) |
|
572 PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60)); |
|
573 PR_ASSERT(exitcount >= arg*4); |
|
574 exitcount -= arg*4; |
|
575 PR_Unlock(exitlock); |
|
576 #if 0 |
|
577 printf("threads ready\n"); |
|
578 #endif |
|
579 } |
|
580 |
|
581 /* Join all the threads */ |
|
582 for(index=0; index<(arg*4); index++) { |
|
583 PR_JoinThread(list[index].thread); |
|
584 if (list[index].internal) { |
|
585 PR_Lock(list[index].lock); |
|
586 PR_DestroyCondVar(list[index].cvar); |
|
587 PR_Unlock(list[index].lock); |
|
588 PR_DestroyLock(list[index].lock); |
|
589 } |
|
590 } |
|
591 |
|
592 PR_DestroyCondVar(sharedcvar); |
|
593 PR_DestroyLock(sharedlock); |
|
594 PR_DestroyCondVar(exitcvar); |
|
595 PR_DestroyLock(exitlock); |
|
596 |
|
597 PR_DELETE(list); |
|
598 PR_DELETE(saved_ptcount); |
|
599 } |
|
600 |
|
601 void |
|
602 CondVarTimeoutTest(void *_arg) |
|
603 { |
|
604 PRInt32 arg = (PRInt32)_arg; |
|
605 PRInt32 index, loops; |
|
606 threadinfo *list; |
|
607 PRLock *sharedlock; |
|
608 PRCondVar *sharedcvar; |
|
609 PRLock *exitlock; |
|
610 PRCondVar *exitcvar; |
|
611 |
|
612 list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4)); |
|
613 |
|
614 sharedlock = PR_NewLock(); |
|
615 sharedcvar = PR_NewCondVar(sharedlock); |
|
616 exitlock = PR_NewLock(); |
|
617 exitcvar = PR_NewCondVar(exitlock); |
|
618 |
|
619 /* Create the threads */ |
|
620 for(index=0; index<arg*4; ) { |
|
621 CreateTestThread(&list[index], |
|
622 index, |
|
623 sharedlock, |
|
624 sharedcvar, |
|
625 count, |
|
626 PR_MillisecondsToInterval(50), |
|
627 &tcount, |
|
628 exitlock, |
|
629 exitcvar, |
|
630 &exitcount, |
|
631 PR_TRUE, |
|
632 PR_LOCAL_THREAD); |
|
633 index++; |
|
634 CreateTestThread(&list[index], |
|
635 index, |
|
636 sharedlock, |
|
637 sharedcvar, |
|
638 count, |
|
639 PR_MillisecondsToInterval(50), |
|
640 &tcount, |
|
641 exitlock, |
|
642 exitcvar, |
|
643 &exitcount, |
|
644 PR_TRUE, |
|
645 PR_GLOBAL_THREAD); |
|
646 index++; |
|
647 list[index].lock = PR_NewLock(); |
|
648 list[index].cvar = PR_NewCondVar(list[index].lock); |
|
649 CreateTestThread(&list[index], |
|
650 index, |
|
651 list[index].lock, |
|
652 list[index].cvar, |
|
653 count, |
|
654 PR_MillisecondsToInterval(50), |
|
655 &tcount, |
|
656 exitlock, |
|
657 exitcvar, |
|
658 &exitcount, |
|
659 PR_FALSE, |
|
660 PR_LOCAL_THREAD); |
|
661 index++; |
|
662 |
|
663 list[index].lock = PR_NewLock(); |
|
664 list[index].cvar = PR_NewCondVar(list[index].lock); |
|
665 CreateTestThread(&list[index], |
|
666 index, |
|
667 list[index].lock, |
|
668 list[index].cvar, |
|
669 count, |
|
670 PR_MillisecondsToInterval(50), |
|
671 &tcount, |
|
672 exitlock, |
|
673 exitcvar, |
|
674 &exitcount, |
|
675 PR_FALSE, |
|
676 PR_GLOBAL_THREAD); |
|
677 |
|
678 index++; |
|
679 } |
|
680 |
|
681 for (loops = 0; loops < count; loops++) { |
|
682 |
|
683 /* Wait for threads to finish */ |
|
684 PR_Lock(exitlock); |
|
685 while(exitcount < arg*4) |
|
686 PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60)); |
|
687 PR_ASSERT(exitcount >= arg*4); |
|
688 exitcount -= arg*4; |
|
689 PR_Unlock(exitlock); |
|
690 } |
|
691 |
|
692 |
|
693 /* Join all the threads */ |
|
694 for(index=0; index<(arg*4); index++) { |
|
695 PR_JoinThread(list[index].thread); |
|
696 if (list[index].internal) { |
|
697 PR_Lock(list[index].lock); |
|
698 PR_DestroyCondVar(list[index].cvar); |
|
699 PR_Unlock(list[index].lock); |
|
700 PR_DestroyLock(list[index].lock); |
|
701 } |
|
702 } |
|
703 |
|
704 PR_DestroyCondVar(sharedcvar); |
|
705 PR_DestroyLock(sharedlock); |
|
706 PR_DestroyCondVar(exitcvar); |
|
707 PR_DestroyLock(exitlock); |
|
708 |
|
709 PR_DELETE(list); |
|
710 } |
|
711 |
|
712 void |
|
713 CondVarMixedTest(void *_arg) |
|
714 { |
|
715 PRInt32 arg = (PRInt32)_arg; |
|
716 PRInt32 index, loops; |
|
717 threadinfo *list; |
|
718 PRLock *sharedlock; |
|
719 PRCondVar *sharedcvar; |
|
720 PRLock *exitlock; |
|
721 PRCondVar *exitcvar; |
|
722 PRInt32 *ptcount; |
|
723 |
|
724 exitcount=0; |
|
725 tcount=0; |
|
726 list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4)); |
|
727 ptcount = (PRInt32 *)PR_CALLOC(sizeof(*ptcount) * (arg * 4)); |
|
728 |
|
729 sharedlock = PR_NewLock(); |
|
730 sharedcvar = PR_NewCondVar(sharedlock); |
|
731 exitlock = PR_NewLock(); |
|
732 exitcvar = PR_NewCondVar(exitlock); |
|
733 |
|
734 /* Create the threads */ |
|
735 for(index=0; index<arg*4; ) { |
|
736 CreateTestThread(&list[index], |
|
737 index, |
|
738 sharedlock, |
|
739 sharedcvar, |
|
740 count, |
|
741 PR_MillisecondsToInterval(50), |
|
742 &tcount, |
|
743 exitlock, |
|
744 exitcvar, |
|
745 &exitcount, |
|
746 PR_TRUE, |
|
747 PR_LOCAL_THREAD); |
|
748 index++; |
|
749 CreateTestThread(&list[index], |
|
750 index, |
|
751 sharedlock, |
|
752 sharedcvar, |
|
753 count, |
|
754 PR_MillisecondsToInterval(50), |
|
755 &tcount, |
|
756 exitlock, |
|
757 exitcvar, |
|
758 &exitcount, |
|
759 PR_TRUE, |
|
760 PR_GLOBAL_THREAD); |
|
761 index++; |
|
762 list[index].lock = PR_NewLock(); |
|
763 list[index].cvar = PR_NewCondVar(list[index].lock); |
|
764 CreateTestThread(&list[index], |
|
765 index, |
|
766 list[index].lock, |
|
767 list[index].cvar, |
|
768 count, |
|
769 PR_MillisecondsToInterval(50), |
|
770 ptcount, |
|
771 exitlock, |
|
772 exitcvar, |
|
773 &exitcount, |
|
774 PR_FALSE, |
|
775 PR_LOCAL_THREAD); |
|
776 index++; |
|
777 ptcount++; |
|
778 |
|
779 list[index].lock = PR_NewLock(); |
|
780 list[index].cvar = PR_NewCondVar(list[index].lock); |
|
781 CreateTestThread(&list[index], |
|
782 index, |
|
783 list[index].lock, |
|
784 list[index].cvar, |
|
785 count, |
|
786 PR_MillisecondsToInterval(50), |
|
787 ptcount, |
|
788 exitlock, |
|
789 exitcvar, |
|
790 &exitcount, |
|
791 PR_FALSE, |
|
792 PR_GLOBAL_THREAD); |
|
793 index++; |
|
794 ptcount++; |
|
795 } |
|
796 |
|
797 |
|
798 /* Notify every 3rd thread */ |
|
799 for (loops = 0; loops < count; loops++) { |
|
800 |
|
801 /* Notify the threads */ |
|
802 for(index=0; index<(arg*4); index+=3) { |
|
803 |
|
804 PR_Lock(list[index].lock); |
|
805 *list[index].tcount++; |
|
806 PR_NotifyCondVar(list[index].cvar); |
|
807 PR_Unlock(list[index].lock); |
|
808 |
|
809 } |
|
810 /* Wait for threads to finish */ |
|
811 PR_Lock(exitlock); |
|
812 while(exitcount < arg*4) |
|
813 PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60)); |
|
814 PR_ASSERT(exitcount >= arg*4); |
|
815 exitcount -= arg*4; |
|
816 PR_Unlock(exitlock); |
|
817 } |
|
818 |
|
819 /* Join all the threads */ |
|
820 for(index=0; index<(arg*4); index++) { |
|
821 PR_JoinThread(list[index].thread); |
|
822 if (list[index].internal) { |
|
823 PR_Lock(list[index].lock); |
|
824 PR_DestroyCondVar(list[index].cvar); |
|
825 PR_Unlock(list[index].lock); |
|
826 PR_DestroyLock(list[index].lock); |
|
827 } |
|
828 } |
|
829 |
|
830 PR_DestroyCondVar(sharedcvar); |
|
831 PR_DestroyLock(sharedlock); |
|
832 |
|
833 PR_DELETE(list); |
|
834 } |
|
835 |
|
836 void |
|
837 CondVarCombinedTest(void *arg) |
|
838 { |
|
839 PRThread *threads[3]; |
|
840 |
|
841 threads[0] = PR_CreateThread(PR_USER_THREAD, |
|
842 CondVarTest, |
|
843 (void *)arg, |
|
844 PR_PRIORITY_NORMAL, |
|
845 PR_GLOBAL_THREAD, |
|
846 PR_JOINABLE_THREAD, |
|
847 0); |
|
848 threads[1] = PR_CreateThread(PR_USER_THREAD, |
|
849 CondVarTimeoutTest, |
|
850 (void *)arg, |
|
851 PR_PRIORITY_NORMAL, |
|
852 PR_GLOBAL_THREAD, |
|
853 PR_JOINABLE_THREAD, |
|
854 0); |
|
855 threads[2] = PR_CreateThread(PR_USER_THREAD, |
|
856 CondVarMixedTest, |
|
857 (void *)arg, |
|
858 PR_PRIORITY_NORMAL, |
|
859 PR_GLOBAL_THREAD, |
|
860 PR_JOINABLE_THREAD, |
|
861 0); |
|
862 |
|
863 PR_JoinThread(threads[0]); |
|
864 PR_JoinThread(threads[1]); |
|
865 PR_JoinThread(threads[2]); |
|
866 } |
|
867 |
|
868 /************************************************************************/ |
|
869 |
|
870 static void Measure(void (*func)(void *), PRInt32 arg, const char *msg) |
|
871 { |
|
872 PRIntervalTime start, stop; |
|
873 double d; |
|
874 |
|
875 start = PR_IntervalNow(); |
|
876 (*func)((void *)arg); |
|
877 stop = PR_IntervalNow(); |
|
878 |
|
879 d = (double)PR_IntervalToMicroseconds(stop - start); |
|
880 |
|
881 printf("%40s: %6.2f usec\n", msg, d / count); |
|
882 } |
|
883 |
|
884 static PRIntn PR_CALLBACK RealMain(int argc, char **argv) |
|
885 { |
|
886 PRInt32 threads, default_threads = DEFAULT_THREADS; |
|
887 PLOptStatus os; |
|
888 PLOptState *opt = PL_CreateOptState(argc, argv, "vc:t:"); |
|
889 while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) |
|
890 { |
|
891 if (PL_OPT_BAD == os) continue; |
|
892 switch (opt->option) |
|
893 { |
|
894 case 'v': /* debug mode */ |
|
895 _debug_on = 1; |
|
896 break; |
|
897 case 'c': /* loop counter */ |
|
898 count = atoi(opt->value); |
|
899 break; |
|
900 case 't': /* number of threads involved */ |
|
901 default_threads = atoi(opt->value); |
|
902 break; |
|
903 default: |
|
904 break; |
|
905 } |
|
906 } |
|
907 PL_DestroyOptState(opt); |
|
908 |
|
909 if (0 == count) count = DEFAULT_COUNT; |
|
910 if (0 == default_threads) default_threads = DEFAULT_THREADS; |
|
911 |
|
912 printf("\n\ |
|
913 CondVar Test: \n\ |
|
914 \n\ |
|
915 Simple test creates several local and global threads; half use a single,\n\ |
|
916 shared condvar, and the other half have their own condvar. The main \n\ |
|
917 thread then loops notifying them to wakeup. \n\ |
|
918 \n\ |
|
919 The timeout test is very similar except that the threads are not \n\ |
|
920 notified. They will all wakeup on a 1 second timeout. \n\ |
|
921 \n\ |
|
922 The mixed test combines the simple test and the timeout test; every \n\ |
|
923 third thread is notified, the other threads are expected to timeout \n\ |
|
924 correctly. \n\ |
|
925 \n\ |
|
926 Lastly, the combined test creates a thread for each of the above three \n\ |
|
927 cases and they all run simultaneously. \n\ |
|
928 \n\ |
|
929 This test is run with %d, %d, %d, and %d threads of each type.\n\n", |
|
930 default_threads, default_threads*2, default_threads*3, default_threads*4); |
|
931 |
|
932 PR_SetConcurrency(2); |
|
933 |
|
934 for (threads = default_threads; threads < default_threads*5; threads+=default_threads) { |
|
935 printf("\n%ld Thread tests\n", threads); |
|
936 Measure(CondVarTestSUU, threads, "Condvar simple test shared UU"); |
|
937 Measure(CondVarTestSUK, threads, "Condvar simple test shared UK"); |
|
938 Measure(CondVarTestPUU, threads, "Condvar simple test priv UU"); |
|
939 Measure(CondVarTestPUK, threads, "Condvar simple test priv UK"); |
|
940 Measure(CondVarTest, threads, "Condvar simple test All"); |
|
941 Measure(CondVarTimeoutTest, threads, "Condvar timeout test"); |
|
942 #if 0 |
|
943 Measure(CondVarMixedTest, threads, "Condvar mixed timeout test"); |
|
944 Measure(CondVarCombinedTest, threads, "Combined condvar test"); |
|
945 #endif |
|
946 } |
|
947 |
|
948 printf("PASS\n"); |
|
949 |
|
950 return 0; |
|
951 } |
|
952 |
|
953 int main(int argc, char **argv) |
|
954 { |
|
955 PRIntn rv; |
|
956 |
|
957 PR_STDIO_INIT(); |
|
958 rv = PR_Initialize(RealMain, argc, argv, 0); |
|
959 return rv; |
|
960 } /* main */ |