nsprpub/pr/tests/y2ktmo.c

Fri, 16 Jan 2015 04:50:19 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 04:50:19 +0100
branch
TOR_BUG_9701
changeset 13
44a2da4a2ab2
permissions
-rw-r--r--

Replace accessor implementation with direct member state manipulation, by
request https://trac.torproject.org/projects/tor/ticket/9701#comment:32

     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/. */
     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  */ 
    33 #include "nspr.h"
    34 #include "plgetopt.h"
    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
    51 #define DEFAULT_LEAD_TIME_SECS 5
    52 #define DEFAULT_TOLERANCE_MSECS 500
    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;
    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
    71 static void SleepThread(void *arg)
    72 {
    73     PRIntervalTime timeout = (PRIntervalTime) arg;
    74     PRIntervalTime elapsed;
    75 #if defined(XP_UNIX) || defined(WIN32)
    76     PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout);
    77     PRInt32 elapsed_msecs;
    78 #endif
    79 #if defined(XP_UNIX)
    80     struct timeval end_time_tv;
    81 #endif
    82 #if defined(WIN32) && !defined(WINCE)
    83     struct _timeb end_time_tb;
    84 #endif
    86     if (PR_Sleep(timeout) == PR_FAILURE) {
    87         fprintf(stderr, "PR_Sleep failed\n");
    88         exit(1);
    89     }
    90     elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
    91     if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
    92         fprintf(stderr, "timeout wrong\n");
    93         exit(1);
    94     }
    95 #if defined(XP_UNIX)
    96     gettimeofday(&end_time_tv, NULL);
    97     elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec)
    98             + (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000;
    99 #endif
   100 #if defined(WIN32)
   101 #if defined(WINCE)
   102     elapsed_msecs = GetTickCount() - start_time_tick;
   103 #else
   104     _ftime(&end_time_tb);
   105     elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time)
   106             + (end_time_tb.millitm - start_time_tb.millitm);
   107 #endif
   108 #endif
   109 #if defined(XP_UNIX) || defined(WIN32)
   110     if (elapsed_msecs + tolerance_msecs < timeout_msecs
   111             || elapsed_msecs > timeout_msecs + tolerance_msecs) {
   112         fprintf(stderr, "timeout wrong\n");
   113         exit(1);
   114     }
   115 #endif
   116     if (debug_mode) {
   117         fprintf(stderr, "Sleep thread (scope %d) done\n",
   118                 PR_GetThreadScope(PR_GetCurrentThread()));
   119     }
   120 }
   122 static void AcceptThread(void *arg)
   123 {
   124     PRIntervalTime timeout = (PRIntervalTime) arg;
   125     PRIntervalTime elapsed;
   126 #if defined(XP_UNIX) || defined(WIN32)
   127     PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout);
   128     PRInt32 elapsed_msecs;
   129 #endif
   130 #if defined(XP_UNIX)
   131     struct timeval end_time_tv;
   132 #endif
   133 #if defined(WIN32) && !defined(WINCE)
   134     struct _timeb end_time_tb;
   135 #endif
   136     PRFileDesc *sock;
   137     PRNetAddr addr;
   138     PRFileDesc *accepted;
   140     sock = PR_NewTCPSocket();
   141     if (sock == NULL) {
   142         fprintf(stderr, "PR_NewTCPSocket failed\n");
   143         exit(1);
   144     }
   145     memset(&addr, 0, sizeof(addr));
   146     addr.inet.family = PR_AF_INET;
   147     addr.inet.port = 0;
   148     addr.inet.ip = PR_htonl(PR_INADDR_ANY);
   149     if (PR_Bind(sock, &addr) == PR_FAILURE) {
   150         fprintf(stderr, "PR_Bind failed\n");
   151         exit(1);
   152     }
   153     if (PR_Listen(sock, 5) == PR_FAILURE) {
   154         fprintf(stderr, "PR_Listen failed\n");
   155         exit(1);
   156     }
   157     accepted = PR_Accept(sock, NULL, timeout);
   158     if (accepted != NULL || PR_GetError() != PR_IO_TIMEOUT_ERROR) {
   159         fprintf(stderr, "PR_Accept did not time out\n");
   160         exit(1);
   161     }
   162     elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
   163     if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
   164         fprintf(stderr, "timeout wrong\n");
   165         exit(1);
   166     }
   167 #if defined(XP_UNIX)
   168     gettimeofday(&end_time_tv, NULL);
   169     elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec)
   170             + (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000;
   171 #endif
   172 #if defined(WIN32)
   173 #if defined(WINCE)
   174     elapsed_msecs = GetTickCount() - start_time_tick;
   175 #else
   176     _ftime(&end_time_tb);
   177     elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time)
   178             + (end_time_tb.millitm - start_time_tb.millitm);
   179 #endif
   180 #endif
   181 #if defined(XP_UNIX) || defined(WIN32)
   182     if (elapsed_msecs + tolerance_msecs < timeout_msecs
   183             || elapsed_msecs > timeout_msecs + tolerance_msecs) {
   184         fprintf(stderr, "timeout wrong\n");
   185         exit(1);
   186     }
   187 #endif
   188     if (PR_Close(sock) == PR_FAILURE) {
   189         fprintf(stderr, "PR_Close failed\n");
   190         exit(1);
   191     }
   192     if (debug_mode) {
   193         fprintf(stderr, "Accept thread (scope %d) done\n",
   194                 PR_GetThreadScope(PR_GetCurrentThread()));
   195     }
   196 }
   198 static void PollThread(void *arg)
   199 {
   200     PRIntervalTime timeout = (PRIntervalTime) arg;
   201     PRIntervalTime elapsed;
   202 #if defined(XP_UNIX) || defined(WIN32)
   203     PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout);
   204     PRInt32 elapsed_msecs;
   205 #endif
   206 #if defined(XP_UNIX)
   207     struct timeval end_time_tv;
   208 #endif
   209 #if defined(WIN32) && !defined(WINCE)
   210     struct _timeb end_time_tb;
   211 #endif
   212     PRFileDesc *sock;
   213     PRNetAddr addr;
   214     PRPollDesc pd;
   215     PRIntn rv;
   217     sock = PR_NewTCPSocket();
   218     if (sock == NULL) {
   219         fprintf(stderr, "PR_NewTCPSocket failed\n");
   220         exit(1);
   221     }
   222     memset(&addr, 0, sizeof(addr));
   223     addr.inet.family = PR_AF_INET;
   224     addr.inet.port = 0;
   225     addr.inet.ip = PR_htonl(PR_INADDR_ANY);
   226     if (PR_Bind(sock, &addr) == PR_FAILURE) {
   227         fprintf(stderr, "PR_Bind failed\n");
   228         exit(1);
   229     }
   230     if (PR_Listen(sock, 5) == PR_FAILURE) {
   231         fprintf(stderr, "PR_Listen failed\n");
   232         exit(1);
   233     }
   234     pd.fd = sock;
   235     pd.in_flags = PR_POLL_READ;
   236     rv = PR_Poll(&pd, 1, timeout);
   237     if (rv != 0) {
   238         fprintf(stderr, "PR_Poll did not time out\n");
   239         exit(1);
   240     }
   241     elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
   242     if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
   243         fprintf(stderr, "timeout wrong\n");
   244         exit(1);
   245     }
   246 #if defined(XP_UNIX)
   247     gettimeofday(&end_time_tv, NULL);
   248     elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec)
   249             + (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000;
   250 #endif
   251 #if defined(WIN32)
   252 #if defined(WINCE)
   253     elapsed_msecs = GetTickCount() - start_time_tick;
   254 #else
   255     _ftime(&end_time_tb);
   256     elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time)
   257             + (end_time_tb.millitm - start_time_tb.millitm);
   258 #endif
   259 #endif
   260 #if defined(XP_UNIX) || defined(WIN32)
   261     if (elapsed_msecs + tolerance_msecs < timeout_msecs
   262             || elapsed_msecs > timeout_msecs + tolerance_msecs) {
   263         fprintf(stderr, "timeout wrong\n");
   264         exit(1);
   265     }
   266 #endif
   267     if (PR_Close(sock) == PR_FAILURE) {
   268         fprintf(stderr, "PR_Close failed\n");
   269         exit(1);
   270     }
   271     if (debug_mode) {
   272         fprintf(stderr, "Poll thread (scope %d) done\n",
   273                 PR_GetThreadScope(PR_GetCurrentThread()));
   274     }
   275 }
   277 static void WaitCondVarThread(void *arg)
   278 {
   279     PRIntervalTime timeout = (PRIntervalTime) arg;
   280     PRIntervalTime elapsed;
   281 #if defined(XP_UNIX) || defined(WIN32)
   282     PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout);
   283     PRInt32 elapsed_msecs;
   284 #endif
   285 #if defined(XP_UNIX)
   286     struct timeval end_time_tv;
   287 #endif
   288 #if defined(WIN32) && !defined(WINCE)
   289     struct _timeb end_time_tb;
   290 #endif
   291     PRLock *ml;
   292     PRCondVar *cv;
   294     ml = PR_NewLock();
   295     if (ml == NULL) {
   296         fprintf(stderr, "PR_NewLock failed\n");
   297         exit(1);
   298     }
   299     cv = PR_NewCondVar(ml);
   300     if (cv == NULL) {
   301         fprintf(stderr, "PR_NewCondVar failed\n");
   302         exit(1);
   303     }
   304     PR_Lock(ml);
   305     PR_WaitCondVar(cv, timeout);
   306     PR_Unlock(ml);
   307     elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
   308     if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
   309         fprintf(stderr, "timeout wrong\n");
   310         exit(1);
   311     }
   312 #if defined(XP_UNIX)
   313     gettimeofday(&end_time_tv, NULL);
   314     elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec)
   315             + (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000;
   316 #endif
   317 #if defined(WIN32)
   318 #if defined(WINCE)
   319     elapsed_msecs = GetTickCount() - start_time_tick;
   320 #else
   321     _ftime(&end_time_tb);
   322     elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time)
   323             + (end_time_tb.millitm - start_time_tb.millitm);
   324 #endif
   325 #endif
   326 #if defined(XP_UNIX) || defined(WIN32)
   327     if (elapsed_msecs + tolerance_msecs < timeout_msecs
   328             || elapsed_msecs > timeout_msecs + tolerance_msecs) {
   329         fprintf(stderr, "timeout wrong\n");
   330         exit(1);
   331     }
   332 #endif
   333     PR_DestroyCondVar(cv);
   334     PR_DestroyLock(ml);
   335     if (debug_mode) {
   336         fprintf(stderr, "wait cond var thread (scope %d) done\n",
   337                 PR_GetThreadScope(PR_GetCurrentThread()));
   338     }
   339 }
   341 static void WaitMonitorThread(void *arg)
   342 {
   343     PRIntervalTime timeout = (PRIntervalTime) arg;
   344     PRIntervalTime elapsed;
   345 #if defined(XP_UNIX) || defined(WIN32)
   346     PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout);
   347     PRInt32 elapsed_msecs;
   348 #endif
   349 #if defined(XP_UNIX)
   350     struct timeval end_time_tv;
   351 #endif
   352 #if defined(WIN32) && !defined(WINCE)
   353     struct _timeb end_time_tb;
   354 #endif
   355     PRMonitor *mon;
   357     mon = PR_NewMonitor();
   358     if (mon == NULL) {
   359         fprintf(stderr, "PR_NewMonitor failed\n");
   360         exit(1);
   361     }
   362     PR_EnterMonitor(mon);
   363     PR_Wait(mon, timeout);
   364     PR_ExitMonitor(mon);
   365     elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
   366     if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
   367         fprintf(stderr, "timeout wrong\n");
   368         exit(1);
   369     }
   370 #if defined(XP_UNIX)
   371     gettimeofday(&end_time_tv, NULL);
   372     elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec)
   373             + (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000;
   374 #endif
   375 #if defined(WIN32)
   376 #if defined(WINCE)
   377     elapsed_msecs = GetTickCount() - start_time_tick;
   378 #else
   379     _ftime(&end_time_tb);
   380     elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time)
   381             + (end_time_tb.millitm - start_time_tb.millitm);
   382 #endif
   383 #endif
   384 #if defined(XP_UNIX) || defined(WIN32)
   385     if (elapsed_msecs + tolerance_msecs < timeout_msecs
   386             || elapsed_msecs > timeout_msecs + tolerance_msecs) {
   387         fprintf(stderr, "timeout wrong\n");
   388         exit(1);
   389     }
   390 #endif
   391     PR_DestroyMonitor(mon);
   392     if (debug_mode) {
   393         fprintf(stderr, "wait monitor thread (scope %d) done\n",
   394                 PR_GetThreadScope(PR_GetCurrentThread()));
   395     }
   396 }
   398 static void WaitCMonitorThread(void *arg)
   399 {
   400     PRIntervalTime timeout = (PRIntervalTime) arg;
   401     PRIntervalTime elapsed;
   402 #if defined(XP_UNIX) || defined(WIN32)
   403     PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout);
   404     PRInt32 elapsed_msecs;
   405 #endif
   406 #if defined(XP_UNIX)
   407     struct timeval end_time_tv;
   408 #endif
   409 #if defined(WIN32) && !defined(WINCE)
   410     struct _timeb end_time_tb;
   411 #endif
   412     int dummy;
   414     PR_CEnterMonitor(&dummy);
   415     PR_CWait(&dummy, timeout);
   416     PR_CExitMonitor(&dummy);
   417     elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
   418     if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
   419         fprintf(stderr, "timeout wrong\n");
   420         exit(1);
   421     }
   422 #if defined(XP_UNIX)
   423     gettimeofday(&end_time_tv, NULL);
   424     elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec)
   425             + (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000;
   426 #endif
   427 #if defined(WIN32)
   428 #if defined(WINCE)
   429     elapsed_msecs = GetTickCount() - start_time_tick;
   430 #else
   431     _ftime(&end_time_tb);
   432     elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time)
   433             + (end_time_tb.millitm - start_time_tb.millitm);
   434 #endif
   435 #endif
   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");
   440         exit(1);
   441     }
   442 #endif
   443     if (debug_mode) {
   444         fprintf(stderr, "wait cached monitor thread (scope %d) done\n",
   445                 PR_GetThreadScope(PR_GetCurrentThread()));
   446     }
   447 }
   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)
   459 {
   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");
   467 }  /* Help */
   469 int main(int argc, char **argv)
   470 {
   471     PRThread **threads;
   472     int num_thread_funcs = sizeof(threadFuncs)/sizeof(NSPRThreadFunc);
   473     int num_thread_scopes = sizeof(threadScopes)/sizeof(PRThreadScope);
   474     int i, j;
   475     int idx;
   476     PRInt32 secs;
   477     PLOptStatus os;
   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;
   485                 break;
   486             case 'l':  /* lead time */
   487                 lead_time_secs = atoi(opt->value);
   488                 break;
   489             case 't':  /* tolerance */
   490                 tolerance_msecs = atoi(opt->value);
   491                 break;
   492             case 'h':
   493             default:
   494                 Help();
   495                 return 2;
   496         }
   497     }
   498     PL_DestroyOptState(opt);
   500     if (debug_mode) {
   501         fprintf(stderr, "lead time: %d secs\n", lead_time_secs);
   502         fprintf(stderr, "tolerance: %d msecs\n", tolerance_msecs);
   503     }
   505     start_time = PR_IntervalNow();
   506 #if defined(XP_UNIX)
   507     gettimeofday(&start_time_tv, NULL);
   508 #endif
   509 #if defined(WIN32)
   510 #ifdef WINCE
   511     start_time_tick = GetTickCount();
   512 #else
   513     _ftime(&start_time_tb);
   514 #endif
   515 #endif
   516     tolerance = PR_MillisecondsToInterval(tolerance_msecs);
   518     threads = PR_Malloc(
   519             num_thread_scopes * num_thread_funcs * sizeof(PRThread*));
   520     if (threads == NULL) {
   521         fprintf(stderr, "PR_Malloc failed\n");
   522         exit(1);
   523     }
   525     /* start to time out 5 seconds after a rollover date */
   526     secs = lead_time_secs + 5;
   527     idx = 0;
   528     for (i = 0; i < num_thread_scopes; i++) { 
   529         for (j = 0; j < num_thread_funcs; j++) {
   530             threads[idx] = PR_CreateThread(PR_USER_THREAD, threadFuncs[j],
   531                 (void*)PR_SecondsToInterval(secs), PR_PRIORITY_NORMAL,
   532                 threadScopes[i], PR_JOINABLE_THREAD, 0);
   533             if (threads[idx] == NULL) {
   534                 fprintf(stderr, "PR_CreateThread failed\n");
   535                 exit(1);
   536             }
   537             secs++;
   538             idx++;
   539         }
   540     }
   541     for (idx = 0; idx < num_thread_scopes*num_thread_funcs; idx++) {
   542         if (PR_JoinThread(threads[idx]) == PR_FAILURE) {
   543             fprintf(stderr, "PR_JoinThread failed\n");
   544             exit(1);
   545         }
   546     }
   547     PR_Free(threads);
   548     printf("PASS\n");
   549     return 0;
   550 }

mercurial