nsprpub/pr/tests/pollable.c

changeset 0
6474c204b198
     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 +}

mercurial