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
11 ** Description: Tests Condition Variable Operations
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 /***********************************************************************
26 ***********************************************************************/
30 /* Used to get the command line option */
38 #define DEFAULT_COUNT 1000
53 static PRBool failed
= PR_FALSE
;
56 ** NewCB creates and initializes a new circular buffer.
58 static CircBuf
* NewCB(void)
62 cbp
= PR_NEW(CircBuf
);
67 cbp
->bufLock
= PR_NewLock();
70 cbp
->notFull
= PR_NewCondVar(cbp
->bufLock
);
71 cbp
->notEmpty
= PR_NewCondVar(cbp
->bufLock
);
77 ** DeleteCB frees a circular buffer.
79 static void DeleteCB(CircBuf
*cbp
)
81 PR_DestroyLock(cbp
->bufLock
);
82 PR_DestroyCondVar(cbp
->notFull
);
83 PR_DestroyCondVar(cbp
->notEmpty
);
89 ** PutCBData puts new data on the queue. If the queue is full, it waits
90 ** until there is room.
92 static void PutCBData(CircBuf
*cbp
, void *data
)
94 PR_Lock(cbp
->bufLock
);
95 /* wait while the buffer is full */
96 while (cbp
->numFull
== kQSIZE
) {
97 PR_WaitCondVar(cbp
->notFull
,PR_INTERVAL_NO_TIMEOUT
);
99 cbp
->data
[(cbp
->startIdx
+ cbp
->numFull
) % kQSIZE
] = data
;
102 /* let a waiting reader know that there is data */
103 PR_NotifyCondVar(cbp
->notEmpty
);
104 PR_Unlock(cbp
->bufLock
);
110 ** GetCBData gets the oldest data on the queue. If the queue is empty, it waits
111 ** until new data appears.
113 static void* GetCBData(CircBuf
*cbp
)
117 PR_Lock(cbp
->bufLock
);
118 /* wait while the buffer is empty */
119 while (cbp
->numFull
== 0) {
120 PR_WaitCondVar(cbp
->notEmpty
,PR_INTERVAL_NO_TIMEOUT
);
122 data
= cbp
->data
[cbp
->startIdx
];
123 cbp
->startIdx
=(cbp
->startIdx
+ 1) % kQSIZE
;
126 /* let a waiting writer know that there is room */
127 PR_NotifyCondVar(cbp
->notFull
);
128 PR_Unlock(cbp
->bufLock
);
134 /************************************************************************/
138 static void PR_CALLBACK
CXReader(void *arg
)
140 CircBuf
*cbp
= (CircBuf
*)arg
;
145 for (i
= 0; i
< n
; i
++) {
146 data
= GetCBData(cbp
);
149 printf("data mismatch at for i = %d usec\n", i
);
153 PR_EnterMonitor(mon
);
159 static void PR_CALLBACK
CXWriter(void *arg
)
161 CircBuf
*cbp
= (CircBuf
*)arg
;
165 for (i
= 0; i
< n
; i
++) {
166 PutCBData(cbp
, (void *)i
);
169 PR_EnterMonitor(mon
);
175 static void CondWaitContextSwitch(PRThreadScope scope1
, PRThreadScope scope2
)
180 PR_EnterMonitor(mon
);
186 t1
= PR_CreateThread(PR_USER_THREAD
,
190 PR_UNJOINABLE_THREAD
,
193 t2
= PR_CreateThread(PR_USER_THREAD
,
197 PR_UNJOINABLE_THREAD
,
201 /* Wait for both of the threads to exit */
203 PR_Wait(mon
, PR_INTERVAL_NO_TIMEOUT
);
211 static void CondWaitContextSwitchUU(void)
213 CondWaitContextSwitch(PR_LOCAL_THREAD
, PR_LOCAL_THREAD
);
216 static void CondWaitContextSwitchUK(void)
218 CondWaitContextSwitch(PR_LOCAL_THREAD
, PR_GLOBAL_THREAD
);
221 static void CondWaitContextSwitchKK(void)
223 CondWaitContextSwitch(PR_GLOBAL_THREAD
, PR_GLOBAL_THREAD
);
226 /************************************************************************/
228 static void Measure(void (*func
)(void), const char *msg
)
230 PRIntervalTime start
, stop
;
233 start
= PR_IntervalNow();
235 stop
= PR_IntervalNow();
237 d
= (double)PR_IntervalToMicroseconds(stop
- start
);
240 printf("%40s: %6.2f usec\n", msg
, d
/ count
);
248 static PRIntn PR_CALLBACK
RealMain(int argc
, char **argv
)
250 /* The command line argument: -d is used to determine if the test is being run
251 in debug mode. The regress tool requires only one line output:PASS or FAIL.
252 All of the printfs associated with this test has been handled with a if (debug_mode)
254 Usage: test_name [-d] [-c n]
257 PLOptState
*opt
= PL_CreateOptState(argc
, argv
, "dc:");
258 while (PL_OPT_EOL
!= (os
= PL_GetNextOpt(opt
)))
260 if (PL_OPT_BAD
== os
) {
265 case 'd': /* debug mode */
268 case 'c': /* loop count */
269 count
= atoi(opt
->value
);
275 PL_DestroyOptState(opt
);
278 count
= DEFAULT_COUNT
;
281 mon
= PR_NewMonitor();
283 Measure(CondWaitContextSwitchUU
, "cond var wait context switch- user/user");
284 Measure(CondWaitContextSwitchUK
, "cond var wait context switch- user/kernel");
285 Measure(CondWaitContextSwitchKK
, "cond var wait context switch- kernel/kernel");
287 PR_DestroyMonitor(mon
);
290 printf("%s\n", (failed
) ? "FAILED" : "PASSED");
302 int main(int argc
, char *argv
[])
307 rv
= PR_Initialize(RealMain
, argc
, argv
, 0);