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 */
75
#include <sys/types.h>
76
#include <sys/timeb.h> /* for _ftime */
79
#define DEFAULT_LEAD_TIME_SECS 5
80
#define DEFAULT_TOLERANCE_MSECS 500
82
static PRBool debug_mode = PR_FALSE;
83
static PRInt32 lead_time_secs = DEFAULT_LEAD_TIME_SECS;
84
static PRInt32 tolerance_msecs = DEFAULT_TOLERANCE_MSECS;
85
static PRIntervalTime start_time;
86
static PRIntervalTime tolerance;
89
static struct timeval start_time_tv;
92
static struct _timeb start_time_tb;
95
static void SleepThread(void *arg)
97
PRIntervalTime timeout = (PRIntervalTime) arg;
98
PRIntervalTime elapsed;
99
#if defined(XP_UNIX) || defined(WIN32)
100
PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout);
101
PRInt32 elapsed_msecs;
104
struct timeval end_time_tv;
107
struct _timeb end_time_tb;
110
if (PR_Sleep(timeout) == PR_FAILURE) {
111
fprintf(stderr, "PR_Sleep failed\n");
114
elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
115
if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
116
fprintf(stderr, "timeout wrong\n");
120
gettimeofday(&end_time_tv, NULL);
121
elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec)
122
+ (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000;
125
_ftime(&end_time_tb);
126
elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time)
127
+ (end_time_tb.millitm - start_time_tb.millitm);
129
#if defined(XP_UNIX) || defined(WIN32)
130
if (elapsed_msecs + tolerance_msecs < timeout_msecs
131
|| elapsed_msecs > timeout_msecs + tolerance_msecs) {
132
fprintf(stderr, "timeout wrong\n");
137
fprintf(stderr, "Sleep thread (scope %d) done\n",
138
PR_GetThreadScope(PR_GetCurrentThread()));
142
static void AcceptThread(void *arg)
144
PRIntervalTime timeout = (PRIntervalTime) arg;
145
PRIntervalTime elapsed;
146
#if defined(XP_UNIX) || defined(WIN32)
147
PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout);
148
PRInt32 elapsed_msecs;
151
struct timeval end_time_tv;
154
struct _timeb end_time_tb;
158
PRFileDesc *accepted;
160
sock = PR_NewTCPSocket();
162
fprintf(stderr, "PR_NewTCPSocket failed\n");
165
memset(&addr, 0, sizeof(addr));
166
addr.inet.family = PR_AF_INET;
168
addr.inet.ip = PR_htonl(PR_INADDR_ANY);
169
if (PR_Bind(sock, &addr) == PR_FAILURE) {
170
fprintf(stderr, "PR_Bind failed\n");
173
if (PR_Listen(sock, 5) == PR_FAILURE) {
174
fprintf(stderr, "PR_Listen failed\n");
177
accepted = PR_Accept(sock, NULL, timeout);
178
if (accepted != NULL || PR_GetError() != PR_IO_TIMEOUT_ERROR) {
179
fprintf(stderr, "PR_Accept did not time out\n");
182
elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
183
if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
184
fprintf(stderr, "timeout wrong\n");
188
gettimeofday(&end_time_tv, NULL);
189
elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec)
190
+ (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000;
193
_ftime(&end_time_tb);
194
elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time)
195
+ (end_time_tb.millitm - start_time_tb.millitm);
197
#if defined(XP_UNIX) || defined(WIN32)
198
if (elapsed_msecs + tolerance_msecs < timeout_msecs
199
|| elapsed_msecs > timeout_msecs + tolerance_msecs) {
200
fprintf(stderr, "timeout wrong\n");
204
if (PR_Close(sock) == PR_FAILURE) {
205
fprintf(stderr, "PR_Close failed\n");
209
fprintf(stderr, "Accept thread (scope %d) done\n",
210
PR_GetThreadScope(PR_GetCurrentThread()));
214
static void PollThread(void *arg)
216
PRIntervalTime timeout = (PRIntervalTime) arg;
217
PRIntervalTime elapsed;
218
#if defined(XP_UNIX) || defined(WIN32)
219
PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout);
220
PRInt32 elapsed_msecs;
223
struct timeval end_time_tv;
226
struct _timeb end_time_tb;
233
sock = PR_NewTCPSocket();
235
fprintf(stderr, "PR_NewTCPSocket failed\n");
238
memset(&addr, 0, sizeof(addr));
239
addr.inet.family = PR_AF_INET;
241
addr.inet.ip = PR_htonl(PR_INADDR_ANY);
242
if (PR_Bind(sock, &addr) == PR_FAILURE) {
243
fprintf(stderr, "PR_Bind failed\n");
246
if (PR_Listen(sock, 5) == PR_FAILURE) {
247
fprintf(stderr, "PR_Listen failed\n");
251
pd.in_flags = PR_POLL_READ;
252
rv = PR_Poll(&pd, 1, timeout);
254
fprintf(stderr, "PR_Poll did not time out\n");
257
elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
258
if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
259
fprintf(stderr, "timeout wrong\n");
263
gettimeofday(&end_time_tv, NULL);
264
elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec)
265
+ (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000;
268
_ftime(&end_time_tb);
269
elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time)
270
+ (end_time_tb.millitm - start_time_tb.millitm);
272
#if defined(XP_UNIX) || defined(WIN32)
273
if (elapsed_msecs + tolerance_msecs < timeout_msecs
274
|| elapsed_msecs > timeout_msecs + tolerance_msecs) {
275
fprintf(stderr, "timeout wrong\n");
279
if (PR_Close(sock) == PR_FAILURE) {
280
fprintf(stderr, "PR_Close failed\n");
284
fprintf(stderr, "Poll thread (scope %d) done\n",
285
PR_GetThreadScope(PR_GetCurrentThread()));
289
static void WaitCondVarThread(void *arg)
291
PRIntervalTime timeout = (PRIntervalTime) arg;
292
PRIntervalTime elapsed;
293
#if defined(XP_UNIX) || defined(WIN32)
294
PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout);
295
PRInt32 elapsed_msecs;
298
struct timeval end_time_tv;
301
struct _timeb end_time_tb;
308
fprintf(stderr, "PR_NewLock failed\n");
311
cv = PR_NewCondVar(ml);
313
fprintf(stderr, "PR_NewCondVar failed\n");
317
PR_WaitCondVar(cv, timeout);
319
elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
320
if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
321
fprintf(stderr, "timeout wrong\n");
325
gettimeofday(&end_time_tv, NULL);
326
elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec)
327
+ (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000;
330
_ftime(&end_time_tb);
331
elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time)
332
+ (end_time_tb.millitm - start_time_tb.millitm);
334
#if defined(XP_UNIX) || defined(WIN32)
335
if (elapsed_msecs + tolerance_msecs < timeout_msecs
336
|| elapsed_msecs > timeout_msecs + tolerance_msecs) {
337
fprintf(stderr, "timeout wrong\n");
341
PR_DestroyCondVar(cv);
344
fprintf(stderr, "wait cond var thread (scope %d) done\n",
345
PR_GetThreadScope(PR_GetCurrentThread()));
349
static void WaitMonitorThread(void *arg)
351
PRIntervalTime timeout = (PRIntervalTime) arg;
352
PRIntervalTime elapsed;
353
#if defined(XP_UNIX) || defined(WIN32)
354
PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout);
355
PRInt32 elapsed_msecs;
358
struct timeval end_time_tv;
361
struct _timeb end_time_tb;
365
mon = PR_NewMonitor();
367
fprintf(stderr, "PR_NewMonitor failed\n");
370
PR_EnterMonitor(mon);
371
PR_Wait(mon, timeout);
373
elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
374
if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
375
fprintf(stderr, "timeout wrong\n");
379
gettimeofday(&end_time_tv, NULL);
380
elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec)
381
+ (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000;
384
_ftime(&end_time_tb);
385
elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time)
386
+ (end_time_tb.millitm - start_time_tb.millitm);
388
#if defined(XP_UNIX) || defined(WIN32)
389
if (elapsed_msecs + tolerance_msecs < timeout_msecs
390
|| elapsed_msecs > timeout_msecs + tolerance_msecs) {
391
fprintf(stderr, "timeout wrong\n");
395
PR_DestroyMonitor(mon);
397
fprintf(stderr, "wait monitor thread (scope %d) done\n",
398
PR_GetThreadScope(PR_GetCurrentThread()));
402
static void WaitCMonitorThread(void *arg)
404
PRIntervalTime timeout = (PRIntervalTime) arg;
405
PRIntervalTime elapsed;
406
#if defined(XP_UNIX) || defined(WIN32)
407
PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout);
408
PRInt32 elapsed_msecs;
411
struct timeval end_time_tv;
414
struct _timeb end_time_tb;
418
PR_CEnterMonitor(&dummy);
419
PR_CWait(&dummy, timeout);
420
PR_CExitMonitor(&dummy);
421
elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
422
if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
423
fprintf(stderr, "timeout wrong\n");
427
gettimeofday(&end_time_tv, NULL);
428
elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec)
429
+ (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000;
432
_ftime(&end_time_tb);
433
elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time)
434
+ (end_time_tb.millitm - start_time_tb.millitm);
436
#if defined(XP_UNIX) || defined(WIN32)
437
if (elapsed_msecs + tolerance_msecs < timeout_msecs
438
|| elapsed_msecs > timeout_msecs + tolerance_msecs) {
439
fprintf(stderr, "timeout wrong\n");
444
fprintf(stderr, "wait cached monitor thread (scope %d) done\n",
445
PR_GetThreadScope(PR_GetCurrentThread()));
449
typedef void (*NSPRThreadFunc)(void*);
451
static NSPRThreadFunc threadFuncs[] = {
452
SleepThread, AcceptThread, PollThread,
453
WaitCondVarThread, WaitMonitorThread, WaitCMonitorThread};
455
static PRThreadScope threadScopes[] = {
456
PR_LOCAL_THREAD, PR_GLOBAL_THREAD, PR_GLOBAL_BOUND_THREAD};
458
static void Help(void)
460
fprintf(stderr, "y2ktmo test program usage:\n");
461
fprintf(stderr, "\t-d debug mode (FALSE)\n");
462
fprintf(stderr, "\t-l <secs> lead time (%d)\n",
463
DEFAULT_LEAD_TIME_SECS);
464
fprintf(stderr, "\t-t <msecs> tolerance (%d)\n",
465
DEFAULT_TOLERANCE_MSECS);
466
fprintf(stderr, "\t-h this message\n");
469
int main(int argc, char **argv)
472
int num_thread_funcs = sizeof(threadFuncs)/sizeof(NSPRThreadFunc);
473
int num_thread_scopes = sizeof(threadScopes)/sizeof(PRThreadScope);
478
PLOptState *opt = PL_CreateOptState(argc, argv, "dl:t:h");
480
while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) {
481
if (PL_OPT_BAD == os) continue;
482
switch (opt->option) {
483
case 'd': /* debug mode */
484
debug_mode = PR_TRUE;
486
case 'l': /* lead time */
487
lead_time_secs = atoi(opt->value);
489
case 't': /* tolerance */
490
tolerance_msecs = atoi(opt->value);
498
PL_DestroyOptState(opt);
501
fprintf(stderr, "lead time: %d secs\n", lead_time_secs);
502
fprintf(stderr, "tolerance: %d msecs\n", tolerance_msecs);
505
start_time = PR_IntervalNow();
507
gettimeofday(&start_time_tv, NULL);
510
_ftime(&start_time_tb);
512
tolerance = PR_MillisecondsToInterval(tolerance_msecs);
515
num_thread_scopes * num_thread_funcs * sizeof(PRThread*));
516
if (threads == NULL) {
517
fprintf(stderr, "PR_Malloc failed\n");
521
/* start to time out 5 seconds after a rollover date */
522
secs = lead_time_secs + 5;
524
for (i = 0; i < num_thread_scopes; i++) {
525
for (j = 0; j < num_thread_funcs; j++) {
526
threads[idx] = PR_CreateThread(PR_USER_THREAD, threadFuncs[j],
527
(void*)PR_SecondsToInterval(secs), PR_PRIORITY_NORMAL,
528
threadScopes[i], PR_JOINABLE_THREAD, 0);
529
if (threads[idx] == NULL) {
530
fprintf(stderr, "PR_CreateThread failed\n");
537
for (idx = 0; idx < num_thread_scopes*num_thread_funcs; idx++) {
538
if (PR_JoinThread(threads[idx]) == PR_FAILURE) {
539
fprintf(stderr, "PR_JoinThread failed\n");