concur.c (3657B)
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 ** File: concur.c 8 ** Description: test of adding and removing concurrency options 9 */ 10 11 #include "prcvar.h" 12 #include "prinit.h" 13 #include "prinrval.h" 14 #include "prlock.h" 15 #include "prprf.h" 16 #include "prmem.h" 17 #include "prlog.h" 18 19 #include "plgetopt.h" 20 21 #include "private/pprio.h" 22 23 #include <stdlib.h> 24 25 #define DEFAULT_RANGE 10 26 #define DEFAULT_LOOPS 100 27 28 static PRThreadScope thread_scope = PR_LOCAL_THREAD; 29 30 typedef struct Context { 31 PRLock* ml; 32 PRCondVar* cv; 33 PRIntn want, have; 34 } Context; 35 36 /* 37 ** Make the instance of 'context' static (not on the stack) 38 ** for Win16 threads 39 */ 40 static Context context = {NULL, NULL, 0, 0}; 41 42 static void PR_CALLBACK Dull(void* arg) { 43 Context* context = (Context*)arg; 44 PR_Lock(context->ml); 45 context->have += 1; 46 while (context->want >= context->have) { 47 PR_WaitCondVar(context->cv, PR_INTERVAL_NO_TIMEOUT); 48 } 49 context->have -= 1; 50 PR_Unlock(context->ml); 51 } /* Dull */ 52 53 PRIntn PR_CALLBACK Concur(PRIntn argc, char** argv) { 54 PRUintn cpus; 55 PLOptStatus os; 56 PRThread** threads; 57 PRBool debug = PR_FALSE; 58 PRUintn range = DEFAULT_RANGE; 59 PRStatus rc; 60 PRUintn cnt; 61 PRUintn loops = DEFAULT_LOOPS; 62 PRIntervalTime hundredMills = PR_MillisecondsToInterval(100); 63 PLOptState* opt = PL_CreateOptState(argc, argv, "Gdl:r:"); 64 while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { 65 if (PL_OPT_BAD == os) { 66 continue; 67 } 68 switch (opt->option) { 69 case 'G': /* GLOBAL threads */ 70 thread_scope = PR_GLOBAL_THREAD; 71 break; 72 case 'd': /* debug mode */ 73 debug = PR_TRUE; 74 break; 75 case 'r': /* range limit */ 76 range = atoi(opt->value); 77 break; 78 case 'l': /* loop counter */ 79 loops = atoi(opt->value); 80 break; 81 default: 82 break; 83 } 84 } 85 PL_DestroyOptState(opt); 86 87 if (0 == range) { 88 range = DEFAULT_RANGE; 89 } 90 if (0 == loops) { 91 loops = DEFAULT_LOOPS; 92 } 93 94 context.ml = PR_NewLock(); 95 context.cv = PR_NewCondVar(context.ml); 96 97 if (debug) 98 PR_fprintf(PR_STDERR, "Testing with %d CPUs and %d interations\n", range, 99 loops); 100 101 threads = (PRThread**)PR_CALLOC(sizeof(PRThread*) * range); 102 while (--loops > 0) { 103 for (cpus = 1; cpus <= range; ++cpus) { 104 PR_SetConcurrency(cpus); 105 context.want = cpus; 106 107 threads[cpus - 1] = 108 PR_CreateThread(PR_USER_THREAD, Dull, &context, PR_PRIORITY_NORMAL, 109 thread_scope, PR_JOINABLE_THREAD, 0); 110 } 111 112 PR_Sleep(hundredMills); 113 114 for (cpus = range; cpus > 0; cpus--) { 115 PR_SetConcurrency(cpus); 116 context.want = cpus - 1; 117 118 PR_Lock(context.ml); 119 PR_NotifyCondVar(context.cv); 120 PR_Unlock(context.ml); 121 } 122 for (cnt = 0; cnt < range; cnt++) { 123 rc = PR_JoinThread(threads[cnt]); 124 PR_ASSERT(rc == PR_SUCCESS); 125 } 126 } 127 128 if (debug) 129 PR_fprintf(PR_STDERR, "Waiting for %d thread(s) to exit\n", context.have); 130 131 while (context.have > 0) { 132 PR_Sleep(hundredMills); 133 } 134 135 if (debug) 136 PR_fprintf(PR_STDERR, "Finished [want: %d, have: %d]\n", context.want, 137 context.have); 138 139 PR_DestroyLock(context.ml); 140 PR_DestroyCondVar(context.cv); 141 PR_DELETE(threads); 142 143 PR_fprintf(PR_STDERR, "PASSED\n"); 144 145 return 0; 146 } /* Concur */ 147 148 int main(int argc, char** argv) { 149 return PR_Initialize(Concur, argc, argv, 0); 150 } /* main */ 151 152 /* concur.c */