y2ktmo.c 17 KB

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