Upload Tizen:Base source
[toolchains/nspr.git] / mozilla / nsprpub / pr / tests / y2ktmo.c
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
4  *
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/
9  *
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
13  * License.
14  *
15  * The Original Code is the Netscape Portable Runtime (NSPR).
16  *
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.
21  *
22  * Contributor(s):
23  *
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.
35  *
36  * ***** END LICENSE BLOCK ***** */
37
38 /*
39  * Test: y2ktmo
40  *
41  * Description:
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.
56  *
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).
63  */ 
64
65 #include "nspr.h"
66 #include "plgetopt.h"
67
68 #include <stdio.h>
69 #include <stdlib.h>
70 #include <string.h>
71 #if defined(XP_UNIX)
72 #include <sys/time.h> /* for gettimeofday */
73 #endif
74 #if defined(WIN32)
75 #if defined(WINCE)
76 #include <windows.h>
77 #else
78 #include <sys/types.h>
79 #include <sys/timeb.h>  /* for _ftime */
80 #endif
81 #endif
82
83 #define DEFAULT_LEAD_TIME_SECS 5
84 #define DEFAULT_TOLERANCE_MSECS 500
85
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;
91
92 #if defined(XP_UNIX)
93 static struct timeval start_time_tv;
94 #endif
95 #if defined(WIN32)
96 #if defined(WINCE)
97 static DWORD start_time_tick;
98 #else
99 static struct _timeb start_time_tb;
100 #endif
101 #endif
102
103 static void SleepThread(void *arg)
104 {
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;
110 #endif
111 #if defined(XP_UNIX)
112     struct timeval end_time_tv;
113 #endif
114 #if defined(WIN32) && !defined(WINCE)
115     struct _timeb end_time_tb;
116 #endif
117
118     if (PR_Sleep(timeout) == PR_FAILURE) {
119         fprintf(stderr, "PR_Sleep failed\n");
120         exit(1);
121     }
122     elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
123     if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
124         fprintf(stderr, "timeout wrong\n");
125         exit(1);
126     }
127 #if defined(XP_UNIX)
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;
131 #endif
132 #if defined(WIN32)
133 #if defined(WINCE)
134     elapsed_msecs = GetTickCount() - start_time_tick;
135 #else
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);
139 #endif
140 #endif
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");
145         exit(1);
146     }
147 #endif
148     if (debug_mode) {
149         fprintf(stderr, "Sleep thread (scope %d) done\n",
150                 PR_GetThreadScope(PR_GetCurrentThread()));
151     }
152 }
153
154 static void AcceptThread(void *arg)
155 {
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;
161 #endif
162 #if defined(XP_UNIX)
163     struct timeval end_time_tv;
164 #endif
165 #if defined(WIN32) && !defined(WINCE)
166     struct _timeb end_time_tb;
167 #endif
168     PRFileDesc *sock;
169     PRNetAddr addr;
170     PRFileDesc *accepted;
171
172     sock = PR_NewTCPSocket();
173     if (sock == NULL) {
174         fprintf(stderr, "PR_NewTCPSocket failed\n");
175         exit(1);
176     }
177     memset(&addr, 0, sizeof(addr));
178     addr.inet.family = PR_AF_INET;
179     addr.inet.port = 0;
180     addr.inet.ip = PR_htonl(PR_INADDR_ANY);
181     if (PR_Bind(sock, &addr) == PR_FAILURE) {
182         fprintf(stderr, "PR_Bind failed\n");
183         exit(1);
184     }
185     if (PR_Listen(sock, 5) == PR_FAILURE) {
186         fprintf(stderr, "PR_Listen failed\n");
187         exit(1);
188     }
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");
192         exit(1);
193     }
194     elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
195     if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
196         fprintf(stderr, "timeout wrong\n");
197         exit(1);
198     }
199 #if defined(XP_UNIX)
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;
203 #endif
204 #if defined(WIN32)
205 #if defined(WINCE)
206     elapsed_msecs = GetTickCount() - start_time_tick;
207 #else
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);
211 #endif
212 #endif
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");
217         exit(1);
218     }
219 #endif
220     if (PR_Close(sock) == PR_FAILURE) {
221         fprintf(stderr, "PR_Close failed\n");
222         exit(1);
223     }
224     if (debug_mode) {
225         fprintf(stderr, "Accept thread (scope %d) done\n",
226                 PR_GetThreadScope(PR_GetCurrentThread()));
227     }
228 }
229
230 static void PollThread(void *arg)
231 {
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;
237 #endif
238 #if defined(XP_UNIX)
239     struct timeval end_time_tv;
240 #endif
241 #if defined(WIN32) && !defined(WINCE)
242     struct _timeb end_time_tb;
243 #endif
244     PRFileDesc *sock;
245     PRNetAddr addr;
246     PRPollDesc pd;
247     PRIntn rv;
248
249     sock = PR_NewTCPSocket();
250     if (sock == NULL) {
251         fprintf(stderr, "PR_NewTCPSocket failed\n");
252         exit(1);
253     }
254     memset(&addr, 0, sizeof(addr));
255     addr.inet.family = PR_AF_INET;
256     addr.inet.port = 0;
257     addr.inet.ip = PR_htonl(PR_INADDR_ANY);
258     if (PR_Bind(sock, &addr) == PR_FAILURE) {
259         fprintf(stderr, "PR_Bind failed\n");
260         exit(1);
261     }
262     if (PR_Listen(sock, 5) == PR_FAILURE) {
263         fprintf(stderr, "PR_Listen failed\n");
264         exit(1);
265     }
266     pd.fd = sock;
267     pd.in_flags = PR_POLL_READ;
268     rv = PR_Poll(&pd, 1, timeout);
269     if (rv != 0) {
270         fprintf(stderr, "PR_Poll did not time out\n");
271         exit(1);
272     }
273     elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
274     if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
275         fprintf(stderr, "timeout wrong\n");
276         exit(1);
277     }
278 #if defined(XP_UNIX)
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;
282 #endif
283 #if defined(WIN32)
284 #if defined(WINCE)
285     elapsed_msecs = GetTickCount() - start_time_tick;
286 #else
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);
290 #endif
291 #endif
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");
296         exit(1);
297     }
298 #endif
299     if (PR_Close(sock) == PR_FAILURE) {
300         fprintf(stderr, "PR_Close failed\n");
301         exit(1);
302     }
303     if (debug_mode) {
304         fprintf(stderr, "Poll thread (scope %d) done\n",
305                 PR_GetThreadScope(PR_GetCurrentThread()));
306     }
307 }
308
309 static void WaitCondVarThread(void *arg)
310 {
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;
316 #endif
317 #if defined(XP_UNIX)
318     struct timeval end_time_tv;
319 #endif
320 #if defined(WIN32) && !defined(WINCE)
321     struct _timeb end_time_tb;
322 #endif
323     PRLock *ml;
324     PRCondVar *cv;
325
326     ml = PR_NewLock();
327     if (ml == NULL) {
328         fprintf(stderr, "PR_NewLock failed\n");
329         exit(1);
330     }
331     cv = PR_NewCondVar(ml);
332     if (cv == NULL) {
333         fprintf(stderr, "PR_NewCondVar failed\n");
334         exit(1);
335     }
336     PR_Lock(ml);
337     PR_WaitCondVar(cv, timeout);
338     PR_Unlock(ml);
339     elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
340     if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
341         fprintf(stderr, "timeout wrong\n");
342         exit(1);
343     }
344 #if defined(XP_UNIX)
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;
348 #endif
349 #if defined(WIN32)
350 #if defined(WINCE)
351     elapsed_msecs = GetTickCount() - start_time_tick;
352 #else
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);
356 #endif
357 #endif
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");
362         exit(1);
363     }
364 #endif
365     PR_DestroyCondVar(cv);
366     PR_DestroyLock(ml);
367     if (debug_mode) {
368         fprintf(stderr, "wait cond var thread (scope %d) done\n",
369                 PR_GetThreadScope(PR_GetCurrentThread()));
370     }
371 }
372
373 static void WaitMonitorThread(void *arg)
374 {
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;
380 #endif
381 #if defined(XP_UNIX)
382     struct timeval end_time_tv;
383 #endif
384 #if defined(WIN32) && !defined(WINCE)
385     struct _timeb end_time_tb;
386 #endif
387     PRMonitor *mon;
388
389     mon = PR_NewMonitor();
390     if (mon == NULL) {
391         fprintf(stderr, "PR_NewMonitor failed\n");
392         exit(1);
393     }
394     PR_EnterMonitor(mon);
395     PR_Wait(mon, timeout);
396     PR_ExitMonitor(mon);
397     elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
398     if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
399         fprintf(stderr, "timeout wrong\n");
400         exit(1);
401     }
402 #if defined(XP_UNIX)
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;
406 #endif
407 #if defined(WIN32)
408 #if defined(WINCE)
409     elapsed_msecs = GetTickCount() - start_time_tick;
410 #else
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);
414 #endif
415 #endif
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");
420         exit(1);
421     }
422 #endif
423     PR_DestroyMonitor(mon);
424     if (debug_mode) {
425         fprintf(stderr, "wait monitor thread (scope %d) done\n",
426                 PR_GetThreadScope(PR_GetCurrentThread()));
427     }
428 }
429
430 static void WaitCMonitorThread(void *arg)
431 {
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;
437 #endif
438 #if defined(XP_UNIX)
439     struct timeval end_time_tv;
440 #endif
441 #if defined(WIN32) && !defined(WINCE)
442     struct _timeb end_time_tb;
443 #endif
444     int dummy;
445
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");
452         exit(1);
453     }
454 #if defined(XP_UNIX)
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;
458 #endif
459 #if defined(WIN32)
460 #if defined(WINCE)
461     elapsed_msecs = GetTickCount() - start_time_tick;
462 #else
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);
466 #endif
467 #endif
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");
472         exit(1);
473     }
474 #endif
475     if (debug_mode) {
476         fprintf(stderr, "wait cached monitor thread (scope %d) done\n",
477                 PR_GetThreadScope(PR_GetCurrentThread()));
478     }
479 }
480
481 typedef void (*NSPRThreadFunc)(void*);
482
483 static NSPRThreadFunc threadFuncs[] = {
484     SleepThread, AcceptThread, PollThread,
485     WaitCondVarThread, WaitMonitorThread, WaitCMonitorThread};
486
487 static PRThreadScope threadScopes[] = {
488     PR_LOCAL_THREAD, PR_GLOBAL_THREAD, PR_GLOBAL_BOUND_THREAD};
489
490 static void Help(void)
491 {
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");
499 }  /* Help */
500
501 int main(int argc, char **argv)
502 {
503     PRThread **threads;
504     int num_thread_funcs = sizeof(threadFuncs)/sizeof(NSPRThreadFunc);
505     int num_thread_scopes = sizeof(threadScopes)/sizeof(PRThreadScope);
506     int i, j;
507     int idx;
508     PRInt32 secs;
509     PLOptStatus os;
510     PLOptState *opt = PL_CreateOptState(argc, argv, "dl:t:h");
511
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;
517                 break;
518             case 'l':  /* lead time */
519                 lead_time_secs = atoi(opt->value);
520                 break;
521             case 't':  /* tolerance */
522                 tolerance_msecs = atoi(opt->value);
523                 break;
524             case 'h':
525             default:
526                 Help();
527                 return 2;
528         }
529     }
530     PL_DestroyOptState(opt);
531
532     if (debug_mode) {
533         fprintf(stderr, "lead time: %d secs\n", lead_time_secs);
534         fprintf(stderr, "tolerance: %d msecs\n", tolerance_msecs);
535     }
536
537     start_time = PR_IntervalNow();
538 #if defined(XP_UNIX)
539     gettimeofday(&start_time_tv, NULL);
540 #endif
541 #if defined(WIN32)
542 #ifdef WINCE
543     start_time_tick = GetTickCount();
544 #else
545     _ftime(&start_time_tb);
546 #endif
547 #endif
548     tolerance = PR_MillisecondsToInterval(tolerance_msecs);
549
550     threads = PR_Malloc(
551             num_thread_scopes * num_thread_funcs * sizeof(PRThread*));
552     if (threads == NULL) {
553         fprintf(stderr, "PR_Malloc failed\n");
554         exit(1);
555     }
556
557     /* start to time out 5 seconds after a rollover date */
558     secs = lead_time_secs + 5;
559     idx = 0;
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");
567                 exit(1);
568             }
569             secs++;
570             idx++;
571         }
572     }
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");
576             exit(1);
577         }
578     }
579     PR_Free(threads);
580     printf("PASS\n");
581     return 0;
582 }