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