summaryrefslogtreecommitdiffstats
path: root/nsprpub/pr/tests/concur.c
diff options
context:
space:
mode:
Diffstat (limited to 'nsprpub/pr/tests/concur.c')
-rw-r--r--nsprpub/pr/tests/concur.c166
1 files changed, 166 insertions, 0 deletions
diff --git a/nsprpub/pr/tests/concur.c b/nsprpub/pr/tests/concur.c
new file mode 100644
index 0000000000..5940290213
--- /dev/null
+++ b/nsprpub/pr/tests/concur.c
@@ -0,0 +1,166 @@
+/* -*- 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 <stdlib.h>
+
+#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 */