nsprpub/pr/tests/cvar.c

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

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

mercurial