nsprpub/pr/tests/pollable.c

Wed, 31 Dec 2014 06:55:46 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:46 +0100
changeset 1
ca08bd8f51b2
permissions
-rw-r--r--

Added tag TORBROWSER_REPLICA for changeset 6474c204b198

michael@0 1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 /*
michael@0 7 * A test for the pollable events.
michael@0 8 *
michael@0 9 * A number of threads are in a ring configuration, each waiting on
michael@0 10 * a pollable event that is set by its upstream neighbor.
michael@0 11 */
michael@0 12
michael@0 13 #include "prinit.h"
michael@0 14 #include "prio.h"
michael@0 15 #include "prthread.h"
michael@0 16 #include "prerror.h"
michael@0 17 #include "prmem.h"
michael@0 18 #include "prlog.h"
michael@0 19 #include "prprf.h"
michael@0 20
michael@0 21 #include "plgetopt.h"
michael@0 22
michael@0 23 #include <stdlib.h>
michael@0 24
michael@0 25 #define DEFAULT_THREADS 10
michael@0 26 #define DEFAULT_LOOPS 100
michael@0 27
michael@0 28 PRIntn numThreads = DEFAULT_THREADS;
michael@0 29 PRIntn numIterations = DEFAULT_LOOPS;
michael@0 30 PRIntervalTime dally = PR_INTERVAL_NO_WAIT;
michael@0 31 PRFileDesc *debug_out = NULL;
michael@0 32 PRBool debug_mode = PR_FALSE;
michael@0 33 PRBool verbosity = PR_FALSE;
michael@0 34
michael@0 35 typedef struct ThreadData {
michael@0 36 PRFileDesc *event;
michael@0 37 int index;
michael@0 38 struct ThreadData *next;
michael@0 39 } ThreadData;
michael@0 40
michael@0 41 void ThreadRoutine(void *arg)
michael@0 42 {
michael@0 43 ThreadData *data = (ThreadData *) arg;
michael@0 44 PRIntn i;
michael@0 45 PRPollDesc pd;
michael@0 46 PRInt32 rv;
michael@0 47
michael@0 48 pd.fd = data->event;
michael@0 49 pd.in_flags = PR_POLL_READ;
michael@0 50
michael@0 51 for (i = 0; i < numIterations; i++) {
michael@0 52 rv = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT);
michael@0 53 if (rv == -1) {
michael@0 54 PR_fprintf(PR_STDERR, "PR_Poll failed\n");
michael@0 55 exit(1);
michael@0 56 }
michael@0 57 if (verbosity) {
michael@0 58 PR_fprintf(debug_out, "thread %d awakened\n", data->index);
michael@0 59 }
michael@0 60 PR_ASSERT(rv != 0);
michael@0 61 PR_ASSERT(pd.out_flags & PR_POLL_READ);
michael@0 62 if (PR_WaitForPollableEvent(data->event) == PR_FAILURE) {
michael@0 63 PR_fprintf(PR_STDERR, "consume event failed\n");
michael@0 64 exit(1);
michael@0 65 }
michael@0 66 if (dally != PR_INTERVAL_NO_WAIT) {
michael@0 67 PR_Sleep(dally);
michael@0 68 }
michael@0 69 if (verbosity) {
michael@0 70 PR_fprintf(debug_out, "thread %d posting event\n", data->index);
michael@0 71 }
michael@0 72 if (PR_SetPollableEvent(data->next->event) == PR_FAILURE) {
michael@0 73 PR_fprintf(PR_STDERR, "post event failed\n");
michael@0 74 exit(1);
michael@0 75 }
michael@0 76 }
michael@0 77 }
michael@0 78
michael@0 79 static void Help(void)
michael@0 80 {
michael@0 81 debug_out = PR_STDOUT;
michael@0 82
michael@0 83 PR_fprintf(
michael@0 84 debug_out, "Usage: pollable [-c n] [-t n] [-d] [-v] [-G] [-C n] [-D n]\n");
michael@0 85 PR_fprintf(
michael@0 86 debug_out, "-c n\tloops at thread level (default: %d)\n", DEFAULT_LOOPS);
michael@0 87 PR_fprintf(
michael@0 88 debug_out, "-t n\tnumber of threads (default: %d)\n", DEFAULT_THREADS);
michael@0 89 PR_fprintf(debug_out, "-d\tturn on debugging output (default: FALSE)\n");
michael@0 90 PR_fprintf(debug_out, "-v\tturn on verbose output (default: FALSE)\n");
michael@0 91 PR_fprintf(debug_out, "-G\tglobal threads only (default: FALSE)\n");
michael@0 92 PR_fprintf(debug_out, "-C n\tconcurrency setting (default: 1)\n");
michael@0 93 PR_fprintf(debug_out, "-D n\tdally setting (msecs) (default: 0)\n");
michael@0 94 } /* Help */
michael@0 95
michael@0 96 int main(int argc, char **argv)
michael@0 97 {
michael@0 98 ThreadData selfData;
michael@0 99 ThreadData *data;
michael@0 100 PRThread **thread;
michael@0 101 void *block;
michael@0 102 PRIntn i;
michael@0 103 PRIntervalTime timeStart, timeEnd;
michael@0 104 PRPollDesc pd;
michael@0 105 PRInt32 rv;
michael@0 106 PRThreadScope thread_scope = PR_LOCAL_THREAD;
michael@0 107 PRBool help = PR_FALSE;
michael@0 108 PRUintn concurrency = 1;
michael@0 109 PRUintn average;
michael@0 110 PLOptStatus os;
michael@0 111 PLOptState *opt;
michael@0 112
michael@0 113 PR_STDIO_INIT();
michael@0 114
michael@0 115 opt = PL_CreateOptState(argc, argv, "hdvc:t:C:GD:");
michael@0 116 while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) {
michael@0 117 if (PL_OPT_BAD == os) {
michael@0 118 continue;
michael@0 119 }
michael@0 120 switch (opt->option) {
michael@0 121 case 'v': /* verbose mode */
michael@0 122 verbosity = PR_TRUE;
michael@0 123 case 'd': /* debug mode */
michael@0 124 debug_mode = PR_TRUE;
michael@0 125 break;
michael@0 126 case 'c': /* loop counter */
michael@0 127 numIterations = atoi(opt->value);
michael@0 128 break;
michael@0 129 case 't': /* thread limit */
michael@0 130 numThreads = atoi(opt->value);
michael@0 131 break;
michael@0 132 case 'C': /* Concurrency limit */
michael@0 133 concurrency = atoi(opt->value);
michael@0 134 break;
michael@0 135 case 'G': /* global threads only */
michael@0 136 thread_scope = PR_GLOBAL_THREAD;
michael@0 137 break;
michael@0 138 case 'D': /* dally */
michael@0 139 dally = PR_MillisecondsToInterval(atoi(opt->value));
michael@0 140 break;
michael@0 141 case 'h': /* help message */
michael@0 142 Help();
michael@0 143 help = PR_TRUE;
michael@0 144 break;
michael@0 145 default:
michael@0 146 break;
michael@0 147 }
michael@0 148 }
michael@0 149 PL_DestroyOptState(opt);
michael@0 150
michael@0 151 if (help) {
michael@0 152 return 1;
michael@0 153 }
michael@0 154
michael@0 155 if (concurrency > 1) {
michael@0 156 PR_SetConcurrency(concurrency);
michael@0 157 }
michael@0 158
michael@0 159 if (PR_TRUE == debug_mode) {
michael@0 160 debug_out = PR_STDOUT;
michael@0 161 PR_fprintf(debug_out, "Test parameters\n");
michael@0 162 PR_fprintf(debug_out, "\tThreads involved: %d\n", numThreads);
michael@0 163 PR_fprintf(debug_out, "\tIteration limit: %d\n", numIterations);
michael@0 164 PR_fprintf(debug_out, "\tConcurrency: %d\n", concurrency);
michael@0 165 PR_fprintf(debug_out, "\tThread type: %s\n",
michael@0 166 (PR_GLOBAL_THREAD == thread_scope) ? "GLOBAL" : "LOCAL");
michael@0 167 }
michael@0 168
michael@0 169 /*
michael@0 170 * Malloc a block of memory and divide it into data and thread.
michael@0 171 */
michael@0 172 block = PR_MALLOC(numThreads * (sizeof(ThreadData) + sizeof(PRThread *)));
michael@0 173 if (block == NULL) {
michael@0 174 PR_fprintf(PR_STDERR, "cannot malloc, failed\n");
michael@0 175 exit(1);
michael@0 176 }
michael@0 177 data = (ThreadData *) block;
michael@0 178 thread = (PRThread **) &data[numThreads];
michael@0 179
michael@0 180 /* Pollable event */
michael@0 181 selfData.event = PR_NewPollableEvent();
michael@0 182 if (selfData.event == NULL) {
michael@0 183 PR_fprintf(PR_STDERR, "cannot create event: (%ld, %ld)\n",
michael@0 184 PR_GetError(), PR_GetOSError());
michael@0 185 exit(1);
michael@0 186 }
michael@0 187 selfData.next = &data[0];
michael@0 188 for (i = 0; i < numThreads; i++) {
michael@0 189 data[i].event = PR_NewPollableEvent();
michael@0 190 if (data[i].event == NULL) {
michael@0 191 PR_fprintf(PR_STDERR, "cannot create event: (%ld, %ld)\n",
michael@0 192 PR_GetError(), PR_GetOSError());
michael@0 193 exit(1);
michael@0 194 }
michael@0 195 data[i].index = i;
michael@0 196 if (i != numThreads - 1) {
michael@0 197 data[i].next = &data[i + 1];
michael@0 198 } else {
michael@0 199 data[i].next = &selfData;
michael@0 200 }
michael@0 201
michael@0 202 thread[i] = PR_CreateThread(PR_USER_THREAD,
michael@0 203 ThreadRoutine, &data[i], PR_PRIORITY_NORMAL,
michael@0 204 thread_scope, PR_JOINABLE_THREAD, 0);
michael@0 205 if (thread[i] == NULL) {
michael@0 206 PR_fprintf(PR_STDERR, "cannot create thread\n");
michael@0 207 exit(1);
michael@0 208 }
michael@0 209 }
michael@0 210
michael@0 211 timeStart = PR_IntervalNow();
michael@0 212 pd.fd = selfData.event;
michael@0 213 pd.in_flags = PR_POLL_READ;
michael@0 214 for (i = 0; i < numIterations; i++) {
michael@0 215 if (dally != PR_INTERVAL_NO_WAIT) {
michael@0 216 PR_Sleep(dally);
michael@0 217 }
michael@0 218 if (verbosity) {
michael@0 219 PR_fprintf(debug_out, "main thread posting event\n");
michael@0 220 }
michael@0 221 if (PR_SetPollableEvent(selfData.next->event) == PR_FAILURE) {
michael@0 222 PR_fprintf(PR_STDERR, "set event failed\n");
michael@0 223 exit(1);
michael@0 224 }
michael@0 225 rv = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT);
michael@0 226 if (rv == -1) {
michael@0 227 PR_fprintf(PR_STDERR, "wait failed\n");
michael@0 228 exit(1);
michael@0 229 }
michael@0 230 PR_ASSERT(rv != 0);
michael@0 231 PR_ASSERT(pd.out_flags & PR_POLL_READ);
michael@0 232 if (verbosity) {
michael@0 233 PR_fprintf(debug_out, "main thread awakened\n");
michael@0 234 }
michael@0 235 if (PR_WaitForPollableEvent(selfData.event) == PR_FAILURE) {
michael@0 236 PR_fprintf(PR_STDERR, "consume event failed\n");
michael@0 237 exit(1);
michael@0 238 }
michael@0 239 }
michael@0 240 timeEnd = PR_IntervalNow();
michael@0 241
michael@0 242 if (debug_mode) {
michael@0 243 average = PR_IntervalToMicroseconds(timeEnd - timeStart)
michael@0 244 / (numIterations * numThreads);
michael@0 245 PR_fprintf(debug_out, "Average switch times %d usecs for %d threads\n",
michael@0 246 average, numThreads);
michael@0 247 }
michael@0 248
michael@0 249 for (i = 0; i < numThreads; i++) {
michael@0 250 if (PR_JoinThread(thread[i]) == PR_FAILURE) {
michael@0 251 PR_fprintf(PR_STDERR, "join thread failed\n");
michael@0 252 exit(1);
michael@0 253 }
michael@0 254 PR_DestroyPollableEvent(data[i].event);
michael@0 255 }
michael@0 256 PR_DELETE(block);
michael@0 257 PR_DestroyPollableEvent(selfData.event);
michael@0 258
michael@0 259 PR_fprintf(PR_STDOUT, "PASSED\n");
michael@0 260 return 0;
michael@0 261 }

mercurial