Upload Tizen:Base source
[toolchains/nspr.git] / mozilla / nsprpub / pr / tests / pollable.c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4  *
5  * The contents of this file are subject to the Mozilla Public License Version
6  * 1.1 (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  * http://www.mozilla.org/MPL/
9  *
10  * Software distributed under the License is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12  * for the specific language governing rights and limitations under the
13  * License.
14  *
15  * The Original Code is the Netscape Portable Runtime (NSPR).
16  *
17  * The Initial Developer of the Original Code is
18  * Netscape Communications Corporation.
19  * Portions created by the Initial Developer are Copyright (C) 1998-2000
20  * the Initial Developer. All Rights Reserved.
21  *
22  * Contributor(s):
23  *
24  * Alternatively, the contents of this file may be used under the terms of
25  * either the GNU General Public License Version 2 or later (the "GPL"), or
26  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27  * in which case the provisions of the GPL or the LGPL are applicable instead
28  * of those above. If you wish to allow use of your version of this file only
29  * under the terms of either the GPL or the LGPL, and not to allow others to
30  * use your version of this file under the terms of the MPL, indicate your
31  * decision by deleting the provisions above and replace them with the notice
32  * and other provisions required by the GPL or the LGPL. If you do not delete
33  * the provisions above, a recipient may use your version of this file under
34  * the terms of any one of the MPL, the GPL or the LGPL.
35  *
36  * ***** END LICENSE BLOCK ***** */
37
38 /*
39  * A test for the pollable events.
40  *
41  * A number of threads are in a ring configuration, each waiting on
42  * a pollable event that is set by its upstream neighbor.
43  */
44
45 #include "prinit.h"
46 #include "prio.h"
47 #include "prthread.h"
48 #include "prerror.h"
49 #include "prmem.h"
50 #include "prlog.h"
51 #include "prprf.h"
52
53 #include "plgetopt.h"
54
55 #include <stdlib.h>
56
57 #define DEFAULT_THREADS 10
58 #define DEFAULT_LOOPS 100
59
60 PRIntn numThreads = DEFAULT_THREADS;
61 PRIntn numIterations = DEFAULT_LOOPS;
62 PRIntervalTime dally = PR_INTERVAL_NO_WAIT;
63 PRFileDesc *debug_out = NULL;
64 PRBool debug_mode = PR_FALSE;
65 PRBool verbosity = PR_FALSE;
66
67 typedef struct ThreadData {
68     PRFileDesc *event;
69     int index;
70     struct ThreadData *next;
71 } ThreadData;
72
73 void ThreadRoutine(void *arg)
74 {
75     ThreadData *data = (ThreadData *) arg;
76     PRIntn i;
77     PRPollDesc pd;
78     PRInt32 rv;
79
80     pd.fd = data->event;
81     pd.in_flags = PR_POLL_READ;
82
83     for (i = 0; i < numIterations; i++) {
84         rv = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT);
85         if (rv == -1) {
86             PR_fprintf(PR_STDERR, "PR_Poll failed\n");
87             exit(1);
88         }
89         if (verbosity) {
90             PR_fprintf(debug_out, "thread %d awakened\n", data->index);
91         }
92         PR_ASSERT(rv != 0);
93         PR_ASSERT(pd.out_flags & PR_POLL_READ);
94         if (PR_WaitForPollableEvent(data->event) == PR_FAILURE) {
95             PR_fprintf(PR_STDERR, "consume event failed\n");
96             exit(1);
97         }
98         if (dally != PR_INTERVAL_NO_WAIT) {
99             PR_Sleep(dally);
100         }
101         if (verbosity) {
102             PR_fprintf(debug_out, "thread %d posting event\n", data->index);
103         }
104         if (PR_SetPollableEvent(data->next->event) == PR_FAILURE) {
105             PR_fprintf(PR_STDERR, "post event failed\n");
106             exit(1);
107         }
108     }
109 }
110
111 static void Help(void)
112 {
113     debug_out = PR_STDOUT;
114
115     PR_fprintf(
116             debug_out, "Usage: pollable [-c n] [-t n] [-d] [-v] [-G] [-C n] [-D n]\n");
117     PR_fprintf(
118             debug_out, "-c n\tloops at thread level (default: %d)\n", DEFAULT_LOOPS);
119     PR_fprintf(
120             debug_out, "-t n\tnumber of threads (default: %d)\n", DEFAULT_THREADS);
121     PR_fprintf(debug_out, "-d\tturn on debugging output (default: FALSE)\n");
122     PR_fprintf(debug_out, "-v\tturn on verbose output (default: FALSE)\n");
123     PR_fprintf(debug_out, "-G\tglobal threads only (default: FALSE)\n");
124     PR_fprintf(debug_out, "-C n\tconcurrency setting (default: 1)\n");
125     PR_fprintf(debug_out, "-D n\tdally setting (msecs) (default: 0)\n");
126 }  /* Help */
127
128 int main(int argc, char **argv)
129 {
130     ThreadData selfData;
131     ThreadData *data;
132     PRThread **thread;
133     void *block;
134     PRIntn i;
135     PRIntervalTime timeStart, timeEnd;
136     PRPollDesc pd;
137     PRInt32 rv;
138     PRThreadScope thread_scope = PR_LOCAL_THREAD;
139     PRBool help = PR_FALSE;
140     PRUintn concurrency = 1;
141     PRUintn average;
142     PLOptStatus os;
143     PLOptState *opt;
144
145     PR_STDIO_INIT();
146
147     opt = PL_CreateOptState(argc, argv, "hdvc:t:C:GD:");
148     while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) {
149         if (PL_OPT_BAD == os) {
150             continue;
151         }
152         switch (opt->option) {
153             case 'v':  /* verbose mode */
154                 verbosity = PR_TRUE;
155             case 'd':  /* debug mode */
156                 debug_mode = PR_TRUE;
157                 break;
158             case 'c':  /* loop counter */
159                 numIterations = atoi(opt->value);
160                 break;
161             case 't':  /* thread limit */
162                 numThreads = atoi(opt->value);
163                 break;
164             case 'C':  /* Concurrency limit */
165                 concurrency = atoi(opt->value);
166                 break;
167             case 'G':  /* global threads only */
168                 thread_scope = PR_GLOBAL_THREAD;
169                 break;
170             case 'D':  /* dally */
171                 dally = PR_MillisecondsToInterval(atoi(opt->value));
172                 break;
173             case 'h':  /* help message */
174                 Help();
175                 help = PR_TRUE;
176                 break;
177             default:
178                 break;
179         }
180     }
181     PL_DestroyOptState(opt);
182
183     if (help) {
184         return 1;
185     }
186
187     if (concurrency > 1) {
188         PR_SetConcurrency(concurrency);
189     }
190
191     if (PR_TRUE == debug_mode) {
192         debug_out = PR_STDOUT;
193         PR_fprintf(debug_out, "Test parameters\n");
194         PR_fprintf(debug_out, "\tThreads involved: %d\n", numThreads);
195         PR_fprintf(debug_out, "\tIteration limit: %d\n", numIterations);
196         PR_fprintf(debug_out, "\tConcurrency: %d\n", concurrency);
197         PR_fprintf(debug_out, "\tThread type: %s\n",
198                 (PR_GLOBAL_THREAD == thread_scope) ? "GLOBAL" : "LOCAL");
199     }
200
201     /*
202      * Malloc a block of memory and divide it into data and thread.
203      */
204     block = PR_MALLOC(numThreads * (sizeof(ThreadData) + sizeof(PRThread *)));
205     if (block == NULL) {
206         PR_fprintf(PR_STDERR, "cannot malloc, failed\n");
207         exit(1);
208     }
209     data = (ThreadData *) block;
210     thread = (PRThread **) &data[numThreads];
211
212     /* Pollable event */
213     selfData.event = PR_NewPollableEvent();
214     if (selfData.event == NULL) {
215         PR_fprintf(PR_STDERR, "cannot create event: (%ld, %ld)\n",
216                 PR_GetError(), PR_GetOSError());
217         exit(1);
218     }
219     selfData.next = &data[0];
220     for (i = 0; i < numThreads; i++) {
221         data[i].event = PR_NewPollableEvent();
222         if (data[i].event == NULL) {
223             PR_fprintf(PR_STDERR, "cannot create event: (%ld, %ld)\n",
224                     PR_GetError(), PR_GetOSError());
225             exit(1);
226         }
227         data[i].index = i;
228         if (i != numThreads - 1) {
229             data[i].next = &data[i + 1];
230         } else {
231             data[i].next = &selfData;
232         }
233
234         thread[i] = PR_CreateThread(PR_USER_THREAD,
235                 ThreadRoutine, &data[i], PR_PRIORITY_NORMAL,
236                 thread_scope, PR_JOINABLE_THREAD, 0);
237         if (thread[i] == NULL) {
238             PR_fprintf(PR_STDERR, "cannot create thread\n");
239             exit(1);
240         }
241     }
242
243     timeStart = PR_IntervalNow();
244     pd.fd = selfData.event;
245     pd.in_flags = PR_POLL_READ;
246     for (i = 0; i < numIterations; i++) {
247         if (dally != PR_INTERVAL_NO_WAIT) {
248             PR_Sleep(dally);
249         }
250         if (verbosity) {
251             PR_fprintf(debug_out, "main thread posting event\n");
252         }
253         if (PR_SetPollableEvent(selfData.next->event) == PR_FAILURE) {
254             PR_fprintf(PR_STDERR, "set event failed\n");
255             exit(1);
256         }
257         rv = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT);
258         if (rv == -1) {
259             PR_fprintf(PR_STDERR, "wait failed\n");
260             exit(1);
261         }
262         PR_ASSERT(rv != 0);
263         PR_ASSERT(pd.out_flags & PR_POLL_READ);
264         if (verbosity) {
265             PR_fprintf(debug_out, "main thread awakened\n");
266         }
267         if (PR_WaitForPollableEvent(selfData.event) == PR_FAILURE) {
268             PR_fprintf(PR_STDERR, "consume event failed\n");
269             exit(1);
270         }
271     }
272     timeEnd = PR_IntervalNow();
273
274     if (debug_mode) {
275         average = PR_IntervalToMicroseconds(timeEnd - timeStart)
276                 / (numIterations * numThreads);
277         PR_fprintf(debug_out, "Average switch times %d usecs for %d threads\n",
278                 average, numThreads);
279     }
280
281     for (i = 0; i < numThreads; i++) {
282         if (PR_JoinThread(thread[i]) == PR_FAILURE) {
283             PR_fprintf(PR_STDERR, "join thread failed\n");
284             exit(1);
285         }
286         PR_DestroyPollableEvent(data[i].event);
287     }
288     PR_DELETE(block);
289         PR_DestroyPollableEvent(selfData.event);
290
291     PR_fprintf(PR_STDOUT, "PASSED\n");
292     return 0;
293 }