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