/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* ** File: concur.c ** Description: test of adding and removing concurrency options */ #include "prcvar.h" #include "prinit.h" #include "prinrval.h" #include "prlock.h" #include "prprf.h" #include "prmem.h" #include "prlog.h" #include "plgetopt.h" #include "private/pprio.h" #include #define DEFAULT_RANGE 10 #define DEFAULT_LOOPS 100 static PRThreadScope thread_scope = PR_LOCAL_THREAD; typedef struct Context { PRLock *ml; PRCondVar *cv; PRIntn want, have; } Context; /* ** Make the instance of 'context' static (not on the stack) ** for Win16 threads */ static Context context = {NULL, NULL, 0, 0}; static void PR_CALLBACK Dull(void *arg) { Context *context = (Context*)arg; PR_Lock(context->ml); context->have += 1; while (context->want >= context->have) { PR_WaitCondVar(context->cv, PR_INTERVAL_NO_TIMEOUT); } context->have -= 1; PR_Unlock(context->ml); } /* Dull */ PRIntn PR_CALLBACK Concur(PRIntn argc, char **argv) { PRUintn cpus; PLOptStatus os; PRThread **threads; PRBool debug = PR_FALSE; PRUintn range = DEFAULT_RANGE; PRStatus rc; PRUintn cnt; PRUintn loops = DEFAULT_LOOPS; PRIntervalTime hundredMills = PR_MillisecondsToInterval(100); PLOptState *opt = PL_CreateOptState(argc, argv, "Gdl:r:"); while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { if (PL_OPT_BAD == os) { continue; } switch (opt->option) { case 'G': /* GLOBAL threads */ thread_scope = PR_GLOBAL_THREAD; break; case 'd': /* debug mode */ debug = PR_TRUE; break; case 'r': /* range limit */ range = atoi(opt->value); break; case 'l': /* loop counter */ loops = atoi(opt->value); break; default: break; } } PL_DestroyOptState(opt); if (0 == range) { range = DEFAULT_RANGE; } if (0 == loops) { loops = DEFAULT_LOOPS; } context.ml = PR_NewLock(); context.cv = PR_NewCondVar(context.ml); if (debug) PR_fprintf( PR_STDERR, "Testing with %d CPUs and %d interations\n", range, loops); threads = (PRThread**) PR_CALLOC(sizeof(PRThread*) * range); while (--loops > 0) { for (cpus = 1; cpus <= range; ++cpus) { PR_SetConcurrency(cpus); context.want = cpus; threads[cpus - 1] = PR_CreateThread( PR_USER_THREAD, Dull, &context, PR_PRIORITY_NORMAL, thread_scope, PR_JOINABLE_THREAD, 0); } PR_Sleep(hundredMills); for (cpus = range; cpus > 0; cpus--) { PR_SetConcurrency(cpus); context.want = cpus - 1; PR_Lock(context.ml); PR_NotifyCondVar(context.cv); PR_Unlock(context.ml); } for(cnt = 0; cnt < range; cnt++) { rc = PR_JoinThread(threads[cnt]); PR_ASSERT(rc == PR_SUCCESS); } } if (debug) PR_fprintf( PR_STDERR, "Waiting for %d thread(s) to exit\n", context.have); while (context.have > 0) { PR_Sleep(hundredMills); } if (debug) PR_fprintf( PR_STDERR, "Finished [want: %d, have: %d]\n", context.want, context.have); PR_DestroyLock(context.ml); PR_DestroyCondVar(context.cv); PR_DELETE(threads); PR_fprintf(PR_STDERR, "PASSED\n"); return 0; } /* Concur */ int main(int argc, char **argv) { PR_STDIO_INIT(); return PR_Initialize(Concur, argc, argv, 0); } /* main */ /* concur.c */