Back to index

lightning-sunbird  0.9+nobinonly
y2ktmo.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Netscape Portable Runtime (NSPR).
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1999-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /*
00039  * Test: y2ktmo
00040  *
00041  * Description:
00042  *   This test tests the interval time facilities in NSPR for Y2K
00043  *   compliance.  All the functions that take a timeout argument
00044  *   are tested: PR_Sleep, socket I/O (PR_Accept is taken as a
00045  *   representative), PR_Poll, PR_WaitCondVar, PR_Wait, and
00046  *   PR_CWait.  A thread of each thread scope (local, global, and
00047  *   global bound) is created to call each of these functions.
00048  *   The test should be started at the specified number of seconds
00049  *   (called the lead time) before a Y2K rollover test date.  The
00050  *   timeout values for these threads will span over the rollover
00051  *   date by at least the specified number of seconds.  For
00052  *   example, if the lead time is 5 seconds, the test should
00053  *   be started at time (D - 5), where D is a rollover date, and
00054  *   the threads will time out at or after time (D + 5).  The
00055  *   timeout values for the threads are spaced one second apart.
00056  *
00057  *   When a thread times out, it calls PR_IntervalNow() to verify
00058  *   that it did wait for the specified time.  In addition, it
00059  *   calls a platform-native function to verify the actual elapsed
00060  *   time again, to rule out the possibility that PR_IntervalNow()
00061  *   is broken.  We allow the actual elapsed time to deviate from
00062  *   the specified timeout by a certain tolerance (in milliseconds).
00063  */ 
00064 
00065 #include "nspr.h"
00066 #include "plgetopt.h"
00067 
00068 #include <stdio.h>
00069 #include <stdlib.h>
00070 #include <string.h>
00071 #if defined(XP_UNIX)
00072 #include <sys/time.h> /* for gettimeofday */
00073 #endif
00074 #if defined(WIN32)
00075 #include <sys/types.h>
00076 #include <sys/timeb.h>  /* for _ftime */
00077 #endif
00078 
00079 #define DEFAULT_LEAD_TIME_SECS 5
00080 #define DEFAULT_TOLERANCE_MSECS 500
00081 
00082 static PRBool debug_mode = PR_FALSE;
00083 static PRInt32 lead_time_secs = DEFAULT_LEAD_TIME_SECS;
00084 static PRInt32 tolerance_msecs = DEFAULT_TOLERANCE_MSECS;
00085 static PRIntervalTime start_time;
00086 static PRIntervalTime tolerance;
00087 
00088 #if defined(XP_UNIX)
00089 static struct timeval start_time_tv;
00090 #endif
00091 #if defined(WIN32)
00092 static struct _timeb start_time_tb;
00093 #endif
00094 
00095 static void SleepThread(void *arg)
00096 {
00097     PRIntervalTime timeout = (PRIntervalTime) arg;
00098     PRIntervalTime elapsed;
00099 #if defined(XP_UNIX) || defined(WIN32)
00100     PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout);
00101     PRInt32 elapsed_msecs;
00102 #endif
00103 #if defined(XP_UNIX)
00104     struct timeval end_time_tv;
00105 #endif
00106 #if defined(WIN32)
00107     struct _timeb end_time_tb;
00108 #endif
00109 
00110     if (PR_Sleep(timeout) == PR_FAILURE) {
00111         fprintf(stderr, "PR_Sleep failed\n");
00112         exit(1);
00113     }
00114     elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
00115     if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
00116         fprintf(stderr, "timeout wrong\n");
00117         exit(1);
00118     }
00119 #if defined(XP_UNIX)
00120     gettimeofday(&end_time_tv, NULL);
00121     elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec)
00122             + (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000;
00123 #endif
00124 #if defined(WIN32)
00125     _ftime(&end_time_tb);
00126     elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time)
00127             + (end_time_tb.millitm - start_time_tb.millitm);
00128 #endif
00129 #if defined(XP_UNIX) || defined(WIN32)
00130     if (elapsed_msecs + tolerance_msecs < timeout_msecs
00131             || elapsed_msecs > timeout_msecs + tolerance_msecs) {
00132         fprintf(stderr, "timeout wrong\n");
00133         exit(1);
00134     }
00135 #endif
00136     if (debug_mode) {
00137         fprintf(stderr, "Sleep thread (scope %d) done\n",
00138                 PR_GetThreadScope(PR_GetCurrentThread()));
00139     }
00140 }
00141 
00142 static void AcceptThread(void *arg)
00143 {
00144     PRIntervalTime timeout = (PRIntervalTime) arg;
00145     PRIntervalTime elapsed;
00146 #if defined(XP_UNIX) || defined(WIN32)
00147     PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout);
00148     PRInt32 elapsed_msecs;
00149 #endif
00150 #if defined(XP_UNIX)
00151     struct timeval end_time_tv;
00152 #endif
00153 #if defined(WIN32)
00154     struct _timeb end_time_tb;
00155 #endif
00156     PRFileDesc *sock;
00157     PRNetAddr addr;
00158     PRFileDesc *accepted;
00159 
00160     sock = PR_NewTCPSocket();
00161     if (sock == NULL) {
00162         fprintf(stderr, "PR_NewTCPSocket failed\n");
00163         exit(1);
00164     }
00165     memset(&addr, 0, sizeof(addr));
00166     addr.inet.family = PR_AF_INET;
00167     addr.inet.port = 0;
00168     addr.inet.ip = PR_htonl(PR_INADDR_ANY);
00169     if (PR_Bind(sock, &addr) == PR_FAILURE) {
00170         fprintf(stderr, "PR_Bind failed\n");
00171         exit(1);
00172     }
00173     if (PR_Listen(sock, 5) == PR_FAILURE) {
00174         fprintf(stderr, "PR_Listen failed\n");
00175         exit(1);
00176     }
00177     accepted = PR_Accept(sock, NULL, timeout);
00178     if (accepted != NULL || PR_GetError() != PR_IO_TIMEOUT_ERROR) {
00179         fprintf(stderr, "PR_Accept did not time out\n");
00180         exit(1);
00181     }
00182     elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
00183     if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
00184         fprintf(stderr, "timeout wrong\n");
00185         exit(1);
00186     }
00187 #if defined(XP_UNIX)
00188     gettimeofday(&end_time_tv, NULL);
00189     elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec)
00190             + (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000;
00191 #endif
00192 #if defined(WIN32)
00193     _ftime(&end_time_tb);
00194     elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time)
00195             + (end_time_tb.millitm - start_time_tb.millitm);
00196 #endif
00197 #if defined(XP_UNIX) || defined(WIN32)
00198     if (elapsed_msecs + tolerance_msecs < timeout_msecs
00199             || elapsed_msecs > timeout_msecs + tolerance_msecs) {
00200         fprintf(stderr, "timeout wrong\n");
00201         exit(1);
00202     }
00203 #endif
00204     if (PR_Close(sock) == PR_FAILURE) {
00205         fprintf(stderr, "PR_Close failed\n");
00206         exit(1);
00207     }
00208     if (debug_mode) {
00209         fprintf(stderr, "Accept thread (scope %d) done\n",
00210                 PR_GetThreadScope(PR_GetCurrentThread()));
00211     }
00212 }
00213 
00214 static void PollThread(void *arg)
00215 {
00216     PRIntervalTime timeout = (PRIntervalTime) arg;
00217     PRIntervalTime elapsed;
00218 #if defined(XP_UNIX) || defined(WIN32)
00219     PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout);
00220     PRInt32 elapsed_msecs;
00221 #endif
00222 #if defined(XP_UNIX)
00223     struct timeval end_time_tv;
00224 #endif
00225 #if defined(WIN32)
00226     struct _timeb end_time_tb;
00227 #endif
00228     PRFileDesc *sock;
00229     PRNetAddr addr;
00230     PRPollDesc pd;
00231     PRIntn rv;
00232 
00233     sock = PR_NewTCPSocket();
00234     if (sock == NULL) {
00235         fprintf(stderr, "PR_NewTCPSocket failed\n");
00236         exit(1);
00237     }
00238     memset(&addr, 0, sizeof(addr));
00239     addr.inet.family = PR_AF_INET;
00240     addr.inet.port = 0;
00241     addr.inet.ip = PR_htonl(PR_INADDR_ANY);
00242     if (PR_Bind(sock, &addr) == PR_FAILURE) {
00243         fprintf(stderr, "PR_Bind failed\n");
00244         exit(1);
00245     }
00246     if (PR_Listen(sock, 5) == PR_FAILURE) {
00247         fprintf(stderr, "PR_Listen failed\n");
00248         exit(1);
00249     }
00250     pd.fd = sock;
00251     pd.in_flags = PR_POLL_READ;
00252     rv = PR_Poll(&pd, 1, timeout);
00253     if (rv != 0) {
00254         fprintf(stderr, "PR_Poll did not time out\n");
00255         exit(1);
00256     }
00257     elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
00258     if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
00259         fprintf(stderr, "timeout wrong\n");
00260         exit(1);
00261     }
00262 #if defined(XP_UNIX)
00263     gettimeofday(&end_time_tv, NULL);
00264     elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec)
00265             + (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000;
00266 #endif
00267 #if defined(WIN32)
00268     _ftime(&end_time_tb);
00269     elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time)
00270             + (end_time_tb.millitm - start_time_tb.millitm);
00271 #endif
00272 #if defined(XP_UNIX) || defined(WIN32)
00273     if (elapsed_msecs + tolerance_msecs < timeout_msecs
00274             || elapsed_msecs > timeout_msecs + tolerance_msecs) {
00275         fprintf(stderr, "timeout wrong\n");
00276         exit(1);
00277     }
00278 #endif
00279     if (PR_Close(sock) == PR_FAILURE) {
00280         fprintf(stderr, "PR_Close failed\n");
00281         exit(1);
00282     }
00283     if (debug_mode) {
00284         fprintf(stderr, "Poll thread (scope %d) done\n",
00285                 PR_GetThreadScope(PR_GetCurrentThread()));
00286     }
00287 }
00288 
00289 static void WaitCondVarThread(void *arg)
00290 {
00291     PRIntervalTime timeout = (PRIntervalTime) arg;
00292     PRIntervalTime elapsed;
00293 #if defined(XP_UNIX) || defined(WIN32)
00294     PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout);
00295     PRInt32 elapsed_msecs;
00296 #endif
00297 #if defined(XP_UNIX)
00298     struct timeval end_time_tv;
00299 #endif
00300 #if defined(WIN32)
00301     struct _timeb end_time_tb;
00302 #endif
00303     PRLock *ml;
00304     PRCondVar *cv;
00305 
00306     ml = PR_NewLock();
00307     if (ml == NULL) {
00308         fprintf(stderr, "PR_NewLock failed\n");
00309         exit(1);
00310     }
00311     cv = PR_NewCondVar(ml);
00312     if (cv == NULL) {
00313         fprintf(stderr, "PR_NewCondVar failed\n");
00314         exit(1);
00315     }
00316     PR_Lock(ml);
00317     PR_WaitCondVar(cv, timeout);
00318     PR_Unlock(ml);
00319     elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
00320     if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
00321         fprintf(stderr, "timeout wrong\n");
00322         exit(1);
00323     }
00324 #if defined(XP_UNIX)
00325     gettimeofday(&end_time_tv, NULL);
00326     elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec)
00327             + (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000;
00328 #endif
00329 #if defined(WIN32)
00330     _ftime(&end_time_tb);
00331     elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time)
00332             + (end_time_tb.millitm - start_time_tb.millitm);
00333 #endif
00334 #if defined(XP_UNIX) || defined(WIN32)
00335     if (elapsed_msecs + tolerance_msecs < timeout_msecs
00336             || elapsed_msecs > timeout_msecs + tolerance_msecs) {
00337         fprintf(stderr, "timeout wrong\n");
00338         exit(1);
00339     }
00340 #endif
00341     PR_DestroyCondVar(cv);
00342     PR_DestroyLock(ml);
00343     if (debug_mode) {
00344         fprintf(stderr, "wait cond var thread (scope %d) done\n",
00345                 PR_GetThreadScope(PR_GetCurrentThread()));
00346     }
00347 }
00348 
00349 static void WaitMonitorThread(void *arg)
00350 {
00351     PRIntervalTime timeout = (PRIntervalTime) arg;
00352     PRIntervalTime elapsed;
00353 #if defined(XP_UNIX) || defined(WIN32)
00354     PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout);
00355     PRInt32 elapsed_msecs;
00356 #endif
00357 #if defined(XP_UNIX)
00358     struct timeval end_time_tv;
00359 #endif
00360 #if defined(WIN32)
00361     struct _timeb end_time_tb;
00362 #endif
00363     PRMonitor *mon;
00364 
00365     mon = PR_NewMonitor();
00366     if (mon == NULL) {
00367         fprintf(stderr, "PR_NewMonitor failed\n");
00368         exit(1);
00369     }
00370     PR_EnterMonitor(mon);
00371     PR_Wait(mon, timeout);
00372     PR_ExitMonitor(mon);
00373     elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
00374     if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
00375         fprintf(stderr, "timeout wrong\n");
00376         exit(1);
00377     }
00378 #if defined(XP_UNIX)
00379     gettimeofday(&end_time_tv, NULL);
00380     elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec)
00381             + (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000;
00382 #endif
00383 #if defined(WIN32)
00384     _ftime(&end_time_tb);
00385     elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time)
00386             + (end_time_tb.millitm - start_time_tb.millitm);
00387 #endif
00388 #if defined(XP_UNIX) || defined(WIN32)
00389     if (elapsed_msecs + tolerance_msecs < timeout_msecs
00390             || elapsed_msecs > timeout_msecs + tolerance_msecs) {
00391         fprintf(stderr, "timeout wrong\n");
00392         exit(1);
00393     }
00394 #endif
00395     PR_DestroyMonitor(mon);
00396     if (debug_mode) {
00397         fprintf(stderr, "wait monitor thread (scope %d) done\n",
00398                 PR_GetThreadScope(PR_GetCurrentThread()));
00399     }
00400 }
00401 
00402 static void WaitCMonitorThread(void *arg)
00403 {
00404     PRIntervalTime timeout = (PRIntervalTime) arg;
00405     PRIntervalTime elapsed;
00406 #if defined(XP_UNIX) || defined(WIN32)
00407     PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout);
00408     PRInt32 elapsed_msecs;
00409 #endif
00410 #if defined(XP_UNIX)
00411     struct timeval end_time_tv;
00412 #endif
00413 #if defined(WIN32)
00414     struct _timeb end_time_tb;
00415 #endif
00416     int dummy;
00417 
00418     PR_CEnterMonitor(&dummy);
00419     PR_CWait(&dummy, timeout);
00420     PR_CExitMonitor(&dummy);
00421     elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
00422     if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
00423         fprintf(stderr, "timeout wrong\n");
00424         exit(1);
00425     }
00426 #if defined(XP_UNIX)
00427     gettimeofday(&end_time_tv, NULL);
00428     elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec)
00429             + (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000;
00430 #endif
00431 #if defined(WIN32)
00432     _ftime(&end_time_tb);
00433     elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time)
00434             + (end_time_tb.millitm - start_time_tb.millitm);
00435 #endif
00436 #if defined(XP_UNIX) || defined(WIN32)
00437     if (elapsed_msecs + tolerance_msecs < timeout_msecs
00438             || elapsed_msecs > timeout_msecs + tolerance_msecs) {
00439         fprintf(stderr, "timeout wrong\n");
00440         exit(1);
00441     }
00442 #endif
00443     if (debug_mode) {
00444         fprintf(stderr, "wait cached monitor thread (scope %d) done\n",
00445                 PR_GetThreadScope(PR_GetCurrentThread()));
00446     }
00447 }
00448 
00449 typedef void (*NSPRThreadFunc)(void*);
00450 
00451 static NSPRThreadFunc threadFuncs[] = {
00452     SleepThread, AcceptThread, PollThread,
00453     WaitCondVarThread, WaitMonitorThread, WaitCMonitorThread};
00454 
00455 static PRThreadScope threadScopes[] = {
00456     PR_LOCAL_THREAD, PR_GLOBAL_THREAD, PR_GLOBAL_BOUND_THREAD};
00457 
00458 static void Help(void)
00459 {
00460     fprintf(stderr, "y2ktmo test program usage:\n");
00461     fprintf(stderr, "\t-d           debug mode         (FALSE)\n");
00462     fprintf(stderr, "\t-l <secs>    lead time          (%d)\n",
00463             DEFAULT_LEAD_TIME_SECS);
00464     fprintf(stderr, "\t-t <msecs>   tolerance          (%d)\n",
00465             DEFAULT_TOLERANCE_MSECS);
00466     fprintf(stderr, "\t-h           this message\n");
00467 }  /* Help */
00468 
00469 int main(int argc, char **argv)
00470 {
00471     PRThread **threads;
00472     int num_thread_funcs = sizeof(threadFuncs)/sizeof(NSPRThreadFunc);
00473     int num_thread_scopes = sizeof(threadScopes)/sizeof(PRThreadScope);
00474     int i, j;
00475     int idx;
00476     PRInt32 secs;
00477     PLOptStatus os;
00478     PLOptState *opt = PL_CreateOptState(argc, argv, "dl:t:h");
00479 
00480     while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) {
00481         if (PL_OPT_BAD == os) continue;
00482         switch (opt->option) {
00483             case 'd':  /* debug mode */
00484                 debug_mode = PR_TRUE;
00485                 break;
00486             case 'l':  /* lead time */
00487                 lead_time_secs = atoi(opt->value);
00488                 break;
00489             case 't':  /* tolerance */
00490                 tolerance_msecs = atoi(opt->value);
00491                 break;
00492             case 'h':
00493             default:
00494                 Help();
00495                 return 2;
00496         }
00497     }
00498     PL_DestroyOptState(opt);
00499 
00500     if (debug_mode) {
00501         fprintf(stderr, "lead time: %d secs\n", lead_time_secs);
00502         fprintf(stderr, "tolerance: %d msecs\n", tolerance_msecs);
00503     }
00504 
00505     start_time = PR_IntervalNow();
00506 #if defined(XP_UNIX)
00507     gettimeofday(&start_time_tv, NULL);
00508 #endif
00509 #if defined(WIN32)
00510     _ftime(&start_time_tb);
00511 #endif
00512     tolerance = PR_MillisecondsToInterval(tolerance_msecs);
00513 
00514     threads = PR_Malloc(
00515             num_thread_scopes * num_thread_funcs * sizeof(PRThread*));
00516     if (threads == NULL) {
00517         fprintf(stderr, "PR_Malloc failed\n");
00518         exit(1);
00519     }
00520 
00521     /* start to time out 5 seconds after a rollover date */
00522     secs = lead_time_secs + 5;
00523     idx = 0;
00524     for (i = 0; i < num_thread_scopes; i++) { 
00525         for (j = 0; j < num_thread_funcs; j++) {
00526             threads[idx] = PR_CreateThread(PR_USER_THREAD, threadFuncs[j],
00527                 (void*)PR_SecondsToInterval(secs), PR_PRIORITY_NORMAL,
00528                 threadScopes[i], PR_JOINABLE_THREAD, 0);
00529             if (threads[idx] == NULL) {
00530                 fprintf(stderr, "PR_CreateThread failed\n");
00531                 exit(1);
00532             }
00533             secs++;
00534             idx++;
00535         }
00536     }
00537     for (idx = 0; idx < num_thread_scopes*num_thread_funcs; idx++) {
00538         if (PR_JoinThread(threads[idx]) == PR_FAILURE) {
00539             fprintf(stderr, "PR_JoinThread failed\n");
00540             exit(1);
00541         }
00542     }
00543     PR_Free(threads);
00544     printf("PASS\n");
00545     return 0;
00546 }