1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/nsprpub/pr/tests/pollable.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,261 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* 1.10 + * A test for the pollable events. 1.11 + * 1.12 + * A number of threads are in a ring configuration, each waiting on 1.13 + * a pollable event that is set by its upstream neighbor. 1.14 + */ 1.15 + 1.16 +#include "prinit.h" 1.17 +#include "prio.h" 1.18 +#include "prthread.h" 1.19 +#include "prerror.h" 1.20 +#include "prmem.h" 1.21 +#include "prlog.h" 1.22 +#include "prprf.h" 1.23 + 1.24 +#include "plgetopt.h" 1.25 + 1.26 +#include <stdlib.h> 1.27 + 1.28 +#define DEFAULT_THREADS 10 1.29 +#define DEFAULT_LOOPS 100 1.30 + 1.31 +PRIntn numThreads = DEFAULT_THREADS; 1.32 +PRIntn numIterations = DEFAULT_LOOPS; 1.33 +PRIntervalTime dally = PR_INTERVAL_NO_WAIT; 1.34 +PRFileDesc *debug_out = NULL; 1.35 +PRBool debug_mode = PR_FALSE; 1.36 +PRBool verbosity = PR_FALSE; 1.37 + 1.38 +typedef struct ThreadData { 1.39 + PRFileDesc *event; 1.40 + int index; 1.41 + struct ThreadData *next; 1.42 +} ThreadData; 1.43 + 1.44 +void ThreadRoutine(void *arg) 1.45 +{ 1.46 + ThreadData *data = (ThreadData *) arg; 1.47 + PRIntn i; 1.48 + PRPollDesc pd; 1.49 + PRInt32 rv; 1.50 + 1.51 + pd.fd = data->event; 1.52 + pd.in_flags = PR_POLL_READ; 1.53 + 1.54 + for (i = 0; i < numIterations; i++) { 1.55 + rv = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT); 1.56 + if (rv == -1) { 1.57 + PR_fprintf(PR_STDERR, "PR_Poll failed\n"); 1.58 + exit(1); 1.59 + } 1.60 + if (verbosity) { 1.61 + PR_fprintf(debug_out, "thread %d awakened\n", data->index); 1.62 + } 1.63 + PR_ASSERT(rv != 0); 1.64 + PR_ASSERT(pd.out_flags & PR_POLL_READ); 1.65 + if (PR_WaitForPollableEvent(data->event) == PR_FAILURE) { 1.66 + PR_fprintf(PR_STDERR, "consume event failed\n"); 1.67 + exit(1); 1.68 + } 1.69 + if (dally != PR_INTERVAL_NO_WAIT) { 1.70 + PR_Sleep(dally); 1.71 + } 1.72 + if (verbosity) { 1.73 + PR_fprintf(debug_out, "thread %d posting event\n", data->index); 1.74 + } 1.75 + if (PR_SetPollableEvent(data->next->event) == PR_FAILURE) { 1.76 + PR_fprintf(PR_STDERR, "post event failed\n"); 1.77 + exit(1); 1.78 + } 1.79 + } 1.80 +} 1.81 + 1.82 +static void Help(void) 1.83 +{ 1.84 + debug_out = PR_STDOUT; 1.85 + 1.86 + PR_fprintf( 1.87 + debug_out, "Usage: pollable [-c n] [-t n] [-d] [-v] [-G] [-C n] [-D n]\n"); 1.88 + PR_fprintf( 1.89 + debug_out, "-c n\tloops at thread level (default: %d)\n", DEFAULT_LOOPS); 1.90 + PR_fprintf( 1.91 + debug_out, "-t n\tnumber of threads (default: %d)\n", DEFAULT_THREADS); 1.92 + PR_fprintf(debug_out, "-d\tturn on debugging output (default: FALSE)\n"); 1.93 + PR_fprintf(debug_out, "-v\tturn on verbose output (default: FALSE)\n"); 1.94 + PR_fprintf(debug_out, "-G\tglobal threads only (default: FALSE)\n"); 1.95 + PR_fprintf(debug_out, "-C n\tconcurrency setting (default: 1)\n"); 1.96 + PR_fprintf(debug_out, "-D n\tdally setting (msecs) (default: 0)\n"); 1.97 +} /* Help */ 1.98 + 1.99 +int main(int argc, char **argv) 1.100 +{ 1.101 + ThreadData selfData; 1.102 + ThreadData *data; 1.103 + PRThread **thread; 1.104 + void *block; 1.105 + PRIntn i; 1.106 + PRIntervalTime timeStart, timeEnd; 1.107 + PRPollDesc pd; 1.108 + PRInt32 rv; 1.109 + PRThreadScope thread_scope = PR_LOCAL_THREAD; 1.110 + PRBool help = PR_FALSE; 1.111 + PRUintn concurrency = 1; 1.112 + PRUintn average; 1.113 + PLOptStatus os; 1.114 + PLOptState *opt; 1.115 + 1.116 + PR_STDIO_INIT(); 1.117 + 1.118 + opt = PL_CreateOptState(argc, argv, "hdvc:t:C:GD:"); 1.119 + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { 1.120 + if (PL_OPT_BAD == os) { 1.121 + continue; 1.122 + } 1.123 + switch (opt->option) { 1.124 + case 'v': /* verbose mode */ 1.125 + verbosity = PR_TRUE; 1.126 + case 'd': /* debug mode */ 1.127 + debug_mode = PR_TRUE; 1.128 + break; 1.129 + case 'c': /* loop counter */ 1.130 + numIterations = atoi(opt->value); 1.131 + break; 1.132 + case 't': /* thread limit */ 1.133 + numThreads = atoi(opt->value); 1.134 + break; 1.135 + case 'C': /* Concurrency limit */ 1.136 + concurrency = atoi(opt->value); 1.137 + break; 1.138 + case 'G': /* global threads only */ 1.139 + thread_scope = PR_GLOBAL_THREAD; 1.140 + break; 1.141 + case 'D': /* dally */ 1.142 + dally = PR_MillisecondsToInterval(atoi(opt->value)); 1.143 + break; 1.144 + case 'h': /* help message */ 1.145 + Help(); 1.146 + help = PR_TRUE; 1.147 + break; 1.148 + default: 1.149 + break; 1.150 + } 1.151 + } 1.152 + PL_DestroyOptState(opt); 1.153 + 1.154 + if (help) { 1.155 + return 1; 1.156 + } 1.157 + 1.158 + if (concurrency > 1) { 1.159 + PR_SetConcurrency(concurrency); 1.160 + } 1.161 + 1.162 + if (PR_TRUE == debug_mode) { 1.163 + debug_out = PR_STDOUT; 1.164 + PR_fprintf(debug_out, "Test parameters\n"); 1.165 + PR_fprintf(debug_out, "\tThreads involved: %d\n", numThreads); 1.166 + PR_fprintf(debug_out, "\tIteration limit: %d\n", numIterations); 1.167 + PR_fprintf(debug_out, "\tConcurrency: %d\n", concurrency); 1.168 + PR_fprintf(debug_out, "\tThread type: %s\n", 1.169 + (PR_GLOBAL_THREAD == thread_scope) ? "GLOBAL" : "LOCAL"); 1.170 + } 1.171 + 1.172 + /* 1.173 + * Malloc a block of memory and divide it into data and thread. 1.174 + */ 1.175 + block = PR_MALLOC(numThreads * (sizeof(ThreadData) + sizeof(PRThread *))); 1.176 + if (block == NULL) { 1.177 + PR_fprintf(PR_STDERR, "cannot malloc, failed\n"); 1.178 + exit(1); 1.179 + } 1.180 + data = (ThreadData *) block; 1.181 + thread = (PRThread **) &data[numThreads]; 1.182 + 1.183 + /* Pollable event */ 1.184 + selfData.event = PR_NewPollableEvent(); 1.185 + if (selfData.event == NULL) { 1.186 + PR_fprintf(PR_STDERR, "cannot create event: (%ld, %ld)\n", 1.187 + PR_GetError(), PR_GetOSError()); 1.188 + exit(1); 1.189 + } 1.190 + selfData.next = &data[0]; 1.191 + for (i = 0; i < numThreads; i++) { 1.192 + data[i].event = PR_NewPollableEvent(); 1.193 + if (data[i].event == NULL) { 1.194 + PR_fprintf(PR_STDERR, "cannot create event: (%ld, %ld)\n", 1.195 + PR_GetError(), PR_GetOSError()); 1.196 + exit(1); 1.197 + } 1.198 + data[i].index = i; 1.199 + if (i != numThreads - 1) { 1.200 + data[i].next = &data[i + 1]; 1.201 + } else { 1.202 + data[i].next = &selfData; 1.203 + } 1.204 + 1.205 + thread[i] = PR_CreateThread(PR_USER_THREAD, 1.206 + ThreadRoutine, &data[i], PR_PRIORITY_NORMAL, 1.207 + thread_scope, PR_JOINABLE_THREAD, 0); 1.208 + if (thread[i] == NULL) { 1.209 + PR_fprintf(PR_STDERR, "cannot create thread\n"); 1.210 + exit(1); 1.211 + } 1.212 + } 1.213 + 1.214 + timeStart = PR_IntervalNow(); 1.215 + pd.fd = selfData.event; 1.216 + pd.in_flags = PR_POLL_READ; 1.217 + for (i = 0; i < numIterations; i++) { 1.218 + if (dally != PR_INTERVAL_NO_WAIT) { 1.219 + PR_Sleep(dally); 1.220 + } 1.221 + if (verbosity) { 1.222 + PR_fprintf(debug_out, "main thread posting event\n"); 1.223 + } 1.224 + if (PR_SetPollableEvent(selfData.next->event) == PR_FAILURE) { 1.225 + PR_fprintf(PR_STDERR, "set event failed\n"); 1.226 + exit(1); 1.227 + } 1.228 + rv = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT); 1.229 + if (rv == -1) { 1.230 + PR_fprintf(PR_STDERR, "wait failed\n"); 1.231 + exit(1); 1.232 + } 1.233 + PR_ASSERT(rv != 0); 1.234 + PR_ASSERT(pd.out_flags & PR_POLL_READ); 1.235 + if (verbosity) { 1.236 + PR_fprintf(debug_out, "main thread awakened\n"); 1.237 + } 1.238 + if (PR_WaitForPollableEvent(selfData.event) == PR_FAILURE) { 1.239 + PR_fprintf(PR_STDERR, "consume event failed\n"); 1.240 + exit(1); 1.241 + } 1.242 + } 1.243 + timeEnd = PR_IntervalNow(); 1.244 + 1.245 + if (debug_mode) { 1.246 + average = PR_IntervalToMicroseconds(timeEnd - timeStart) 1.247 + / (numIterations * numThreads); 1.248 + PR_fprintf(debug_out, "Average switch times %d usecs for %d threads\n", 1.249 + average, numThreads); 1.250 + } 1.251 + 1.252 + for (i = 0; i < numThreads; i++) { 1.253 + if (PR_JoinThread(thread[i]) == PR_FAILURE) { 1.254 + PR_fprintf(PR_STDERR, "join thread failed\n"); 1.255 + exit(1); 1.256 + } 1.257 + PR_DestroyPollableEvent(data[i].event); 1.258 + } 1.259 + PR_DELETE(block); 1.260 + PR_DestroyPollableEvent(selfData.event); 1.261 + 1.262 + PR_fprintf(PR_STDOUT, "PASSED\n"); 1.263 + return 0; 1.264 +}