Back to index

lightning-sunbird  0.9+nobinonly
cvar2.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Netscape Portable Runtime (NSPR).
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /***********************************************************************
00039 **  1996 - Netscape Communications Corporation
00040 **
00041 ** Name: cvar2.c
00042 **
00043 ** Description: Simple test creates several local and global threads;
00044 **              half use a single,shared condvar, and the
00045 **              other half have their own condvar. The main thread then loops
00046 **                          notifying them to wakeup. 
00047 **
00048 ** Modification History:
00049 ** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
00050 **              The debug mode will print all of the printfs associated with this test.
00051 **                    The regress mode will be the default mode. Since the regress tool limits
00052 **           the output to a one line status:PASS or FAIL,all of the printf statements
00053 **                    have been handled with an if (debug_mode) statement. 
00054 ***********************************************************************/
00055 
00056 #include "nspr.h"
00057 #include "plerror.h"
00058 #include "plgetopt.h"
00059 
00060 #include <stdio.h>
00061 #include <stdlib.h>
00062 #include <string.h>
00063 
00064 int _debug_on = 0;
00065 #define DPRINTF(arg) if (_debug_on) printf arg
00066 
00067 #ifdef XP_MAC
00068 #include "prlog.h"
00069 #define printf PR_LogPrint
00070 extern void SetupMacPrintfLog(char *logFile);
00071 #endif
00072 
00073 #define DEFAULT_COUNT   100
00074 #define DEFAULT_THREADS 5
00075 PRInt32 count = DEFAULT_COUNT;
00076 
00077 typedef struct threadinfo {
00078     PRThread        *thread;
00079     PRInt32          id;
00080     PRBool           internal;
00081     PRInt32         *tcount;
00082     PRLock          *lock;
00083     PRCondVar       *cvar;
00084     PRIntervalTime   timeout;
00085     PRInt32          loops;
00086 
00087     PRLock          *exitlock;
00088     PRCondVar       *exitcvar;
00089     PRInt32         *exitcount;
00090 } threadinfo;
00091 
00092 /*
00093 ** Make exitcount, tcount static. for Win16.
00094 */
00095 static PRInt32 exitcount=0;
00096 static PRInt32 tcount=0;
00097 
00098 
00099 /* Thread that gets notified; many threads share the same condvar */
00100 void PR_CALLBACK
00101 SharedCondVarThread(void *_info)
00102 {
00103     threadinfo *info = (threadinfo *)_info;
00104     PRInt32 index;
00105 
00106     for (index=0; index<info->loops; index++) {
00107         PR_Lock(info->lock);
00108         if (*info->tcount == 0)
00109             PR_WaitCondVar(info->cvar, info->timeout);
00110 #if 0
00111         printf("shared thread %ld notified in loop %ld\n", info->id, index);
00112 #endif
00113         (*info->tcount)--;
00114         PR_Unlock(info->lock);
00115 
00116         PR_Lock(info->exitlock);
00117         (*info->exitcount)++;
00118         PR_NotifyCondVar(info->exitcvar);
00119         PR_Unlock(info->exitlock);
00120     }
00121 #if 0
00122     printf("shared thread %ld terminating\n", info->id);
00123 #endif
00124 }
00125 
00126 /* Thread that gets notified; no other threads use the same condvar */
00127 void PR_CALLBACK
00128 PrivateCondVarThread(void *_info)
00129 {
00130     threadinfo *info = (threadinfo *)_info;
00131     PRInt32 index;
00132 
00133     for (index=0; index<info->loops; index++) {
00134         PR_Lock(info->lock);
00135         if (*info->tcount == 0) {
00136            DPRINTF(("PrivateCondVarThread: thread 0x%lx waiting on cvar = 0x%lx\n",
00137                             PR_GetCurrentThread(), info->cvar));
00138             PR_WaitCondVar(info->cvar, info->timeout);
00139        }
00140 #if 0
00141         printf("solo   thread %ld notified in loop %ld\n", info->id, index);
00142 #endif
00143         (*info->tcount)--;
00144         PR_Unlock(info->lock);
00145 
00146         PR_Lock(info->exitlock);
00147         (*info->exitcount)++;
00148         PR_NotifyCondVar(info->exitcvar);
00149 DPRINTF(("PrivateCondVarThread: thread 0x%lx notified exitcvar = 0x%lx cnt = %ld\n",
00150                      PR_GetCurrentThread(), info->exitcvar,(*info->exitcount)));
00151         PR_Unlock(info->exitlock);
00152     }
00153 #if 0
00154     printf("solo   thread %ld terminating\n", info->id);
00155 #endif
00156 }
00157 
00158 void 
00159 CreateTestThread(threadinfo *info, 
00160                  PRInt32 id,
00161                  PRLock *lock,
00162                  PRCondVar *cvar,
00163                  PRInt32 loops,
00164                  PRIntervalTime timeout,
00165                  PRInt32 *tcount,
00166                  PRLock *exitlock,
00167                  PRCondVar *exitcvar,
00168                  PRInt32 *exitcount,
00169                  PRBool shared, 
00170                  PRThreadScope scope)
00171 {
00172     info->id = id;
00173     info->internal = (shared) ? PR_FALSE : PR_TRUE;
00174     info->lock = lock;
00175     info->cvar = cvar;
00176     info->loops = loops;
00177     info->timeout = timeout;
00178     info->tcount = tcount;
00179     info->exitlock = exitlock;
00180     info->exitcvar = exitcvar;
00181     info->exitcount = exitcount;
00182     info->thread = PR_CreateThread(
00183                            PR_USER_THREAD,
00184                            shared?SharedCondVarThread:PrivateCondVarThread,
00185                            info,
00186                            PR_PRIORITY_NORMAL,
00187                            scope,
00188                            PR_JOINABLE_THREAD,
00189                            0);
00190     if (!info->thread)
00191         PL_PrintError("error creating thread\n");
00192 }
00193 
00194 
00195 void 
00196 CondVarTestSUU(void *_arg)
00197 {
00198     PRInt32 arg = (PRInt32)_arg;
00199     PRInt32 index, loops;
00200     threadinfo *list;
00201     PRLock *sharedlock;
00202     PRCondVar *sharedcvar;
00203     PRLock *exitlock;
00204     PRCondVar *exitcvar;
00205     
00206     exitcount=0;
00207     tcount=0;
00208     list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4));
00209 
00210     sharedlock = PR_NewLock();
00211     sharedcvar = PR_NewCondVar(sharedlock);
00212     exitlock = PR_NewLock();
00213     exitcvar = PR_NewCondVar(exitlock);
00214 
00215     /* Create the threads */
00216     for(index=0; index<arg; ) {
00217         CreateTestThread(&list[index],
00218                          index,
00219                          sharedlock,
00220                          sharedcvar,
00221                          count,
00222                          PR_INTERVAL_NO_TIMEOUT,
00223                          &tcount,
00224                          exitlock,
00225                          exitcvar,
00226                          &exitcount,
00227                          PR_TRUE,
00228                          PR_LOCAL_THREAD);
00229         index++;
00230        DPRINTF(("CondVarTestSUU: created thread 0x%lx\n",list[index].thread));
00231     }
00232 
00233     for (loops = 0; loops < count; loops++) {
00234         /* Notify the threads */
00235         for(index=0; index<(arg); index++) {
00236             PR_Lock(list[index].lock);
00237             (*list[index].tcount)++;
00238             PR_NotifyCondVar(list[index].cvar);
00239             PR_Unlock(list[index].lock);
00240            DPRINTF(("PrivateCondVarThread: thread 0x%lx notified cvar = 0x%lx\n",
00241                             PR_GetCurrentThread(), list[index].cvar));
00242         }
00243 
00244         /* Wait for threads to finish */
00245         PR_Lock(exitlock);
00246         while(exitcount < arg)
00247             PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60));
00248         PR_ASSERT(exitcount >= arg);
00249         exitcount -= arg;
00250         PR_Unlock(exitlock);
00251     }
00252 
00253     /* Join all the threads */
00254     for(index=0; index<(arg); index++) 
00255         PR_JoinThread(list[index].thread);
00256 
00257     PR_DestroyCondVar(sharedcvar);
00258     PR_DestroyLock(sharedlock);
00259     PR_DestroyCondVar(exitcvar);
00260     PR_DestroyLock(exitlock);
00261 
00262     PR_DELETE(list);
00263 }
00264 
00265 void 
00266 CondVarTestSUK(void *_arg)
00267 {
00268     PRInt32 arg = (PRInt32)_arg;
00269     PRInt32 index, loops;
00270     threadinfo *list;
00271     PRLock *sharedlock;
00272     PRCondVar *sharedcvar;
00273     PRLock *exitlock;
00274     PRCondVar *exitcvar;
00275     exitcount=0;
00276     tcount=0;
00277 
00278     list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4));
00279 
00280     sharedlock = PR_NewLock();
00281     sharedcvar = PR_NewCondVar(sharedlock);
00282     exitlock = PR_NewLock();
00283     exitcvar = PR_NewCondVar(exitlock);
00284 
00285     /* Create the threads */
00286     for(index=0; index<arg; ) {
00287         CreateTestThread(&list[index],
00288                          index,
00289                          sharedlock,
00290                          sharedcvar,
00291                          count,
00292                          PR_INTERVAL_NO_TIMEOUT,
00293                          &tcount,
00294                          exitlock,
00295                          exitcvar,
00296                          &exitcount,
00297                          PR_TRUE,
00298                          PR_GLOBAL_THREAD);
00299         index++;
00300     }
00301 
00302     for (loops = 0; loops < count; loops++) {
00303         /* Notify the threads */
00304         for(index=0; index<(arg); index++) {
00305 
00306             PR_Lock(list[index].lock);
00307             (*list[index].tcount)++;
00308             PR_NotifyCondVar(list[index].cvar);
00309             PR_Unlock(list[index].lock);
00310         }
00311 
00312 #if 0
00313         printf("wait for threads to be done\n");
00314 #endif
00315         /* Wait for threads to finish */
00316         PR_Lock(exitlock);
00317         while(exitcount < arg)
00318             PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60));
00319         PR_ASSERT(exitcount >= arg);
00320         exitcount -= arg;
00321         PR_Unlock(exitlock);
00322 #if 0
00323         printf("threads ready\n");
00324 #endif
00325     }
00326 
00327     /* Join all the threads */
00328     for(index=0; index<(arg); index++) 
00329         PR_JoinThread(list[index].thread);
00330 
00331     PR_DestroyCondVar(sharedcvar);
00332     PR_DestroyLock(sharedlock);
00333     PR_DestroyCondVar(exitcvar);
00334     PR_DestroyLock(exitlock);
00335 
00336     PR_DELETE(list);
00337 }
00338 
00339 void 
00340 CondVarTestPUU(void *_arg)
00341 {
00342     PRInt32 arg = (PRInt32)_arg;
00343     PRInt32 index, loops;
00344     threadinfo *list;
00345     PRLock *sharedlock;
00346     PRCondVar *sharedcvar;
00347     PRLock *exitlock;
00348     PRCondVar *exitcvar;
00349     PRInt32 *tcount, *saved_tcount;
00350 
00351     exitcount=0;
00352     list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4));
00353     saved_tcount = tcount = (PRInt32 *)PR_CALLOC(sizeof(*tcount) * (arg * 4));
00354 
00355     sharedlock = PR_NewLock();
00356     sharedcvar = PR_NewCondVar(sharedlock);
00357     exitlock = PR_NewLock();
00358     exitcvar = PR_NewCondVar(exitlock);
00359 
00360     /* Create the threads */
00361     for(index=0; index<arg; ) {
00362         list[index].lock = PR_NewLock();
00363         list[index].cvar = PR_NewCondVar(list[index].lock);
00364         CreateTestThread(&list[index],
00365                          index,
00366                          list[index].lock,
00367                          list[index].cvar,
00368                          count,
00369                          PR_INTERVAL_NO_TIMEOUT,
00370                          tcount,
00371                          exitlock,
00372                          exitcvar,
00373                          &exitcount,
00374                          PR_FALSE,
00375                          PR_LOCAL_THREAD);
00376 
00377        DPRINTF(("CondVarTestPUU: created thread 0x%lx\n",list[index].thread));
00378         index++;
00379        tcount++;
00380     }
00381 
00382     for (loops = 0; loops < count; loops++) {
00383         /* Notify the threads */
00384         for(index=0; index<(arg); index++) {
00385 
00386             PR_Lock(list[index].lock);
00387             (*list[index].tcount)++;
00388             PR_NotifyCondVar(list[index].cvar);
00389             PR_Unlock(list[index].lock);
00390         }
00391 
00392        PR_Lock(exitlock);
00393         /* Wait for threads to finish */
00394         while(exitcount < arg) {
00395 DPRINTF(("CondVarTestPUU: thread 0x%lx waiting on exitcvar = 0x%lx cnt = %ld\n",
00396                             PR_GetCurrentThread(), exitcvar, exitcount));
00397               PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60));
00398        }
00399         PR_ASSERT(exitcount >= arg);
00400         exitcount -= arg;
00401         PR_Unlock(exitlock);
00402     }
00403 
00404     /* Join all the threads */
00405     for(index=0; index<(arg); index++)  {
00406        DPRINTF(("CondVarTestPUU: joining thread 0x%lx\n",list[index].thread));
00407         PR_JoinThread(list[index].thread);
00408         if (list[index].internal) {
00409             PR_Lock(list[index].lock);
00410             PR_DestroyCondVar(list[index].cvar);
00411             PR_Unlock(list[index].lock);
00412             PR_DestroyLock(list[index].lock);
00413         }
00414     }
00415 
00416     PR_DestroyCondVar(sharedcvar);
00417     PR_DestroyLock(sharedlock);
00418     PR_DestroyCondVar(exitcvar);
00419     PR_DestroyLock(exitlock);
00420 
00421     PR_DELETE(list);
00422     PR_DELETE(saved_tcount);
00423 }
00424 
00425 void 
00426 CondVarTestPUK(void *_arg)
00427 {
00428     PRInt32 arg = (PRInt32)_arg;
00429     PRInt32 index, loops;
00430     threadinfo *list;
00431     PRLock *sharedlock;
00432     PRCondVar *sharedcvar;
00433     PRLock *exitlock;
00434     PRCondVar *exitcvar;
00435     PRInt32 *tcount, *saved_tcount;
00436 
00437     exitcount=0;
00438     list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4));
00439     saved_tcount = tcount = (PRInt32 *)PR_CALLOC(sizeof(*tcount) * (arg * 4));
00440 
00441     sharedlock = PR_NewLock();
00442     sharedcvar = PR_NewCondVar(sharedlock);
00443     exitlock = PR_NewLock();
00444     exitcvar = PR_NewCondVar(exitlock);
00445 
00446     /* Create the threads */
00447     for(index=0; index<arg; ) {
00448         list[index].lock = PR_NewLock();
00449         list[index].cvar = PR_NewCondVar(list[index].lock);
00450         CreateTestThread(&list[index],
00451                          index,
00452                          list[index].lock,
00453                          list[index].cvar,
00454                          count,
00455                          PR_INTERVAL_NO_TIMEOUT,
00456                          tcount,
00457                          exitlock,
00458                          exitcvar,
00459                          &exitcount,
00460                          PR_FALSE,
00461                          PR_GLOBAL_THREAD);
00462 
00463         index++;
00464         tcount++;
00465     }
00466 
00467     for (loops = 0; loops < count; loops++) {
00468         /* Notify the threads */
00469         for(index=0; index<(arg); index++) {
00470 
00471             PR_Lock(list[index].lock);
00472             (*list[index].tcount)++;
00473             PR_NotifyCondVar(list[index].cvar);
00474             PR_Unlock(list[index].lock);
00475         }
00476 
00477         /* Wait for threads to finish */
00478         PR_Lock(exitlock);
00479         while(exitcount < arg)
00480             PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60));
00481         PR_ASSERT(exitcount >= arg);
00482         exitcount -= arg;
00483         PR_Unlock(exitlock);
00484     }
00485 
00486     /* Join all the threads */
00487     for(index=0; index<(arg); index++) {
00488         PR_JoinThread(list[index].thread);
00489         if (list[index].internal) {
00490             PR_Lock(list[index].lock);
00491             PR_DestroyCondVar(list[index].cvar);
00492             PR_Unlock(list[index].lock);
00493             PR_DestroyLock(list[index].lock);
00494         }
00495     }
00496 
00497     PR_DestroyCondVar(sharedcvar);
00498     PR_DestroyLock(sharedlock);
00499     PR_DestroyCondVar(exitcvar);
00500     PR_DestroyLock(exitlock);
00501 
00502     PR_DELETE(list);
00503     PR_DELETE(saved_tcount);
00504 }
00505 
00506 void 
00507 CondVarTest(void *_arg)
00508 {
00509     PRInt32 arg = (PRInt32)_arg;
00510     PRInt32 index, loops;
00511     threadinfo *list;
00512     PRLock *sharedlock;
00513     PRCondVar *sharedcvar;
00514     PRLock *exitlock;
00515     PRCondVar *exitcvar;
00516     PRInt32 *ptcount, *saved_ptcount;
00517 
00518     exitcount=0;
00519     tcount=0;
00520     list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4));
00521     saved_ptcount = ptcount = (PRInt32 *)PR_CALLOC(sizeof(*ptcount) * (arg * 4));
00522 
00523     sharedlock = PR_NewLock();
00524     sharedcvar = PR_NewCondVar(sharedlock);
00525     exitlock = PR_NewLock();
00526     exitcvar = PR_NewCondVar(exitlock);
00527 
00528     /* Create the threads */
00529     for(index=0; index<arg*4; ) {
00530         CreateTestThread(&list[index],
00531                          index,
00532                          sharedlock,
00533                          sharedcvar,
00534                          count,
00535                          PR_INTERVAL_NO_TIMEOUT,
00536                          &tcount,
00537                          exitlock,
00538                          exitcvar,
00539                          &exitcount,
00540                          PR_TRUE,
00541                          PR_LOCAL_THREAD);
00542 
00543         index++;
00544         CreateTestThread(&list[index],
00545                          index,
00546                          sharedlock,
00547                          sharedcvar,
00548                          count,
00549                          PR_INTERVAL_NO_TIMEOUT,
00550                          &tcount,
00551                          exitlock,
00552                          exitcvar,
00553                          &exitcount,
00554                          PR_TRUE,
00555                          PR_GLOBAL_THREAD);
00556 
00557         index++;
00558         list[index].lock = PR_NewLock();
00559         list[index].cvar = PR_NewCondVar(list[index].lock);
00560         CreateTestThread(&list[index],
00561                          index,
00562                          list[index].lock,
00563                          list[index].cvar,
00564                          count,
00565                          PR_INTERVAL_NO_TIMEOUT,
00566                          ptcount,
00567                          exitlock,
00568                          exitcvar,
00569                          &exitcount,
00570                          PR_FALSE,
00571                          PR_LOCAL_THREAD);
00572         index++;
00573        ptcount++;
00574         list[index].lock = PR_NewLock();
00575         list[index].cvar = PR_NewCondVar(list[index].lock);
00576         CreateTestThread(&list[index],
00577                          index,
00578                          list[index].lock,
00579                          list[index].cvar,
00580                          count,
00581                          PR_INTERVAL_NO_TIMEOUT,
00582                          ptcount,
00583                          exitlock,
00584                          exitcvar,
00585                          &exitcount,
00586                          PR_FALSE,
00587                          PR_GLOBAL_THREAD);
00588 
00589         index++;
00590        ptcount++;
00591     }
00592 
00593     for (loops = 0; loops < count; loops++) {
00594 
00595         /* Notify the threads */
00596         for(index=0; index<(arg*4); index++) {
00597             PR_Lock(list[index].lock);
00598             (*list[index].tcount)++;
00599             PR_NotifyCondVar(list[index].cvar);
00600             PR_Unlock(list[index].lock);
00601         }
00602 
00603 #if 0
00604         printf("wait for threads done\n");
00605 #endif
00606 
00607         /* Wait for threads to finish */
00608         PR_Lock(exitlock);
00609         while(exitcount < arg*4)
00610             PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60));
00611         PR_ASSERT(exitcount >= arg*4);
00612         exitcount -= arg*4;
00613         PR_Unlock(exitlock);
00614 #if 0
00615         printf("threads ready\n");
00616 #endif
00617     }
00618 
00619     /* Join all the threads */
00620     for(index=0; index<(arg*4); index++) {
00621         PR_JoinThread(list[index].thread);
00622         if (list[index].internal) {
00623             PR_Lock(list[index].lock);
00624             PR_DestroyCondVar(list[index].cvar);
00625             PR_Unlock(list[index].lock);
00626             PR_DestroyLock(list[index].lock);
00627         }
00628     }
00629 
00630     PR_DestroyCondVar(sharedcvar);
00631     PR_DestroyLock(sharedlock);
00632     PR_DestroyCondVar(exitcvar);
00633     PR_DestroyLock(exitlock);
00634 
00635     PR_DELETE(list);
00636     PR_DELETE(saved_ptcount);
00637 }
00638 
00639 void 
00640 CondVarTimeoutTest(void *_arg)
00641 {
00642     PRInt32 arg = (PRInt32)_arg;
00643     PRInt32 index, loops;
00644     threadinfo *list;
00645     PRLock *sharedlock;
00646     PRCondVar *sharedcvar;
00647     PRLock *exitlock;
00648     PRCondVar *exitcvar;
00649 
00650     list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4));
00651 
00652     sharedlock = PR_NewLock();
00653     sharedcvar = PR_NewCondVar(sharedlock);
00654     exitlock = PR_NewLock();
00655     exitcvar = PR_NewCondVar(exitlock);
00656 
00657     /* Create the threads */
00658     for(index=0; index<arg*4; ) {
00659         CreateTestThread(&list[index],
00660                          index,
00661                          sharedlock,
00662                          sharedcvar,
00663                          count,
00664                          PR_MillisecondsToInterval(50),
00665                          &tcount,
00666                          exitlock,
00667                          exitcvar,
00668                          &exitcount,
00669                          PR_TRUE,
00670                          PR_LOCAL_THREAD);
00671         index++;
00672         CreateTestThread(&list[index],
00673                          index,
00674                          sharedlock,
00675                          sharedcvar,
00676                          count,
00677                          PR_MillisecondsToInterval(50),
00678                          &tcount,
00679                          exitlock,
00680                          exitcvar,
00681                          &exitcount,
00682                          PR_TRUE,
00683                          PR_GLOBAL_THREAD);
00684         index++;
00685         list[index].lock = PR_NewLock();
00686         list[index].cvar = PR_NewCondVar(list[index].lock);
00687         CreateTestThread(&list[index],
00688                          index,
00689                          list[index].lock,
00690                          list[index].cvar,
00691                          count,
00692                          PR_MillisecondsToInterval(50),
00693                          &tcount,
00694                          exitlock,
00695                          exitcvar,
00696                          &exitcount,
00697                          PR_FALSE,
00698                          PR_LOCAL_THREAD);
00699         index++;
00700 
00701         list[index].lock = PR_NewLock();
00702         list[index].cvar = PR_NewCondVar(list[index].lock);
00703         CreateTestThread(&list[index],
00704                          index,
00705                          list[index].lock,
00706                          list[index].cvar,
00707                          count,
00708                          PR_MillisecondsToInterval(50),
00709                          &tcount,
00710                          exitlock,
00711                          exitcvar,
00712                          &exitcount,
00713                          PR_FALSE,
00714                          PR_GLOBAL_THREAD);
00715 
00716         index++;
00717     }
00718 
00719     for (loops = 0; loops < count; loops++) {
00720 
00721         /* Wait for threads to finish */
00722         PR_Lock(exitlock);
00723         while(exitcount < arg*4)
00724             PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60));
00725         PR_ASSERT(exitcount >= arg*4);
00726         exitcount -= arg*4;
00727         PR_Unlock(exitlock);
00728     }
00729 
00730 
00731     /* Join all the threads */
00732     for(index=0; index<(arg*4); index++) {
00733         PR_JoinThread(list[index].thread);
00734         if (list[index].internal) {
00735             PR_Lock(list[index].lock);
00736             PR_DestroyCondVar(list[index].cvar);
00737             PR_Unlock(list[index].lock);
00738             PR_DestroyLock(list[index].lock);
00739         }
00740     }
00741 
00742     PR_DestroyCondVar(sharedcvar);
00743     PR_DestroyLock(sharedlock);
00744     PR_DestroyCondVar(exitcvar);
00745     PR_DestroyLock(exitlock);
00746 
00747     PR_DELETE(list);
00748 }
00749 
00750 void 
00751 CondVarMixedTest(void *_arg)
00752 {
00753     PRInt32 arg = (PRInt32)_arg;
00754     PRInt32 index, loops;
00755     threadinfo *list;
00756     PRLock *sharedlock;
00757     PRCondVar *sharedcvar;
00758     PRLock *exitlock;
00759     PRCondVar *exitcvar;
00760     PRInt32 *ptcount;
00761 
00762     exitcount=0;
00763     tcount=0;
00764     list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4));
00765     ptcount = (PRInt32 *)PR_CALLOC(sizeof(*ptcount) * (arg * 4));
00766 
00767     sharedlock = PR_NewLock();
00768     sharedcvar = PR_NewCondVar(sharedlock);
00769     exitlock = PR_NewLock();
00770     exitcvar = PR_NewCondVar(exitlock);
00771 
00772     /* Create the threads */
00773     for(index=0; index<arg*4; ) {
00774         CreateTestThread(&list[index],
00775                          index,
00776                          sharedlock,
00777                          sharedcvar,
00778                          count,
00779                          PR_MillisecondsToInterval(50),
00780                          &tcount,
00781                          exitlock,
00782                          exitcvar,
00783                          &exitcount,
00784                          PR_TRUE,
00785                          PR_LOCAL_THREAD);
00786         index++;
00787         CreateTestThread(&list[index],
00788                          index,
00789                          sharedlock,
00790                          sharedcvar,
00791                          count,
00792                          PR_MillisecondsToInterval(50),
00793                          &tcount,
00794                          exitlock,
00795                          exitcvar,
00796                          &exitcount,
00797                          PR_TRUE,
00798                          PR_GLOBAL_THREAD);
00799         index++;
00800         list[index].lock = PR_NewLock();
00801         list[index].cvar = PR_NewCondVar(list[index].lock);
00802         CreateTestThread(&list[index],
00803                          index,
00804                          list[index].lock,
00805                          list[index].cvar,
00806                          count,
00807                          PR_MillisecondsToInterval(50),
00808                          ptcount,
00809                          exitlock,
00810                          exitcvar,
00811                          &exitcount,
00812                          PR_FALSE,
00813                          PR_LOCAL_THREAD);
00814         index++;
00815        ptcount++;
00816 
00817         list[index].lock = PR_NewLock();
00818         list[index].cvar = PR_NewCondVar(list[index].lock);
00819         CreateTestThread(&list[index],
00820                          index,
00821                          list[index].lock,
00822                          list[index].cvar,
00823                          count,
00824                          PR_MillisecondsToInterval(50),
00825                          ptcount,
00826                          exitlock,
00827                          exitcvar,
00828                          &exitcount,
00829                          PR_FALSE,
00830                          PR_GLOBAL_THREAD);
00831         index++;
00832        ptcount++;
00833     }
00834 
00835 
00836     /* Notify every 3rd thread */
00837     for (loops = 0; loops < count; loops++) {
00838 
00839         /* Notify the threads */
00840         for(index=0; index<(arg*4); index+=3) {
00841 
00842             PR_Lock(list[index].lock);
00843             *list[index].tcount++;
00844             PR_NotifyCondVar(list[index].cvar);
00845             PR_Unlock(list[index].lock);
00846 
00847         }
00848         /* Wait for threads to finish */
00849         PR_Lock(exitlock);
00850         while(exitcount < arg*4)
00851             PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60));
00852         PR_ASSERT(exitcount >= arg*4);
00853         exitcount -= arg*4;
00854         PR_Unlock(exitlock);
00855     }
00856 
00857     /* Join all the threads */
00858     for(index=0; index<(arg*4); index++) {
00859         PR_JoinThread(list[index].thread);
00860         if (list[index].internal) {
00861             PR_Lock(list[index].lock);
00862             PR_DestroyCondVar(list[index].cvar);
00863             PR_Unlock(list[index].lock);
00864             PR_DestroyLock(list[index].lock);
00865         }
00866     }
00867 
00868     PR_DestroyCondVar(sharedcvar);
00869     PR_DestroyLock(sharedlock);
00870 
00871     PR_DELETE(list);
00872 }
00873 
00874 void 
00875 CondVarCombinedTest(void *arg)
00876 {
00877     PRThread *threads[3];
00878 
00879     threads[0] = PR_CreateThread(PR_USER_THREAD,
00880                                  CondVarTest,
00881                                  (void *)arg,
00882                                  PR_PRIORITY_NORMAL,
00883                                  PR_GLOBAL_THREAD,
00884                                  PR_JOINABLE_THREAD,
00885                                  0);
00886     threads[1] = PR_CreateThread(PR_USER_THREAD,
00887                                  CondVarTimeoutTest,
00888                                  (void *)arg,
00889                                  PR_PRIORITY_NORMAL,
00890                                  PR_GLOBAL_THREAD,
00891                                  PR_JOINABLE_THREAD,
00892                                  0);
00893     threads[2] = PR_CreateThread(PR_USER_THREAD,
00894                                  CondVarMixedTest,
00895                                  (void *)arg,
00896                                  PR_PRIORITY_NORMAL,
00897                                  PR_GLOBAL_THREAD,
00898                                  PR_JOINABLE_THREAD,
00899                                  0);
00900 
00901     PR_JoinThread(threads[0]);
00902     PR_JoinThread(threads[1]);
00903     PR_JoinThread(threads[2]);
00904 }
00905 
00906 /************************************************************************/
00907 
00908 static void Measure(void (*func)(void *), PRInt32 arg, const char *msg)
00909 {
00910     PRIntervalTime start, stop;
00911     double d;
00912 
00913     start = PR_IntervalNow();
00914     (*func)((void *)arg);
00915     stop = PR_IntervalNow();
00916 
00917     d = (double)PR_IntervalToMicroseconds(stop - start);
00918 
00919     printf("%40s: %6.2f usec\n", msg, d / count);
00920 }
00921 
00922 static PRIntn PR_CALLBACK RealMain(int argc, char **argv)
00923 {
00924     PRInt32 threads, default_threads = DEFAULT_THREADS;
00925        PLOptStatus os;
00926        PLOptState *opt = PL_CreateOptState(argc, argv, "vc:t:");
00927        while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
00928     {
00929               if (PL_OPT_BAD == os) continue;
00930         switch (opt->option)
00931         {
00932         case 'v':  /* debug mode */
00933                      _debug_on = 1;
00934             break;
00935         case 'c':  /* loop counter */
00936                      count = atoi(opt->value);
00937             break;
00938         case 't':  /* number of threads involved */
00939                      default_threads = atoi(opt->value);
00940             break;
00941          default:
00942             break;
00943         }
00944     }
00945        PL_DestroyOptState(opt);
00946 
00947     if (0 == count) count = DEFAULT_COUNT;
00948     if (0 == default_threads) default_threads = DEFAULT_THREADS;
00949 
00950 #ifdef XP_MAC
00951        SetupMacPrintfLog("cvar2.log");
00952 #endif
00953 
00954     printf("\n\
00955 CondVar Test:                                                           \n\
00956                                                                         \n\
00957 Simple test creates several local and global threads; half use a single,\n\
00958 shared condvar, and the other half have their own condvar.  The main    \n\
00959 thread then loops notifying them to wakeup.                             \n\
00960                                                                         \n\
00961 The timeout test is very similar except that the threads are not        \n\
00962 notified.  They will all wakeup on a 1 second timeout.                  \n\
00963                                                                         \n\
00964 The mixed test combines the simple test and the timeout test; every     \n\
00965 third thread is notified, the other threads are expected to timeout     \n\
00966 correctly.                                                              \n\
00967                                                                         \n\
00968 Lastly, the combined test creates a thread for each of the above three  \n\
00969 cases and they all run simultaneously.                                  \n\
00970                                                                         \n\
00971 This test is run with %d, %d, %d, and %d threads of each type.\n\n",
00972 default_threads, default_threads*2, default_threads*3, default_threads*4);
00973 
00974     PR_SetConcurrency(2);
00975 
00976     for (threads = default_threads; threads < default_threads*5; threads+=default_threads) {
00977         printf("\n%ld Thread tests\n", threads);
00978         Measure(CondVarTestSUU, threads, "Condvar simple test shared UU");
00979         Measure(CondVarTestSUK, threads, "Condvar simple test shared UK");
00980         Measure(CondVarTestPUU, threads, "Condvar simple test priv UU");
00981         Measure(CondVarTestPUK, threads, "Condvar simple test priv UK");
00982 #ifdef XP_MAC
00983        /* Mac heaps can't handle thread*4 stack allocations at a time for (10, 15, 20)*4 */
00984         Measure(CondVarTest, 5, "Condvar simple test All");
00985         Measure(CondVarTimeoutTest, 5,  "Condvar timeout test");
00986 #else
00987         Measure(CondVarTest, threads, "Condvar simple test All");
00988         Measure(CondVarTimeoutTest, threads,  "Condvar timeout test");
00989 #endif
00990 #if 0
00991         Measure(CondVarMixedTest, threads,  "Condvar mixed timeout test");
00992         Measure(CondVarCombinedTest, threads, "Combined condvar test");
00993 #endif
00994     }
00995 
00996     printf("PASS\n");
00997 
00998     return 0;
00999 }
01000 
01001 PRIntn main(PRIntn argc, char *argv[])
01002 {
01003     PRIntn rv;
01004     
01005     PR_STDIO_INIT();
01006     rv = PR_Initialize(RealMain, argc, argv, 0);
01007     return rv;
01008 }  /* main */