nsprpub/pr/tests/cvar.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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 ** 1996 - Netscape Communications Corporation
michael@0 8 **
michael@0 9 ** Name: cvar.c
michael@0 10 **
michael@0 11 ** Description: Tests Condition Variable Operations
michael@0 12 **
michael@0 13 ** Modification History:
michael@0 14 ** 13-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
michael@0 15 ** The debug mode will print all of the printfs associated with this test.
michael@0 16 ** The regress mode will be the default mode. Since the regress tool limits
michael@0 17 ** the output to a one line status:PASS or FAIL,all of the printf statements
michael@0 18 ** have been handled with an if (debug_mode) statement.
michael@0 19 ** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
michael@0 20 ** recognize the return code from tha main program.
michael@0 21 ** 12-June-97 Revert to return code 0 and 1.
michael@0 22 ***********************************************************************/
michael@0 23
michael@0 24 /***********************************************************************
michael@0 25 ** Includes
michael@0 26 ***********************************************************************/
michael@0 27
michael@0 28 #include "nspr.h"
michael@0 29
michael@0 30 /* Used to get the command line option */
michael@0 31 #include "plgetopt.h"
michael@0 32
michael@0 33 #include <stdio.h>
michael@0 34 #include <stdlib.h>
michael@0 35 #include <string.h>
michael@0 36
michael@0 37 PRMonitor *mon;
michael@0 38 #define DEFAULT_COUNT 1000
michael@0 39 PRInt32 count = 0;
michael@0 40 PRIntn debug_mode;
michael@0 41
michael@0 42 #define kQSIZE 1
michael@0 43
michael@0 44 typedef struct {
michael@0 45 PRLock *bufLock;
michael@0 46 int startIdx;
michael@0 47 int numFull;
michael@0 48 PRCondVar *notFull;
michael@0 49 PRCondVar *notEmpty;
michael@0 50 void *data[kQSIZE];
michael@0 51 } CircBuf;
michael@0 52
michael@0 53 static PRBool failed = PR_FALSE;
michael@0 54
michael@0 55 /*
michael@0 56 ** NewCB creates and initializes a new circular buffer.
michael@0 57 */
michael@0 58 static CircBuf* NewCB(void)
michael@0 59 {
michael@0 60 CircBuf *cbp;
michael@0 61
michael@0 62 cbp = PR_NEW(CircBuf);
michael@0 63 if (cbp == NULL)
michael@0 64 return (NULL);
michael@0 65
michael@0 66 cbp->bufLock = PR_NewLock();
michael@0 67 cbp->startIdx = 0;
michael@0 68 cbp->numFull = 0;
michael@0 69 cbp->notFull = PR_NewCondVar(cbp->bufLock);
michael@0 70 cbp->notEmpty = PR_NewCondVar(cbp->bufLock);
michael@0 71
michael@0 72 return (cbp);
michael@0 73 }
michael@0 74
michael@0 75 /*
michael@0 76 ** DeleteCB frees a circular buffer.
michael@0 77 */
michael@0 78 static void DeleteCB(CircBuf *cbp)
michael@0 79 {
michael@0 80 PR_DestroyLock(cbp->bufLock);
michael@0 81 PR_DestroyCondVar(cbp->notFull);
michael@0 82 PR_DestroyCondVar(cbp->notEmpty);
michael@0 83 PR_DELETE(cbp);
michael@0 84 }
michael@0 85
michael@0 86
michael@0 87 /*
michael@0 88 ** PutCBData puts new data on the queue. If the queue is full, it waits
michael@0 89 ** until there is room.
michael@0 90 */
michael@0 91 static void PutCBData(CircBuf *cbp, void *data)
michael@0 92 {
michael@0 93 PR_Lock(cbp->bufLock);
michael@0 94 /* wait while the buffer is full */
michael@0 95 while (cbp->numFull == kQSIZE)
michael@0 96 PR_WaitCondVar(cbp->notFull,PR_INTERVAL_NO_TIMEOUT);
michael@0 97 cbp->data[(cbp->startIdx + cbp->numFull) % kQSIZE] = data;
michael@0 98 cbp->numFull += 1;
michael@0 99
michael@0 100 /* let a waiting reader know that there is data */
michael@0 101 PR_NotifyCondVar(cbp->notEmpty);
michael@0 102 PR_Unlock(cbp->bufLock);
michael@0 103
michael@0 104 }
michael@0 105
michael@0 106
michael@0 107 /*
michael@0 108 ** GetCBData gets the oldest data on the queue. If the queue is empty, it waits
michael@0 109 ** until new data appears.
michael@0 110 */
michael@0 111 static void* GetCBData(CircBuf *cbp)
michael@0 112 {
michael@0 113 void *data;
michael@0 114
michael@0 115 PR_Lock(cbp->bufLock);
michael@0 116 /* wait while the buffer is empty */
michael@0 117 while (cbp->numFull == 0)
michael@0 118 PR_WaitCondVar(cbp->notEmpty,PR_INTERVAL_NO_TIMEOUT);
michael@0 119 data = cbp->data[cbp->startIdx];
michael@0 120 cbp->startIdx =(cbp->startIdx + 1) % kQSIZE;
michael@0 121 cbp->numFull -= 1;
michael@0 122
michael@0 123 /* let a waiting writer know that there is room */
michael@0 124 PR_NotifyCondVar(cbp->notFull);
michael@0 125 PR_Unlock(cbp->bufLock);
michael@0 126
michael@0 127 return (data);
michael@0 128 }
michael@0 129
michael@0 130
michael@0 131 /************************************************************************/
michael@0 132
michael@0 133 static int alive;
michael@0 134
michael@0 135 static void PR_CALLBACK CXReader(void *arg)
michael@0 136 {
michael@0 137 CircBuf *cbp = (CircBuf *)arg;
michael@0 138 PRInt32 i, n;
michael@0 139 void *data;
michael@0 140
michael@0 141 n = count / 2;
michael@0 142 for (i = 0; i < n; i++) {
michael@0 143 data = GetCBData(cbp);
michael@0 144 if ((int)data != i)
michael@0 145 if (debug_mode) printf("data mismatch at for i = %d usec\n", i);
michael@0 146 }
michael@0 147
michael@0 148 PR_EnterMonitor(mon);
michael@0 149 --alive;
michael@0 150 PR_Notify(mon);
michael@0 151 PR_ExitMonitor(mon);
michael@0 152 }
michael@0 153
michael@0 154 static void PR_CALLBACK CXWriter(void *arg)
michael@0 155 {
michael@0 156 CircBuf *cbp = (CircBuf *)arg;
michael@0 157 PRInt32 i, n;
michael@0 158
michael@0 159 n = count / 2;
michael@0 160 for (i = 0; i < n; i++)
michael@0 161 PutCBData(cbp, (void *)i);
michael@0 162
michael@0 163 PR_EnterMonitor(mon);
michael@0 164 --alive;
michael@0 165 PR_Notify(mon);
michael@0 166 PR_ExitMonitor(mon);
michael@0 167 }
michael@0 168
michael@0 169 static void CondWaitContextSwitch(PRThreadScope scope1, PRThreadScope scope2)
michael@0 170 {
michael@0 171 PRThread *t1, *t2;
michael@0 172 CircBuf *cbp;
michael@0 173
michael@0 174 PR_EnterMonitor(mon);
michael@0 175
michael@0 176 alive = 2;
michael@0 177
michael@0 178 cbp = NewCB();
michael@0 179
michael@0 180 t1 = PR_CreateThread(PR_USER_THREAD,
michael@0 181 CXReader, cbp,
michael@0 182 PR_PRIORITY_NORMAL,
michael@0 183 scope1,
michael@0 184 PR_UNJOINABLE_THREAD,
michael@0 185 0);
michael@0 186 PR_ASSERT(t1);
michael@0 187 t2 = PR_CreateThread(PR_USER_THREAD,
michael@0 188 CXWriter, cbp,
michael@0 189 PR_PRIORITY_NORMAL,
michael@0 190 scope2,
michael@0 191 PR_UNJOINABLE_THREAD,
michael@0 192 0);
michael@0 193 PR_ASSERT(t2);
michael@0 194
michael@0 195 /* Wait for both of the threads to exit */
michael@0 196 while (alive) {
michael@0 197 PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT);
michael@0 198 }
michael@0 199
michael@0 200 DeleteCB(cbp);
michael@0 201
michael@0 202 PR_ExitMonitor(mon);
michael@0 203 }
michael@0 204
michael@0 205 static void CondWaitContextSwitchUU(void)
michael@0 206 {
michael@0 207 CondWaitContextSwitch(PR_LOCAL_THREAD, PR_LOCAL_THREAD);
michael@0 208 }
michael@0 209
michael@0 210 static void CondWaitContextSwitchUK(void)
michael@0 211 {
michael@0 212 CondWaitContextSwitch(PR_LOCAL_THREAD, PR_GLOBAL_THREAD);
michael@0 213 }
michael@0 214
michael@0 215 static void CondWaitContextSwitchKK(void)
michael@0 216 {
michael@0 217 CondWaitContextSwitch(PR_GLOBAL_THREAD, PR_GLOBAL_THREAD);
michael@0 218 }
michael@0 219
michael@0 220 /************************************************************************/
michael@0 221
michael@0 222 static void Measure(void (*func)(void), const char *msg)
michael@0 223 {
michael@0 224 PRIntervalTime start, stop;
michael@0 225 double d;
michael@0 226
michael@0 227 start = PR_IntervalNow();
michael@0 228 (*func)();
michael@0 229 stop = PR_IntervalNow();
michael@0 230
michael@0 231 d = (double)PR_IntervalToMicroseconds(stop - start);
michael@0 232
michael@0 233 if (debug_mode) printf("%40s: %6.2f usec\n", msg, d / count);
michael@0 234
michael@0 235 if (0 == d) failed = PR_TRUE;
michael@0 236 }
michael@0 237
michael@0 238 static PRIntn PR_CALLBACK RealMain(int argc, char **argv)
michael@0 239 {
michael@0 240 /* The command line argument: -d is used to determine if the test is being run
michael@0 241 in debug mode. The regress tool requires only one line output:PASS or FAIL.
michael@0 242 All of the printfs associated with this test has been handled with a if (debug_mode)
michael@0 243 test.
michael@0 244 Usage: test_name [-d] [-c n]
michael@0 245 */
michael@0 246 PLOptStatus os;
michael@0 247 PLOptState *opt = PL_CreateOptState(argc, argv, "dc:");
michael@0 248 while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
michael@0 249 {
michael@0 250 if (PL_OPT_BAD == os) continue;
michael@0 251 switch (opt->option)
michael@0 252 {
michael@0 253 case 'd': /* debug mode */
michael@0 254 debug_mode = 1;
michael@0 255 break;
michael@0 256 case 'c': /* loop count */
michael@0 257 count = atoi(opt->value);
michael@0 258 break;
michael@0 259 default:
michael@0 260 break;
michael@0 261 }
michael@0 262 }
michael@0 263 PL_DestroyOptState(opt);
michael@0 264
michael@0 265 if (0 == count) count = DEFAULT_COUNT;
michael@0 266
michael@0 267 mon = PR_NewMonitor();
michael@0 268
michael@0 269 Measure(CondWaitContextSwitchUU, "cond var wait context switch- user/user");
michael@0 270 Measure(CondWaitContextSwitchUK, "cond var wait context switch- user/kernel");
michael@0 271 Measure(CondWaitContextSwitchKK, "cond var wait context switch- kernel/kernel");
michael@0 272
michael@0 273 PR_DestroyMonitor(mon);
michael@0 274
michael@0 275 if (debug_mode) printf("%s\n", (failed) ? "FAILED" : "PASSED");
michael@0 276
michael@0 277 if(failed)
michael@0 278 return 1;
michael@0 279 else
michael@0 280 return 0;
michael@0 281 }
michael@0 282
michael@0 283
michael@0 284 int main(int argc, char *argv[])
michael@0 285 {
michael@0 286 PRIntn rv;
michael@0 287
michael@0 288 PR_STDIO_INIT();
michael@0 289 rv = PR_Initialize(RealMain, argc, argv, 0);
michael@0 290 return rv;
michael@0 291 } /* main */

mercurial