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
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/
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
15 * The Original Code is the Netscape Portable Runtime (NSPR).
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1999-2000
20 * the Initial Developer. All Rights Reserved.
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.
36 * ***** END LICENSE BLOCK ***** */
42 * This test tests the interval time facilities in NSPR for Y2K
43 * compliance. All the functions that take a timeout argument
44 * are tested: PR_Sleep, socket I/O (PR_Accept is taken as a
45 * representative), PR_Poll, PR_WaitCondVar, PR_Wait, and
46 * PR_CWait. A thread of each thread scope (local, global, and
47 * global bound) is created to call each of these functions.
48 * The test should be started at the specified number of seconds
49 * (called the lead time) before a Y2K rollover test date. The
50 * timeout values for these threads will span over the rollover
51 * date by at least the specified number of seconds. For
52 * example, if the lead time is 5 seconds, the test should
53 * be started at time (D - 5), where D is a rollover date, and
54 * the threads will time out at or after time (D + 5). The
55 * timeout values for the threads are spaced one second apart.
57 * When a thread times out, it calls PR_IntervalNow() to verify
58 * that it did wait for the specified time. In addition, it
59 * calls a platform-native function to verify the actual elapsed
60 * time again, to rule out the possibility that PR_IntervalNow()
61 * is broken. We allow the actual elapsed time to deviate from
62 * the specified timeout by a certain tolerance (in milliseconds).
72 #include <sys/time.h> /* for gettimeofday */
78 #include <sys/types.h>
79 #include <sys/timeb.h> /* for _ftime */
83 #define DEFAULT_LEAD_TIME_SECS 5
84 #define DEFAULT_TOLERANCE_MSECS 500
86 static PRBool debug_mode = PR_FALSE;
87 static PRInt32 lead_time_secs = DEFAULT_LEAD_TIME_SECS;
88 static PRInt32 tolerance_msecs = DEFAULT_TOLERANCE_MSECS;
89 static PRIntervalTime start_time;
90 static PRIntervalTime tolerance;
93 static struct timeval start_time_tv;
97 static DWORD start_time_tick;
99 static struct _timeb start_time_tb;
103 static void SleepThread(void *arg)
105 PRIntervalTime timeout = (PRIntervalTime) arg;
106 PRIntervalTime elapsed;
107 #if defined(XP_UNIX) || defined(WIN32)
108 PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout);
109 PRInt32 elapsed_msecs;
112 struct timeval end_time_tv;
114 #if defined(WIN32) && !defined(WINCE)
115 struct _timeb end_time_tb;
118 if (PR_Sleep(timeout) == PR_FAILURE) {
119 fprintf(stderr, "PR_Sleep failed\n");
122 elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
123 if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
124 fprintf(stderr, "timeout wrong\n");
128 gettimeofday(&end_time_tv, NULL);
129 elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec)
130 + (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000;
134 elapsed_msecs = GetTickCount() - start_time_tick;
136 _ftime(&end_time_tb);
137 elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time)
138 + (end_time_tb.millitm - start_time_tb.millitm);
141 #if defined(XP_UNIX) || defined(WIN32)
142 if (elapsed_msecs + tolerance_msecs < timeout_msecs
143 || elapsed_msecs > timeout_msecs + tolerance_msecs) {
144 fprintf(stderr, "timeout wrong\n");
149 fprintf(stderr, "Sleep thread (scope %d) done\n",
150 PR_GetThreadScope(PR_GetCurrentThread()));
154 static void AcceptThread(void *arg)
156 PRIntervalTime timeout = (PRIntervalTime) arg;
157 PRIntervalTime elapsed;
158 #if defined(XP_UNIX) || defined(WIN32)
159 PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout);
160 PRInt32 elapsed_msecs;
163 struct timeval end_time_tv;
165 #if defined(WIN32) && !defined(WINCE)
166 struct _timeb end_time_tb;
170 PRFileDesc *accepted;
172 sock = PR_NewTCPSocket();
174 fprintf(stderr, "PR_NewTCPSocket failed\n");
177 memset(&addr, 0, sizeof(addr));
178 addr.inet.family = PR_AF_INET;
180 addr.inet.ip = PR_htonl(PR_INADDR_ANY);
181 if (PR_Bind(sock, &addr) == PR_FAILURE) {
182 fprintf(stderr, "PR_Bind failed\n");
185 if (PR_Listen(sock, 5) == PR_FAILURE) {
186 fprintf(stderr, "PR_Listen failed\n");
189 accepted = PR_Accept(sock, NULL, timeout);
190 if (accepted != NULL || PR_GetError() != PR_IO_TIMEOUT_ERROR) {
191 fprintf(stderr, "PR_Accept did not time out\n");
194 elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
195 if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
196 fprintf(stderr, "timeout wrong\n");
200 gettimeofday(&end_time_tv, NULL);
201 elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec)
202 + (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000;
206 elapsed_msecs = GetTickCount() - start_time_tick;
208 _ftime(&end_time_tb);
209 elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time)
210 + (end_time_tb.millitm - start_time_tb.millitm);
213 #if defined(XP_UNIX) || defined(WIN32)
214 if (elapsed_msecs + tolerance_msecs < timeout_msecs
215 || elapsed_msecs > timeout_msecs + tolerance_msecs) {
216 fprintf(stderr, "timeout wrong\n");
220 if (PR_Close(sock) == PR_FAILURE) {
221 fprintf(stderr, "PR_Close failed\n");
225 fprintf(stderr, "Accept thread (scope %d) done\n",
226 PR_GetThreadScope(PR_GetCurrentThread()));
230 static void PollThread(void *arg)
232 PRIntervalTime timeout = (PRIntervalTime) arg;
233 PRIntervalTime elapsed;
234 #if defined(XP_UNIX) || defined(WIN32)
235 PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout);
236 PRInt32 elapsed_msecs;
239 struct timeval end_time_tv;
241 #if defined(WIN32) && !defined(WINCE)
242 struct _timeb end_time_tb;
249 sock = PR_NewTCPSocket();
251 fprintf(stderr, "PR_NewTCPSocket failed\n");
254 memset(&addr, 0, sizeof(addr));
255 addr.inet.family = PR_AF_INET;
257 addr.inet.ip = PR_htonl(PR_INADDR_ANY);
258 if (PR_Bind(sock, &addr) == PR_FAILURE) {
259 fprintf(stderr, "PR_Bind failed\n");
262 if (PR_Listen(sock, 5) == PR_FAILURE) {
263 fprintf(stderr, "PR_Listen failed\n");
267 pd.in_flags = PR_POLL_READ;
268 rv = PR_Poll(&pd, 1, timeout);
270 fprintf(stderr, "PR_Poll did not time out\n");
273 elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
274 if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
275 fprintf(stderr, "timeout wrong\n");
279 gettimeofday(&end_time_tv, NULL);
280 elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec)
281 + (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000;
285 elapsed_msecs = GetTickCount() - start_time_tick;
287 _ftime(&end_time_tb);
288 elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time)
289 + (end_time_tb.millitm - start_time_tb.millitm);
292 #if defined(XP_UNIX) || defined(WIN32)
293 if (elapsed_msecs + tolerance_msecs < timeout_msecs
294 || elapsed_msecs > timeout_msecs + tolerance_msecs) {
295 fprintf(stderr, "timeout wrong\n");
299 if (PR_Close(sock) == PR_FAILURE) {
300 fprintf(stderr, "PR_Close failed\n");
304 fprintf(stderr, "Poll thread (scope %d) done\n",
305 PR_GetThreadScope(PR_GetCurrentThread()));
309 static void WaitCondVarThread(void *arg)
311 PRIntervalTime timeout = (PRIntervalTime) arg;
312 PRIntervalTime elapsed;
313 #if defined(XP_UNIX) || defined(WIN32)
314 PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout);
315 PRInt32 elapsed_msecs;
318 struct timeval end_time_tv;
320 #if defined(WIN32) && !defined(WINCE)
321 struct _timeb end_time_tb;
328 fprintf(stderr, "PR_NewLock failed\n");
331 cv = PR_NewCondVar(ml);
333 fprintf(stderr, "PR_NewCondVar failed\n");
337 PR_WaitCondVar(cv, timeout);
339 elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
340 if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
341 fprintf(stderr, "timeout wrong\n");
345 gettimeofday(&end_time_tv, NULL);
346 elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec)
347 + (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000;
351 elapsed_msecs = GetTickCount() - start_time_tick;
353 _ftime(&end_time_tb);
354 elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time)
355 + (end_time_tb.millitm - start_time_tb.millitm);
358 #if defined(XP_UNIX) || defined(WIN32)
359 if (elapsed_msecs + tolerance_msecs < timeout_msecs
360 || elapsed_msecs > timeout_msecs + tolerance_msecs) {
361 fprintf(stderr, "timeout wrong\n");
365 PR_DestroyCondVar(cv);
368 fprintf(stderr, "wait cond var thread (scope %d) done\n",
369 PR_GetThreadScope(PR_GetCurrentThread()));
373 static void WaitMonitorThread(void *arg)
375 PRIntervalTime timeout = (PRIntervalTime) arg;
376 PRIntervalTime elapsed;
377 #if defined(XP_UNIX) || defined(WIN32)
378 PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout);
379 PRInt32 elapsed_msecs;
382 struct timeval end_time_tv;
384 #if defined(WIN32) && !defined(WINCE)
385 struct _timeb end_time_tb;
389 mon = PR_NewMonitor();
391 fprintf(stderr, "PR_NewMonitor failed\n");
394 PR_EnterMonitor(mon);
395 PR_Wait(mon, timeout);
397 elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
398 if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
399 fprintf(stderr, "timeout wrong\n");
403 gettimeofday(&end_time_tv, NULL);
404 elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec)
405 + (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000;
409 elapsed_msecs = GetTickCount() - start_time_tick;
411 _ftime(&end_time_tb);
412 elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time)
413 + (end_time_tb.millitm - start_time_tb.millitm);
416 #if defined(XP_UNIX) || defined(WIN32)
417 if (elapsed_msecs + tolerance_msecs < timeout_msecs
418 || elapsed_msecs > timeout_msecs + tolerance_msecs) {
419 fprintf(stderr, "timeout wrong\n");
423 PR_DestroyMonitor(mon);
425 fprintf(stderr, "wait monitor thread (scope %d) done\n",
426 PR_GetThreadScope(PR_GetCurrentThread()));
430 static void WaitCMonitorThread(void *arg)
432 PRIntervalTime timeout = (PRIntervalTime) arg;
433 PRIntervalTime elapsed;
434 #if defined(XP_UNIX) || defined(WIN32)
435 PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout);
436 PRInt32 elapsed_msecs;
439 struct timeval end_time_tv;
441 #if defined(WIN32) && !defined(WINCE)
442 struct _timeb end_time_tb;
446 PR_CEnterMonitor(&dummy);
447 PR_CWait(&dummy, timeout);
448 PR_CExitMonitor(&dummy);
449 elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
450 if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
451 fprintf(stderr, "timeout wrong\n");
455 gettimeofday(&end_time_tv, NULL);
456 elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec)
457 + (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000;
461 elapsed_msecs = GetTickCount() - start_time_tick;
463 _ftime(&end_time_tb);
464 elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time)
465 + (end_time_tb.millitm - start_time_tb.millitm);
468 #if defined(XP_UNIX) || defined(WIN32)
469 if (elapsed_msecs + tolerance_msecs < timeout_msecs
470 || elapsed_msecs > timeout_msecs + tolerance_msecs) {
471 fprintf(stderr, "timeout wrong\n");
476 fprintf(stderr, "wait cached monitor thread (scope %d) done\n",
477 PR_GetThreadScope(PR_GetCurrentThread()));
481 typedef void (*NSPRThreadFunc)(void*);
483 static NSPRThreadFunc threadFuncs[] = {
484 SleepThread, AcceptThread, PollThread,
485 WaitCondVarThread, WaitMonitorThread, WaitCMonitorThread};
487 static PRThreadScope threadScopes[] = {
488 PR_LOCAL_THREAD, PR_GLOBAL_THREAD, PR_GLOBAL_BOUND_THREAD};
490 static void Help(void)
492 fprintf(stderr, "y2ktmo test program usage:\n");
493 fprintf(stderr, "\t-d debug mode (FALSE)\n");
494 fprintf(stderr, "\t-l <secs> lead time (%d)\n",
495 DEFAULT_LEAD_TIME_SECS);
496 fprintf(stderr, "\t-t <msecs> tolerance (%d)\n",
497 DEFAULT_TOLERANCE_MSECS);
498 fprintf(stderr, "\t-h this message\n");
501 int main(int argc, char **argv)
504 int num_thread_funcs = sizeof(threadFuncs)/sizeof(NSPRThreadFunc);
505 int num_thread_scopes = sizeof(threadScopes)/sizeof(PRThreadScope);
510 PLOptState *opt = PL_CreateOptState(argc, argv, "dl:t:h");
512 while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) {
513 if (PL_OPT_BAD == os) continue;
514 switch (opt->option) {
515 case 'd': /* debug mode */
516 debug_mode = PR_TRUE;
518 case 'l': /* lead time */
519 lead_time_secs = atoi(opt->value);
521 case 't': /* tolerance */
522 tolerance_msecs = atoi(opt->value);
530 PL_DestroyOptState(opt);
533 fprintf(stderr, "lead time: %d secs\n", lead_time_secs);
534 fprintf(stderr, "tolerance: %d msecs\n", tolerance_msecs);
537 start_time = PR_IntervalNow();
539 gettimeofday(&start_time_tv, NULL);
543 start_time_tick = GetTickCount();
545 _ftime(&start_time_tb);
548 tolerance = PR_MillisecondsToInterval(tolerance_msecs);
551 num_thread_scopes * num_thread_funcs * sizeof(PRThread*));
552 if (threads == NULL) {
553 fprintf(stderr, "PR_Malloc failed\n");
557 /* start to time out 5 seconds after a rollover date */
558 secs = lead_time_secs + 5;
560 for (i = 0; i < num_thread_scopes; i++) {
561 for (j = 0; j < num_thread_funcs; j++) {
562 threads[idx] = PR_CreateThread(PR_USER_THREAD, threadFuncs[j],
563 (void*)PR_SecondsToInterval(secs), PR_PRIORITY_NORMAL,
564 threadScopes[i], PR_JOINABLE_THREAD, 0);
565 if (threads[idx] == NULL) {
566 fprintf(stderr, "PR_CreateThread failed\n");
573 for (idx = 0; idx < num_thread_scopes*num_thread_funcs; idx++) {
574 if (PR_JoinThread(threads[idx]) == PR_FAILURE) {
575 fprintf(stderr, "PR_JoinThread failed\n");