summaryrefslogtreecommitdiffstats
path: root/nsprpub/pr/tests/y2ktmo.c
diff options
context:
space:
mode:
Diffstat (limited to 'nsprpub/pr/tests/y2ktmo.c')
-rw-r--r--nsprpub/pr/tests/y2ktmo.c550
1 files changed, 550 insertions, 0 deletions
diff --git a/nsprpub/pr/tests/y2ktmo.c b/nsprpub/pr/tests/y2ktmo.c
new file mode 100644
index 000000000..e55cf9977
--- /dev/null
+++ b/nsprpub/pr/tests/y2ktmo.c
@@ -0,0 +1,550 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * Test: y2ktmo
+ *
+ * Description:
+ * This test tests the interval time facilities in NSPR for Y2K
+ * compliance. All the functions that take a timeout argument
+ * are tested: PR_Sleep, socket I/O (PR_Accept is taken as a
+ * representative), PR_Poll, PR_WaitCondVar, PR_Wait, and
+ * PR_CWait. A thread of each thread scope (local, global, and
+ * global bound) is created to call each of these functions.
+ * The test should be started at the specified number of seconds
+ * (called the lead time) before a Y2K rollover test date. The
+ * timeout values for these threads will span over the rollover
+ * date by at least the specified number of seconds. For
+ * example, if the lead time is 5 seconds, the test should
+ * be started at time (D - 5), where D is a rollover date, and
+ * the threads will time out at or after time (D + 5). The
+ * timeout values for the threads are spaced one second apart.
+ *
+ * When a thread times out, it calls PR_IntervalNow() to verify
+ * that it did wait for the specified time. In addition, it
+ * calls a platform-native function to verify the actual elapsed
+ * time again, to rule out the possibility that PR_IntervalNow()
+ * is broken. We allow the actual elapsed time to deviate from
+ * the specified timeout by a certain tolerance (in milliseconds).
+ */
+
+#include "nspr.h"
+#include "plgetopt.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if defined(XP_UNIX)
+#include <sys/time.h> /* for gettimeofday */
+#endif
+#if defined(WIN32)
+#if defined(WINCE)
+#include <windows.h>
+#else
+#include <sys/types.h>
+#include <sys/timeb.h> /* for _ftime */
+#endif
+#endif
+
+#define DEFAULT_LEAD_TIME_SECS 5
+#define DEFAULT_TOLERANCE_MSECS 500
+
+static PRBool debug_mode = PR_FALSE;
+static PRInt32 lead_time_secs = DEFAULT_LEAD_TIME_SECS;
+static PRInt32 tolerance_msecs = DEFAULT_TOLERANCE_MSECS;
+static PRIntervalTime start_time;
+static PRIntervalTime tolerance;
+
+#if defined(XP_UNIX)
+static struct timeval start_time_tv;
+#endif
+#if defined(WIN32)
+#if defined(WINCE)
+static DWORD start_time_tick;
+#else
+static struct _timeb start_time_tb;
+#endif
+#endif
+
+static void SleepThread(void *arg)
+{
+ PRIntervalTime timeout = (PRIntervalTime) arg;
+ PRIntervalTime elapsed;
+#if defined(XP_UNIX) || defined(WIN32)
+ PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout);
+ PRInt32 elapsed_msecs;
+#endif
+#if defined(XP_UNIX)
+ struct timeval end_time_tv;
+#endif
+#if defined(WIN32) && !defined(WINCE)
+ struct _timeb end_time_tb;
+#endif
+
+ if (PR_Sleep(timeout) == PR_FAILURE) {
+ fprintf(stderr, "PR_Sleep failed\n");
+ exit(1);
+ }
+ elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
+ if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
+ fprintf(stderr, "timeout wrong\n");
+ exit(1);
+ }
+#if defined(XP_UNIX)
+ gettimeofday(&end_time_tv, NULL);
+ elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec)
+ + (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000;
+#endif
+#if defined(WIN32)
+#if defined(WINCE)
+ elapsed_msecs = GetTickCount() - start_time_tick;
+#else
+ _ftime(&end_time_tb);
+ elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time)
+ + (end_time_tb.millitm - start_time_tb.millitm);
+#endif
+#endif
+#if defined(XP_UNIX) || defined(WIN32)
+ if (elapsed_msecs + tolerance_msecs < timeout_msecs
+ || elapsed_msecs > timeout_msecs + tolerance_msecs) {
+ fprintf(stderr, "timeout wrong\n");
+ exit(1);
+ }
+#endif
+ if (debug_mode) {
+ fprintf(stderr, "Sleep thread (scope %d) done\n",
+ PR_GetThreadScope(PR_GetCurrentThread()));
+ }
+}
+
+static void AcceptThread(void *arg)
+{
+ PRIntervalTime timeout = (PRIntervalTime) arg;
+ PRIntervalTime elapsed;
+#if defined(XP_UNIX) || defined(WIN32)
+ PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout);
+ PRInt32 elapsed_msecs;
+#endif
+#if defined(XP_UNIX)
+ struct timeval end_time_tv;
+#endif
+#if defined(WIN32) && !defined(WINCE)
+ struct _timeb end_time_tb;
+#endif
+ PRFileDesc *sock;
+ PRNetAddr addr;
+ PRFileDesc *accepted;
+
+ sock = PR_NewTCPSocket();
+ if (sock == NULL) {
+ fprintf(stderr, "PR_NewTCPSocket failed\n");
+ exit(1);
+ }
+ memset(&addr, 0, sizeof(addr));
+ addr.inet.family = PR_AF_INET;
+ addr.inet.port = 0;
+ addr.inet.ip = PR_htonl(PR_INADDR_ANY);
+ if (PR_Bind(sock, &addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_Bind failed\n");
+ exit(1);
+ }
+ if (PR_Listen(sock, 5) == PR_FAILURE) {
+ fprintf(stderr, "PR_Listen failed\n");
+ exit(1);
+ }
+ accepted = PR_Accept(sock, NULL, timeout);
+ if (accepted != NULL || PR_GetError() != PR_IO_TIMEOUT_ERROR) {
+ fprintf(stderr, "PR_Accept did not time out\n");
+ exit(1);
+ }
+ elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
+ if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
+ fprintf(stderr, "timeout wrong\n");
+ exit(1);
+ }
+#if defined(XP_UNIX)
+ gettimeofday(&end_time_tv, NULL);
+ elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec)
+ + (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000;
+#endif
+#if defined(WIN32)
+#if defined(WINCE)
+ elapsed_msecs = GetTickCount() - start_time_tick;
+#else
+ _ftime(&end_time_tb);
+ elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time)
+ + (end_time_tb.millitm - start_time_tb.millitm);
+#endif
+#endif
+#if defined(XP_UNIX) || defined(WIN32)
+ if (elapsed_msecs + tolerance_msecs < timeout_msecs
+ || elapsed_msecs > timeout_msecs + tolerance_msecs) {
+ fprintf(stderr, "timeout wrong\n");
+ exit(1);
+ }
+#endif
+ if (PR_Close(sock) == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+ if (debug_mode) {
+ fprintf(stderr, "Accept thread (scope %d) done\n",
+ PR_GetThreadScope(PR_GetCurrentThread()));
+ }
+}
+
+static void PollThread(void *arg)
+{
+ PRIntervalTime timeout = (PRIntervalTime) arg;
+ PRIntervalTime elapsed;
+#if defined(XP_UNIX) || defined(WIN32)
+ PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout);
+ PRInt32 elapsed_msecs;
+#endif
+#if defined(XP_UNIX)
+ struct timeval end_time_tv;
+#endif
+#if defined(WIN32) && !defined(WINCE)
+ struct _timeb end_time_tb;
+#endif
+ PRFileDesc *sock;
+ PRNetAddr addr;
+ PRPollDesc pd;
+ PRIntn rv;
+
+ sock = PR_NewTCPSocket();
+ if (sock == NULL) {
+ fprintf(stderr, "PR_NewTCPSocket failed\n");
+ exit(1);
+ }
+ memset(&addr, 0, sizeof(addr));
+ addr.inet.family = PR_AF_INET;
+ addr.inet.port = 0;
+ addr.inet.ip = PR_htonl(PR_INADDR_ANY);
+ if (PR_Bind(sock, &addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_Bind failed\n");
+ exit(1);
+ }
+ if (PR_Listen(sock, 5) == PR_FAILURE) {
+ fprintf(stderr, "PR_Listen failed\n");
+ exit(1);
+ }
+ pd.fd = sock;
+ pd.in_flags = PR_POLL_READ;
+ rv = PR_Poll(&pd, 1, timeout);
+ if (rv != 0) {
+ fprintf(stderr, "PR_Poll did not time out\n");
+ exit(1);
+ }
+ elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
+ if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
+ fprintf(stderr, "timeout wrong\n");
+ exit(1);
+ }
+#if defined(XP_UNIX)
+ gettimeofday(&end_time_tv, NULL);
+ elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec)
+ + (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000;
+#endif
+#if defined(WIN32)
+#if defined(WINCE)
+ elapsed_msecs = GetTickCount() - start_time_tick;
+#else
+ _ftime(&end_time_tb);
+ elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time)
+ + (end_time_tb.millitm - start_time_tb.millitm);
+#endif
+#endif
+#if defined(XP_UNIX) || defined(WIN32)
+ if (elapsed_msecs + tolerance_msecs < timeout_msecs
+ || elapsed_msecs > timeout_msecs + tolerance_msecs) {
+ fprintf(stderr, "timeout wrong\n");
+ exit(1);
+ }
+#endif
+ if (PR_Close(sock) == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+ if (debug_mode) {
+ fprintf(stderr, "Poll thread (scope %d) done\n",
+ PR_GetThreadScope(PR_GetCurrentThread()));
+ }
+}
+
+static void WaitCondVarThread(void *arg)
+{
+ PRIntervalTime timeout = (PRIntervalTime) arg;
+ PRIntervalTime elapsed;
+#if defined(XP_UNIX) || defined(WIN32)
+ PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout);
+ PRInt32 elapsed_msecs;
+#endif
+#if defined(XP_UNIX)
+ struct timeval end_time_tv;
+#endif
+#if defined(WIN32) && !defined(WINCE)
+ struct _timeb end_time_tb;
+#endif
+ PRLock *ml;
+ PRCondVar *cv;
+
+ ml = PR_NewLock();
+ if (ml == NULL) {
+ fprintf(stderr, "PR_NewLock failed\n");
+ exit(1);
+ }
+ cv = PR_NewCondVar(ml);
+ if (cv == NULL) {
+ fprintf(stderr, "PR_NewCondVar failed\n");
+ exit(1);
+ }
+ PR_Lock(ml);
+ PR_WaitCondVar(cv, timeout);
+ PR_Unlock(ml);
+ elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
+ if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
+ fprintf(stderr, "timeout wrong\n");
+ exit(1);
+ }
+#if defined(XP_UNIX)
+ gettimeofday(&end_time_tv, NULL);
+ elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec)
+ + (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000;
+#endif
+#if defined(WIN32)
+#if defined(WINCE)
+ elapsed_msecs = GetTickCount() - start_time_tick;
+#else
+ _ftime(&end_time_tb);
+ elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time)
+ + (end_time_tb.millitm - start_time_tb.millitm);
+#endif
+#endif
+#if defined(XP_UNIX) || defined(WIN32)
+ if (elapsed_msecs + tolerance_msecs < timeout_msecs
+ || elapsed_msecs > timeout_msecs + tolerance_msecs) {
+ fprintf(stderr, "timeout wrong\n");
+ exit(1);
+ }
+#endif
+ PR_DestroyCondVar(cv);
+ PR_DestroyLock(ml);
+ if (debug_mode) {
+ fprintf(stderr, "wait cond var thread (scope %d) done\n",
+ PR_GetThreadScope(PR_GetCurrentThread()));
+ }
+}
+
+static void WaitMonitorThread(void *arg)
+{
+ PRIntervalTime timeout = (PRIntervalTime) arg;
+ PRIntervalTime elapsed;
+#if defined(XP_UNIX) || defined(WIN32)
+ PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout);
+ PRInt32 elapsed_msecs;
+#endif
+#if defined(XP_UNIX)
+ struct timeval end_time_tv;
+#endif
+#if defined(WIN32) && !defined(WINCE)
+ struct _timeb end_time_tb;
+#endif
+ PRMonitor *mon;
+
+ mon = PR_NewMonitor();
+ if (mon == NULL) {
+ fprintf(stderr, "PR_NewMonitor failed\n");
+ exit(1);
+ }
+ PR_EnterMonitor(mon);
+ PR_Wait(mon, timeout);
+ PR_ExitMonitor(mon);
+ elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
+ if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
+ fprintf(stderr, "timeout wrong\n");
+ exit(1);
+ }
+#if defined(XP_UNIX)
+ gettimeofday(&end_time_tv, NULL);
+ elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec)
+ + (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000;
+#endif
+#if defined(WIN32)
+#if defined(WINCE)
+ elapsed_msecs = GetTickCount() - start_time_tick;
+#else
+ _ftime(&end_time_tb);
+ elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time)
+ + (end_time_tb.millitm - start_time_tb.millitm);
+#endif
+#endif
+#if defined(XP_UNIX) || defined(WIN32)
+ if (elapsed_msecs + tolerance_msecs < timeout_msecs
+ || elapsed_msecs > timeout_msecs + tolerance_msecs) {
+ fprintf(stderr, "timeout wrong\n");
+ exit(1);
+ }
+#endif
+ PR_DestroyMonitor(mon);
+ if (debug_mode) {
+ fprintf(stderr, "wait monitor thread (scope %d) done\n",
+ PR_GetThreadScope(PR_GetCurrentThread()));
+ }
+}
+
+static void WaitCMonitorThread(void *arg)
+{
+ PRIntervalTime timeout = (PRIntervalTime) arg;
+ PRIntervalTime elapsed;
+#if defined(XP_UNIX) || defined(WIN32)
+ PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout);
+ PRInt32 elapsed_msecs;
+#endif
+#if defined(XP_UNIX)
+ struct timeval end_time_tv;
+#endif
+#if defined(WIN32) && !defined(WINCE)
+ struct _timeb end_time_tb;
+#endif
+ int dummy;
+
+ PR_CEnterMonitor(&dummy);
+ PR_CWait(&dummy, timeout);
+ PR_CExitMonitor(&dummy);
+ elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
+ if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
+ fprintf(stderr, "timeout wrong\n");
+ exit(1);
+ }
+#if defined(XP_UNIX)
+ gettimeofday(&end_time_tv, NULL);
+ elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec)
+ + (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000;
+#endif
+#if defined(WIN32)
+#if defined(WINCE)
+ elapsed_msecs = GetTickCount() - start_time_tick;
+#else
+ _ftime(&end_time_tb);
+ elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time)
+ + (end_time_tb.millitm - start_time_tb.millitm);
+#endif
+#endif
+#if defined(XP_UNIX) || defined(WIN32)
+ if (elapsed_msecs + tolerance_msecs < timeout_msecs
+ || elapsed_msecs > timeout_msecs + tolerance_msecs) {
+ fprintf(stderr, "timeout wrong\n");
+ exit(1);
+ }
+#endif
+ if (debug_mode) {
+ fprintf(stderr, "wait cached monitor thread (scope %d) done\n",
+ PR_GetThreadScope(PR_GetCurrentThread()));
+ }
+}
+
+typedef void (*NSPRThreadFunc)(void*);
+
+static NSPRThreadFunc threadFuncs[] = {
+ SleepThread, AcceptThread, PollThread,
+ WaitCondVarThread, WaitMonitorThread, WaitCMonitorThread};
+
+static PRThreadScope threadScopes[] = {
+ PR_LOCAL_THREAD, PR_GLOBAL_THREAD, PR_GLOBAL_BOUND_THREAD};
+
+static void Help(void)
+{
+ fprintf(stderr, "y2ktmo test program usage:\n");
+ fprintf(stderr, "\t-d debug mode (FALSE)\n");
+ fprintf(stderr, "\t-l <secs> lead time (%d)\n",
+ DEFAULT_LEAD_TIME_SECS);
+ fprintf(stderr, "\t-t <msecs> tolerance (%d)\n",
+ DEFAULT_TOLERANCE_MSECS);
+ fprintf(stderr, "\t-h this message\n");
+} /* Help */
+
+int main(int argc, char **argv)
+{
+ PRThread **threads;
+ int num_thread_funcs = sizeof(threadFuncs)/sizeof(NSPRThreadFunc);
+ int num_thread_scopes = sizeof(threadScopes)/sizeof(PRThreadScope);
+ int i, j;
+ int idx;
+ PRInt32 secs;
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "dl:t:h");
+
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) {
+ if (PL_OPT_BAD == os) continue;
+ switch (opt->option) {
+ case 'd': /* debug mode */
+ debug_mode = PR_TRUE;
+ break;
+ case 'l': /* lead time */
+ lead_time_secs = atoi(opt->value);
+ break;
+ case 't': /* tolerance */
+ tolerance_msecs = atoi(opt->value);
+ break;
+ case 'h':
+ default:
+ Help();
+ return 2;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ if (debug_mode) {
+ fprintf(stderr, "lead time: %d secs\n", lead_time_secs);
+ fprintf(stderr, "tolerance: %d msecs\n", tolerance_msecs);
+ }
+
+ start_time = PR_IntervalNow();
+#if defined(XP_UNIX)
+ gettimeofday(&start_time_tv, NULL);
+#endif
+#if defined(WIN32)
+#ifdef WINCE
+ start_time_tick = GetTickCount();
+#else
+ _ftime(&start_time_tb);
+#endif
+#endif
+ tolerance = PR_MillisecondsToInterval(tolerance_msecs);
+
+ threads = PR_Malloc(
+ num_thread_scopes * num_thread_funcs * sizeof(PRThread*));
+ if (threads == NULL) {
+ fprintf(stderr, "PR_Malloc failed\n");
+ exit(1);
+ }
+
+ /* start to time out 5 seconds after a rollover date */
+ secs = lead_time_secs + 5;
+ idx = 0;
+ for (i = 0; i < num_thread_scopes; i++) {
+ for (j = 0; j < num_thread_funcs; j++) {
+ threads[idx] = PR_CreateThread(PR_USER_THREAD, threadFuncs[j],
+ (void*)PR_SecondsToInterval(secs), PR_PRIORITY_NORMAL,
+ threadScopes[i], PR_JOINABLE_THREAD, 0);
+ if (threads[idx] == NULL) {
+ fprintf(stderr, "PR_CreateThread failed\n");
+ exit(1);
+ }
+ secs++;
+ idx++;
+ }
+ }
+ for (idx = 0; idx < num_thread_scopes*num_thread_funcs; idx++) {
+ if (PR_JoinThread(threads[idx]) == PR_FAILURE) {
+ fprintf(stderr, "PR_JoinThread failed\n");
+ exit(1);
+ }
+ }
+ PR_Free(threads);
+ printf("PASS\n");
+ return 0;
+}