1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/nsprpub/pr/tests/cvar.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,291 @@ 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 +** 1996 - Netscape Communications Corporation 1.11 +** 1.12 +** Name: cvar.c 1.13 +** 1.14 +** Description: Tests Condition Variable Operations 1.15 +** 1.16 +** Modification History: 1.17 +** 13-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. 1.18 +** The debug mode will print all of the printfs associated with this test. 1.19 +** The regress mode will be the default mode. Since the regress tool limits 1.20 +** the output to a one line status:PASS or FAIL,all of the printf statements 1.21 +** have been handled with an if (debug_mode) statement. 1.22 +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to 1.23 +** recognize the return code from tha main program. 1.24 +** 12-June-97 Revert to return code 0 and 1. 1.25 +***********************************************************************/ 1.26 + 1.27 +/*********************************************************************** 1.28 +** Includes 1.29 +***********************************************************************/ 1.30 + 1.31 +#include "nspr.h" 1.32 + 1.33 +/* Used to get the command line option */ 1.34 +#include "plgetopt.h" 1.35 + 1.36 +#include <stdio.h> 1.37 +#include <stdlib.h> 1.38 +#include <string.h> 1.39 + 1.40 +PRMonitor *mon; 1.41 +#define DEFAULT_COUNT 1000 1.42 +PRInt32 count = 0; 1.43 +PRIntn debug_mode; 1.44 + 1.45 +#define kQSIZE 1 1.46 + 1.47 +typedef struct { 1.48 + PRLock *bufLock; 1.49 + int startIdx; 1.50 + int numFull; 1.51 + PRCondVar *notFull; 1.52 + PRCondVar *notEmpty; 1.53 + void *data[kQSIZE]; 1.54 +} CircBuf; 1.55 + 1.56 +static PRBool failed = PR_FALSE; 1.57 + 1.58 +/* 1.59 +** NewCB creates and initializes a new circular buffer. 1.60 +*/ 1.61 +static CircBuf* NewCB(void) 1.62 +{ 1.63 + CircBuf *cbp; 1.64 + 1.65 + cbp = PR_NEW(CircBuf); 1.66 + if (cbp == NULL) 1.67 + return (NULL); 1.68 + 1.69 + cbp->bufLock = PR_NewLock(); 1.70 + cbp->startIdx = 0; 1.71 + cbp->numFull = 0; 1.72 + cbp->notFull = PR_NewCondVar(cbp->bufLock); 1.73 + cbp->notEmpty = PR_NewCondVar(cbp->bufLock); 1.74 + 1.75 + return (cbp); 1.76 +} 1.77 + 1.78 +/* 1.79 +** DeleteCB frees a circular buffer. 1.80 +*/ 1.81 +static void DeleteCB(CircBuf *cbp) 1.82 +{ 1.83 + PR_DestroyLock(cbp->bufLock); 1.84 + PR_DestroyCondVar(cbp->notFull); 1.85 + PR_DestroyCondVar(cbp->notEmpty); 1.86 + PR_DELETE(cbp); 1.87 +} 1.88 + 1.89 + 1.90 +/* 1.91 +** PutCBData puts new data on the queue. If the queue is full, it waits 1.92 +** until there is room. 1.93 +*/ 1.94 +static void PutCBData(CircBuf *cbp, void *data) 1.95 +{ 1.96 + PR_Lock(cbp->bufLock); 1.97 + /* wait while the buffer is full */ 1.98 + while (cbp->numFull == kQSIZE) 1.99 + PR_WaitCondVar(cbp->notFull,PR_INTERVAL_NO_TIMEOUT); 1.100 + cbp->data[(cbp->startIdx + cbp->numFull) % kQSIZE] = data; 1.101 + cbp->numFull += 1; 1.102 + 1.103 + /* let a waiting reader know that there is data */ 1.104 + PR_NotifyCondVar(cbp->notEmpty); 1.105 + PR_Unlock(cbp->bufLock); 1.106 + 1.107 +} 1.108 + 1.109 + 1.110 +/* 1.111 +** GetCBData gets the oldest data on the queue. If the queue is empty, it waits 1.112 +** until new data appears. 1.113 +*/ 1.114 +static void* GetCBData(CircBuf *cbp) 1.115 +{ 1.116 + void *data; 1.117 + 1.118 + PR_Lock(cbp->bufLock); 1.119 + /* wait while the buffer is empty */ 1.120 + while (cbp->numFull == 0) 1.121 + PR_WaitCondVar(cbp->notEmpty,PR_INTERVAL_NO_TIMEOUT); 1.122 + data = cbp->data[cbp->startIdx]; 1.123 + cbp->startIdx =(cbp->startIdx + 1) % kQSIZE; 1.124 + cbp->numFull -= 1; 1.125 + 1.126 + /* let a waiting writer know that there is room */ 1.127 + PR_NotifyCondVar(cbp->notFull); 1.128 + PR_Unlock(cbp->bufLock); 1.129 + 1.130 + return (data); 1.131 +} 1.132 + 1.133 + 1.134 +/************************************************************************/ 1.135 + 1.136 +static int alive; 1.137 + 1.138 +static void PR_CALLBACK CXReader(void *arg) 1.139 +{ 1.140 + CircBuf *cbp = (CircBuf *)arg; 1.141 + PRInt32 i, n; 1.142 + void *data; 1.143 + 1.144 + n = count / 2; 1.145 + for (i = 0; i < n; i++) { 1.146 + data = GetCBData(cbp); 1.147 + if ((int)data != i) 1.148 + if (debug_mode) printf("data mismatch at for i = %d usec\n", i); 1.149 + } 1.150 + 1.151 + PR_EnterMonitor(mon); 1.152 + --alive; 1.153 + PR_Notify(mon); 1.154 + PR_ExitMonitor(mon); 1.155 +} 1.156 + 1.157 +static void PR_CALLBACK CXWriter(void *arg) 1.158 +{ 1.159 + CircBuf *cbp = (CircBuf *)arg; 1.160 + PRInt32 i, n; 1.161 + 1.162 + n = count / 2; 1.163 + for (i = 0; i < n; i++) 1.164 + PutCBData(cbp, (void *)i); 1.165 + 1.166 + PR_EnterMonitor(mon); 1.167 + --alive; 1.168 + PR_Notify(mon); 1.169 + PR_ExitMonitor(mon); 1.170 +} 1.171 + 1.172 +static void CondWaitContextSwitch(PRThreadScope scope1, PRThreadScope scope2) 1.173 +{ 1.174 + PRThread *t1, *t2; 1.175 + CircBuf *cbp; 1.176 + 1.177 + PR_EnterMonitor(mon); 1.178 + 1.179 + alive = 2; 1.180 + 1.181 + cbp = NewCB(); 1.182 + 1.183 + t1 = PR_CreateThread(PR_USER_THREAD, 1.184 + CXReader, cbp, 1.185 + PR_PRIORITY_NORMAL, 1.186 + scope1, 1.187 + PR_UNJOINABLE_THREAD, 1.188 + 0); 1.189 + PR_ASSERT(t1); 1.190 + t2 = PR_CreateThread(PR_USER_THREAD, 1.191 + CXWriter, cbp, 1.192 + PR_PRIORITY_NORMAL, 1.193 + scope2, 1.194 + PR_UNJOINABLE_THREAD, 1.195 + 0); 1.196 + PR_ASSERT(t2); 1.197 + 1.198 + /* Wait for both of the threads to exit */ 1.199 + while (alive) { 1.200 + PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT); 1.201 + } 1.202 + 1.203 + DeleteCB(cbp); 1.204 + 1.205 + PR_ExitMonitor(mon); 1.206 +} 1.207 + 1.208 +static void CondWaitContextSwitchUU(void) 1.209 +{ 1.210 + CondWaitContextSwitch(PR_LOCAL_THREAD, PR_LOCAL_THREAD); 1.211 +} 1.212 + 1.213 +static void CondWaitContextSwitchUK(void) 1.214 +{ 1.215 + CondWaitContextSwitch(PR_LOCAL_THREAD, PR_GLOBAL_THREAD); 1.216 +} 1.217 + 1.218 +static void CondWaitContextSwitchKK(void) 1.219 +{ 1.220 + CondWaitContextSwitch(PR_GLOBAL_THREAD, PR_GLOBAL_THREAD); 1.221 +} 1.222 + 1.223 +/************************************************************************/ 1.224 + 1.225 +static void Measure(void (*func)(void), const char *msg) 1.226 +{ 1.227 + PRIntervalTime start, stop; 1.228 + double d; 1.229 + 1.230 + start = PR_IntervalNow(); 1.231 + (*func)(); 1.232 + stop = PR_IntervalNow(); 1.233 + 1.234 + d = (double)PR_IntervalToMicroseconds(stop - start); 1.235 + 1.236 + if (debug_mode) printf("%40s: %6.2f usec\n", msg, d / count); 1.237 + 1.238 + if (0 == d) failed = PR_TRUE; 1.239 +} 1.240 + 1.241 +static PRIntn PR_CALLBACK RealMain(int argc, char **argv) 1.242 +{ 1.243 + /* The command line argument: -d is used to determine if the test is being run 1.244 + in debug mode. The regress tool requires only one line output:PASS or FAIL. 1.245 + All of the printfs associated with this test has been handled with a if (debug_mode) 1.246 + test. 1.247 + Usage: test_name [-d] [-c n] 1.248 + */ 1.249 + PLOptStatus os; 1.250 + PLOptState *opt = PL_CreateOptState(argc, argv, "dc:"); 1.251 + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) 1.252 + { 1.253 + if (PL_OPT_BAD == os) continue; 1.254 + switch (opt->option) 1.255 + { 1.256 + case 'd': /* debug mode */ 1.257 + debug_mode = 1; 1.258 + break; 1.259 + case 'c': /* loop count */ 1.260 + count = atoi(opt->value); 1.261 + break; 1.262 + default: 1.263 + break; 1.264 + } 1.265 + } 1.266 + PL_DestroyOptState(opt); 1.267 + 1.268 + if (0 == count) count = DEFAULT_COUNT; 1.269 + 1.270 + mon = PR_NewMonitor(); 1.271 + 1.272 + Measure(CondWaitContextSwitchUU, "cond var wait context switch- user/user"); 1.273 + Measure(CondWaitContextSwitchUK, "cond var wait context switch- user/kernel"); 1.274 + Measure(CondWaitContextSwitchKK, "cond var wait context switch- kernel/kernel"); 1.275 + 1.276 + PR_DestroyMonitor(mon); 1.277 + 1.278 + if (debug_mode) printf("%s\n", (failed) ? "FAILED" : "PASSED"); 1.279 + 1.280 + if(failed) 1.281 + return 1; 1.282 + else 1.283 + return 0; 1.284 +} 1.285 + 1.286 + 1.287 +int main(int argc, char *argv[]) 1.288 +{ 1.289 + PRIntn rv; 1.290 + 1.291 + PR_STDIO_INIT(); 1.292 + rv = PR_Initialize(RealMain, argc, argv, 0); 1.293 + return rv; 1.294 +} /* main */