y2ktmo.c (16221B)
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/. */ 5 6 /* 7 * Test: y2ktmo 8 * 9 * Description: 10 * This test tests the interval time facilities in NSPR for Y2K 11 * compliance. All the functions that take a timeout argument 12 * are tested: PR_Sleep, socket I/O (PR_Accept is taken as a 13 * representative), PR_Poll, PR_WaitCondVar, PR_Wait, and 14 * PR_CWait. A thread of each thread scope (local, global, and 15 * global bound) is created to call each of these functions. 16 * The test should be started at the specified number of seconds 17 * (called the lead time) before a Y2K rollover test date. The 18 * timeout values for these threads will span over the rollover 19 * date by at least the specified number of seconds. For 20 * example, if the lead time is 5 seconds, the test should 21 * be started at time (D - 5), where D is a rollover date, and 22 * the threads will time out at or after time (D + 5). The 23 * timeout values for the threads are spaced one second apart. 24 * 25 * When a thread times out, it calls PR_IntervalNow() to verify 26 * that it did wait for the specified time. In addition, it 27 * calls a platform-native function to verify the actual elapsed 28 * time again, to rule out the possibility that PR_IntervalNow() 29 * is broken. We allow the actual elapsed time to deviate from 30 * the specified timeout by a certain tolerance (in milliseconds). 31 */ 32 33 #include "nspr.h" 34 #include "plgetopt.h" 35 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #if defined(XP_UNIX) 40 # include <sys/time.h> /* for gettimeofday */ 41 #endif 42 #if defined(WIN32) 43 # if defined(WINCE) 44 # include <windows.h> 45 # else 46 # include <sys/types.h> 47 # include <sys/timeb.h> /* for _ftime */ 48 # endif 49 #endif 50 51 #define DEFAULT_LEAD_TIME_SECS 5 52 #define DEFAULT_TOLERANCE_MSECS 500 53 54 static PRBool debug_mode = PR_FALSE; 55 static PRInt32 lead_time_secs = DEFAULT_LEAD_TIME_SECS; 56 static PRInt32 tolerance_msecs = DEFAULT_TOLERANCE_MSECS; 57 static PRIntervalTime start_time; 58 static PRIntervalTime tolerance; 59 60 #if defined(XP_UNIX) 61 static struct timeval start_time_tv; 62 #endif 63 #if defined(WIN32) 64 # if defined(WINCE) 65 static DWORD start_time_tick; 66 # else 67 static struct _timeb start_time_tb; 68 # endif 69 #endif 70 71 static void SleepThread(void* arg) { 72 PRIntervalTime timeout = (PRIntervalTime)arg; 73 PRIntervalTime elapsed; 74 #if defined(XP_UNIX) || defined(WIN32) 75 PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout); 76 PRInt32 elapsed_msecs; 77 #endif 78 #if defined(XP_UNIX) 79 struct timeval end_time_tv; 80 #endif 81 #if defined(WIN32) && !defined(WINCE) 82 struct _timeb end_time_tb; 83 #endif 84 85 if (PR_Sleep(timeout) == PR_FAILURE) { 86 fprintf(stderr, "PR_Sleep failed\n"); 87 exit(1); 88 } 89 elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time); 90 if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) { 91 fprintf(stderr, "timeout wrong\n"); 92 exit(1); 93 } 94 #if defined(XP_UNIX) 95 gettimeofday(&end_time_tv, NULL); 96 elapsed_msecs = 1000 * (end_time_tv.tv_sec - start_time_tv.tv_sec) + 97 (end_time_tv.tv_usec - start_time_tv.tv_usec) / 1000; 98 #endif 99 #if defined(WIN32) 100 # if defined(WINCE) 101 elapsed_msecs = GetTickCount() - start_time_tick; 102 # else 103 _ftime(&end_time_tb); 104 elapsed_msecs = 1000 * (end_time_tb.time - start_time_tb.time) + 105 (end_time_tb.millitm - start_time_tb.millitm); 106 # endif 107 #endif 108 #if defined(XP_UNIX) || defined(WIN32) 109 if (elapsed_msecs + tolerance_msecs < timeout_msecs || 110 elapsed_msecs > timeout_msecs + tolerance_msecs) { 111 fprintf(stderr, "timeout wrong\n"); 112 exit(1); 113 } 114 #endif 115 if (debug_mode) { 116 fprintf(stderr, "Sleep thread (scope %d) done\n", 117 PR_GetThreadScope(PR_GetCurrentThread())); 118 } 119 } 120 121 static void AcceptThread(void* arg) { 122 PRIntervalTime timeout = (PRIntervalTime)arg; 123 PRIntervalTime elapsed; 124 #if defined(XP_UNIX) || defined(WIN32) 125 PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout); 126 PRInt32 elapsed_msecs; 127 #endif 128 #if defined(XP_UNIX) 129 struct timeval end_time_tv; 130 #endif 131 #if defined(WIN32) && !defined(WINCE) 132 struct _timeb end_time_tb; 133 #endif 134 PRFileDesc* sock; 135 PRNetAddr addr; 136 PRFileDesc* accepted; 137 138 sock = PR_NewTCPSocket(); 139 if (sock == NULL) { 140 fprintf(stderr, "PR_NewTCPSocket failed\n"); 141 exit(1); 142 } 143 memset(&addr, 0, sizeof(addr)); 144 addr.inet.family = PR_AF_INET; 145 addr.inet.port = 0; 146 addr.inet.ip = PR_htonl(PR_INADDR_ANY); 147 if (PR_Bind(sock, &addr) == PR_FAILURE) { 148 fprintf(stderr, "PR_Bind failed\n"); 149 exit(1); 150 } 151 if (PR_Listen(sock, 5) == PR_FAILURE) { 152 fprintf(stderr, "PR_Listen failed\n"); 153 exit(1); 154 } 155 accepted = PR_Accept(sock, NULL, timeout); 156 if (accepted != NULL || PR_GetError() != PR_IO_TIMEOUT_ERROR) { 157 fprintf(stderr, "PR_Accept did not time out\n"); 158 exit(1); 159 } 160 elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time); 161 if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) { 162 fprintf(stderr, "timeout wrong\n"); 163 exit(1); 164 } 165 #if defined(XP_UNIX) 166 gettimeofday(&end_time_tv, NULL); 167 elapsed_msecs = 1000 * (end_time_tv.tv_sec - start_time_tv.tv_sec) + 168 (end_time_tv.tv_usec - start_time_tv.tv_usec) / 1000; 169 #endif 170 #if defined(WIN32) 171 # if defined(WINCE) 172 elapsed_msecs = GetTickCount() - start_time_tick; 173 # else 174 _ftime(&end_time_tb); 175 elapsed_msecs = 1000 * (end_time_tb.time - start_time_tb.time) + 176 (end_time_tb.millitm - start_time_tb.millitm); 177 # endif 178 #endif 179 #if defined(XP_UNIX) || defined(WIN32) 180 if (elapsed_msecs + tolerance_msecs < timeout_msecs || 181 elapsed_msecs > timeout_msecs + tolerance_msecs) { 182 fprintf(stderr, "timeout wrong\n"); 183 exit(1); 184 } 185 #endif 186 if (PR_Close(sock) == PR_FAILURE) { 187 fprintf(stderr, "PR_Close failed\n"); 188 exit(1); 189 } 190 if (debug_mode) { 191 fprintf(stderr, "Accept thread (scope %d) done\n", 192 PR_GetThreadScope(PR_GetCurrentThread())); 193 } 194 } 195 196 static void PollThread(void* arg) { 197 PRIntervalTime timeout = (PRIntervalTime)arg; 198 PRIntervalTime elapsed; 199 #if defined(XP_UNIX) || defined(WIN32) 200 PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout); 201 PRInt32 elapsed_msecs; 202 #endif 203 #if defined(XP_UNIX) 204 struct timeval end_time_tv; 205 #endif 206 #if defined(WIN32) && !defined(WINCE) 207 struct _timeb end_time_tb; 208 #endif 209 PRFileDesc* sock; 210 PRNetAddr addr; 211 PRPollDesc pd; 212 PRIntn rv; 213 214 sock = PR_NewTCPSocket(); 215 if (sock == NULL) { 216 fprintf(stderr, "PR_NewTCPSocket failed\n"); 217 exit(1); 218 } 219 memset(&addr, 0, sizeof(addr)); 220 addr.inet.family = PR_AF_INET; 221 addr.inet.port = 0; 222 addr.inet.ip = PR_htonl(PR_INADDR_ANY); 223 if (PR_Bind(sock, &addr) == PR_FAILURE) { 224 fprintf(stderr, "PR_Bind failed\n"); 225 exit(1); 226 } 227 if (PR_Listen(sock, 5) == PR_FAILURE) { 228 fprintf(stderr, "PR_Listen failed\n"); 229 exit(1); 230 } 231 pd.fd = sock; 232 pd.in_flags = PR_POLL_READ; 233 rv = PR_Poll(&pd, 1, timeout); 234 if (rv != 0) { 235 fprintf(stderr, "PR_Poll did not time out\n"); 236 exit(1); 237 } 238 elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time); 239 if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) { 240 fprintf(stderr, "timeout wrong\n"); 241 exit(1); 242 } 243 #if defined(XP_UNIX) 244 gettimeofday(&end_time_tv, NULL); 245 elapsed_msecs = 1000 * (end_time_tv.tv_sec - start_time_tv.tv_sec) + 246 (end_time_tv.tv_usec - start_time_tv.tv_usec) / 1000; 247 #endif 248 #if defined(WIN32) 249 # if defined(WINCE) 250 elapsed_msecs = GetTickCount() - start_time_tick; 251 # else 252 _ftime(&end_time_tb); 253 elapsed_msecs = 1000 * (end_time_tb.time - start_time_tb.time) + 254 (end_time_tb.millitm - start_time_tb.millitm); 255 # endif 256 #endif 257 #if defined(XP_UNIX) || defined(WIN32) 258 if (elapsed_msecs + tolerance_msecs < timeout_msecs || 259 elapsed_msecs > timeout_msecs + tolerance_msecs) { 260 fprintf(stderr, "timeout wrong\n"); 261 exit(1); 262 } 263 #endif 264 if (PR_Close(sock) == PR_FAILURE) { 265 fprintf(stderr, "PR_Close failed\n"); 266 exit(1); 267 } 268 if (debug_mode) { 269 fprintf(stderr, "Poll thread (scope %d) done\n", 270 PR_GetThreadScope(PR_GetCurrentThread())); 271 } 272 } 273 274 static void WaitCondVarThread(void* arg) { 275 PRIntervalTime timeout = (PRIntervalTime)arg; 276 PRIntervalTime elapsed; 277 #if defined(XP_UNIX) || defined(WIN32) 278 PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout); 279 PRInt32 elapsed_msecs; 280 #endif 281 #if defined(XP_UNIX) 282 struct timeval end_time_tv; 283 #endif 284 #if defined(WIN32) && !defined(WINCE) 285 struct _timeb end_time_tb; 286 #endif 287 PRLock* ml; 288 PRCondVar* cv; 289 290 ml = PR_NewLock(); 291 if (ml == NULL) { 292 fprintf(stderr, "PR_NewLock failed\n"); 293 exit(1); 294 } 295 cv = PR_NewCondVar(ml); 296 if (cv == NULL) { 297 fprintf(stderr, "PR_NewCondVar failed\n"); 298 exit(1); 299 } 300 PR_Lock(ml); 301 PR_WaitCondVar(cv, timeout); 302 PR_Unlock(ml); 303 elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time); 304 if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) { 305 fprintf(stderr, "timeout wrong\n"); 306 exit(1); 307 } 308 #if defined(XP_UNIX) 309 gettimeofday(&end_time_tv, NULL); 310 elapsed_msecs = 1000 * (end_time_tv.tv_sec - start_time_tv.tv_sec) + 311 (end_time_tv.tv_usec - start_time_tv.tv_usec) / 1000; 312 #endif 313 #if defined(WIN32) 314 # if defined(WINCE) 315 elapsed_msecs = GetTickCount() - start_time_tick; 316 # else 317 _ftime(&end_time_tb); 318 elapsed_msecs = 1000 * (end_time_tb.time - start_time_tb.time) + 319 (end_time_tb.millitm - start_time_tb.millitm); 320 # endif 321 #endif 322 #if defined(XP_UNIX) || defined(WIN32) 323 if (elapsed_msecs + tolerance_msecs < timeout_msecs || 324 elapsed_msecs > timeout_msecs + tolerance_msecs) { 325 fprintf(stderr, "timeout wrong\n"); 326 exit(1); 327 } 328 #endif 329 PR_DestroyCondVar(cv); 330 PR_DestroyLock(ml); 331 if (debug_mode) { 332 fprintf(stderr, "wait cond var thread (scope %d) done\n", 333 PR_GetThreadScope(PR_GetCurrentThread())); 334 } 335 } 336 337 static void WaitMonitorThread(void* arg) { 338 PRIntervalTime timeout = (PRIntervalTime)arg; 339 PRIntervalTime elapsed; 340 #if defined(XP_UNIX) || defined(WIN32) 341 PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout); 342 PRInt32 elapsed_msecs; 343 #endif 344 #if defined(XP_UNIX) 345 struct timeval end_time_tv; 346 #endif 347 #if defined(WIN32) && !defined(WINCE) 348 struct _timeb end_time_tb; 349 #endif 350 PRMonitor* mon; 351 352 mon = PR_NewMonitor(); 353 if (mon == NULL) { 354 fprintf(stderr, "PR_NewMonitor failed\n"); 355 exit(1); 356 } 357 PR_EnterMonitor(mon); 358 PR_Wait(mon, timeout); 359 PR_ExitMonitor(mon); 360 elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time); 361 if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) { 362 fprintf(stderr, "timeout wrong\n"); 363 exit(1); 364 } 365 #if defined(XP_UNIX) 366 gettimeofday(&end_time_tv, NULL); 367 elapsed_msecs = 1000 * (end_time_tv.tv_sec - start_time_tv.tv_sec) + 368 (end_time_tv.tv_usec - start_time_tv.tv_usec) / 1000; 369 #endif 370 #if defined(WIN32) 371 # if defined(WINCE) 372 elapsed_msecs = GetTickCount() - start_time_tick; 373 # else 374 _ftime(&end_time_tb); 375 elapsed_msecs = 1000 * (end_time_tb.time - start_time_tb.time) + 376 (end_time_tb.millitm - start_time_tb.millitm); 377 # endif 378 #endif 379 #if defined(XP_UNIX) || defined(WIN32) 380 if (elapsed_msecs + tolerance_msecs < timeout_msecs || 381 elapsed_msecs > timeout_msecs + tolerance_msecs) { 382 fprintf(stderr, "timeout wrong\n"); 383 exit(1); 384 } 385 #endif 386 PR_DestroyMonitor(mon); 387 if (debug_mode) { 388 fprintf(stderr, "wait monitor thread (scope %d) done\n", 389 PR_GetThreadScope(PR_GetCurrentThread())); 390 } 391 } 392 393 static void WaitCMonitorThread(void* arg) { 394 PRIntervalTime timeout = (PRIntervalTime)arg; 395 PRIntervalTime elapsed; 396 #if defined(XP_UNIX) || defined(WIN32) 397 PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout); 398 PRInt32 elapsed_msecs; 399 #endif 400 #if defined(XP_UNIX) 401 struct timeval end_time_tv; 402 #endif 403 #if defined(WIN32) && !defined(WINCE) 404 struct _timeb end_time_tb; 405 #endif 406 int dummy; 407 408 PR_CEnterMonitor(&dummy); 409 PR_CWait(&dummy, timeout); 410 PR_CExitMonitor(&dummy); 411 elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time); 412 if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) { 413 fprintf(stderr, "timeout wrong\n"); 414 exit(1); 415 } 416 #if defined(XP_UNIX) 417 gettimeofday(&end_time_tv, NULL); 418 elapsed_msecs = 1000 * (end_time_tv.tv_sec - start_time_tv.tv_sec) + 419 (end_time_tv.tv_usec - start_time_tv.tv_usec) / 1000; 420 #endif 421 #if defined(WIN32) 422 # if defined(WINCE) 423 elapsed_msecs = GetTickCount() - start_time_tick; 424 # else 425 _ftime(&end_time_tb); 426 elapsed_msecs = 1000 * (end_time_tb.time - start_time_tb.time) + 427 (end_time_tb.millitm - start_time_tb.millitm); 428 # endif 429 #endif 430 #if defined(XP_UNIX) || defined(WIN32) 431 if (elapsed_msecs + tolerance_msecs < timeout_msecs || 432 elapsed_msecs > timeout_msecs + tolerance_msecs) { 433 fprintf(stderr, "timeout wrong\n"); 434 exit(1); 435 } 436 #endif 437 if (debug_mode) { 438 fprintf(stderr, "wait cached monitor thread (scope %d) done\n", 439 PR_GetThreadScope(PR_GetCurrentThread())); 440 } 441 } 442 443 typedef void (*NSPRThreadFunc)(void*); 444 445 static NSPRThreadFunc threadFuncs[] = {SleepThread, AcceptThread, 446 PollThread, WaitCondVarThread, 447 WaitMonitorThread, WaitCMonitorThread}; 448 449 static PRThreadScope threadScopes[] = {PR_LOCAL_THREAD, PR_GLOBAL_THREAD, 450 PR_GLOBAL_BOUND_THREAD}; 451 452 static void Help(void) { 453 fprintf(stderr, "y2ktmo test program usage:\n"); 454 fprintf(stderr, "\t-d debug mode (FALSE)\n"); 455 fprintf(stderr, "\t-l <secs> lead time (%d)\n", 456 DEFAULT_LEAD_TIME_SECS); 457 fprintf(stderr, "\t-t <msecs> tolerance (%d)\n", 458 DEFAULT_TOLERANCE_MSECS); 459 fprintf(stderr, "\t-h this message\n"); 460 } /* Help */ 461 462 int main(int argc, char** argv) { 463 PRThread** threads; 464 int num_thread_funcs = sizeof(threadFuncs) / sizeof(NSPRThreadFunc); 465 int num_thread_scopes = sizeof(threadScopes) / sizeof(PRThreadScope); 466 int i, j; 467 int idx; 468 PRInt32 secs; 469 PLOptStatus os; 470 PLOptState* opt = PL_CreateOptState(argc, argv, "dl:t:h"); 471 472 while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { 473 if (PL_OPT_BAD == os) { 474 continue; 475 } 476 switch (opt->option) { 477 case 'd': /* debug mode */ 478 debug_mode = PR_TRUE; 479 break; 480 case 'l': /* lead time */ 481 lead_time_secs = atoi(opt->value); 482 break; 483 case 't': /* tolerance */ 484 tolerance_msecs = atoi(opt->value); 485 break; 486 case 'h': 487 default: 488 Help(); 489 return 2; 490 } 491 } 492 PL_DestroyOptState(opt); 493 494 if (debug_mode) { 495 fprintf(stderr, "lead time: %d secs\n", lead_time_secs); 496 fprintf(stderr, "tolerance: %d msecs\n", tolerance_msecs); 497 } 498 499 start_time = PR_IntervalNow(); 500 #if defined(XP_UNIX) 501 gettimeofday(&start_time_tv, NULL); 502 #endif 503 #if defined(WIN32) 504 # ifdef WINCE 505 start_time_tick = GetTickCount(); 506 # else 507 _ftime(&start_time_tb); 508 # endif 509 #endif 510 tolerance = PR_MillisecondsToInterval(tolerance_msecs); 511 512 threads = PR_Malloc(num_thread_scopes * num_thread_funcs * sizeof(PRThread*)); 513 if (threads == NULL) { 514 fprintf(stderr, "PR_Malloc failed\n"); 515 exit(1); 516 } 517 518 /* start to time out 5 seconds after a rollover date */ 519 secs = lead_time_secs + 5; 520 idx = 0; 521 for (i = 0; i < num_thread_scopes; i++) { 522 for (j = 0; j < num_thread_funcs; j++) { 523 threads[idx] = PR_CreateThread( 524 PR_USER_THREAD, threadFuncs[j], (void*)PR_SecondsToInterval(secs), 525 PR_PRIORITY_NORMAL, threadScopes[i], PR_JOINABLE_THREAD, 0); 526 if (threads[idx] == NULL) { 527 fprintf(stderr, "PR_CreateThread failed\n"); 528 exit(1); 529 } 530 secs++; 531 idx++; 532 } 533 } 534 for (idx = 0; idx < num_thread_scopes * num_thread_funcs; idx++) { 535 if (PR_JoinThread(threads[idx]) == PR_FAILURE) { 536 fprintf(stderr, "PR_JoinThread failed\n"); 537 exit(1); 538 } 539 } 540 PR_Free(threads); 541 printf("PASS\n"); 542 return 0; 543 }