summaryrefslogtreecommitdiffstats
path: root/nsprpub/pr/tests/alarm.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--nsprpub/pr/tests/alarm.c552
1 files changed, 552 insertions, 0 deletions
diff --git a/nsprpub/pr/tests/alarm.c b/nsprpub/pr/tests/alarm.c
new file mode 100644
index 0000000000..10a148e448
--- /dev/null
+++ b/nsprpub/pr/tests/alarm.c
@@ -0,0 +1,552 @@
+/* -*- 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/. */
+
+/***********************************************************************
+** 1996 - Netscape Communications Corporation
+**
+** Name: alarmtst.c
+**
+** Description: Test alarms
+**
+** Modification History:
+** 13-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
+** The debug mode will print all of the printfs associated with this test.
+** The regress mode will be the default mode. Since the regress tool limits
+** the output to a one line status:PASS or FAIL,all of the printf statements
+** have been handled with an if (debug_mode) statement.
+** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
+** recognize the return code from tha main program.
+***********************************************************************/
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+
+#include "prlog.h"
+#include "prinit.h"
+#include "obsolete/pralarm.h"
+#include "prlock.h"
+#include "prlong.h"
+#include "prcvar.h"
+#include "prinrval.h"
+#include "prtime.h"
+
+/* Used to get the command line option */
+#include "plgetopt.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+#if defined(XP_UNIX)
+#include <sys/time.h>
+#endif
+
+static PRIntn debug_mode;
+static PRIntn failed_already=0;
+static PRThreadScope thread_scope = PR_LOCAL_THREAD;
+
+typedef struct notifyData {
+ PRLock *ml;
+ PRCondVar *child;
+ PRCondVar *parent;
+ PRBool pending;
+ PRUint32 counter;
+} NotifyData;
+
+static void Notifier(void *arg)
+{
+ NotifyData *notifyData = (NotifyData*)arg;
+ PR_Lock(notifyData->ml);
+ while (notifyData->counter > 0)
+ {
+ while (!notifyData->pending) {
+ PR_WaitCondVar(notifyData->child, PR_INTERVAL_NO_TIMEOUT);
+ }
+ notifyData->counter -= 1;
+ notifyData->pending = PR_FALSE;
+ PR_NotifyCondVar(notifyData->parent);
+ }
+ PR_Unlock(notifyData->ml);
+} /* Notifier */
+/***********************************************************************
+** PRIVATE FUNCTION: ConditionNotify
+** DESCRIPTION:
+**
+** INPUTS: loops
+** OUTPUTS: None
+** RETURN: overhead
+** SIDE EFFECTS:
+**
+** RESTRICTIONS:
+** None
+** MEMORY: NA
+** ALGORITHM:
+**
+***********************************************************************/
+
+
+static PRIntervalTime ConditionNotify(PRUint32 loops)
+{
+ PRThread *thread;
+ NotifyData notifyData;
+ PRIntervalTime timein, overhead;
+
+ timein = PR_IntervalNow();
+
+ notifyData.counter = loops;
+ notifyData.ml = PR_NewLock();
+ notifyData.child = PR_NewCondVar(notifyData.ml);
+ notifyData.parent = PR_NewCondVar(notifyData.ml);
+ thread = PR_CreateThread(
+ PR_USER_THREAD, Notifier, &notifyData,
+ PR_GetThreadPriority(PR_GetCurrentThread()),
+ thread_scope, PR_JOINABLE_THREAD, 0);
+
+ overhead = PR_IntervalNow() - timein; /* elapsed so far */
+
+ PR_Lock(notifyData.ml);
+ while (notifyData.counter > 0)
+ {
+ notifyData.pending = PR_TRUE;
+ PR_NotifyCondVar(notifyData.child);
+ while (notifyData.pending) {
+ PR_WaitCondVar(notifyData.parent, PR_INTERVAL_NO_TIMEOUT);
+ }
+ }
+ PR_Unlock(notifyData.ml);
+
+ timein = PR_IntervalNow();
+
+ (void)PR_JoinThread(thread);
+ PR_DestroyCondVar(notifyData.child);
+ PR_DestroyCondVar(notifyData.parent);
+ PR_DestroyLock(notifyData.ml);
+
+ overhead += (PR_IntervalNow() - timein); /* more overhead */
+
+ return overhead;
+} /* ConditionNotify */
+
+static PRIntervalTime ConditionTimeout(PRUint32 loops)
+{
+ PRUintn count;
+ PRIntervalTime overhead, timein = PR_IntervalNow();
+
+ PRLock *ml = PR_NewLock();
+ PRCondVar *cv = PR_NewCondVar(ml);
+ PRIntervalTime interval = PR_MillisecondsToInterval(50);
+
+ overhead = PR_IntervalNow() - timein;
+
+ PR_Lock(ml);
+ for (count = 0; count < loops; ++count)
+ {
+ overhead += interval;
+ PR_ASSERT(PR_WaitCondVar(cv, interval) == PR_SUCCESS);
+ }
+ PR_Unlock(ml);
+
+ timein = PR_IntervalNow();
+ PR_DestroyCondVar(cv);
+ PR_DestroyLock(ml);
+ overhead += (PR_IntervalNow() - timein);
+
+ return overhead;
+} /* ConditionTimeout */
+
+typedef struct AlarmData {
+ PRLock *ml;
+ PRCondVar *cv;
+ PRUint32 rate, late, times;
+ PRIntervalTime duration, timein, period;
+} AlarmData;
+
+static PRBool AlarmFn1(PRAlarmID *id, void *clientData, PRUint32 late)
+{
+ PRStatus rv = PR_SUCCESS;
+ PRBool keepGoing, resetAlarm;
+ PRIntervalTime interval, now = PR_IntervalNow();
+ AlarmData *ad = (AlarmData*)clientData;
+
+ PR_Lock(ad->ml);
+ ad->late += late;
+ ad->times += 1;
+ keepGoing = ((PRIntervalTime)(now - ad->timein) < ad->duration) ?
+ PR_TRUE : PR_FALSE;
+ if (!keepGoing) {
+ rv = PR_NotifyCondVar(ad->cv);
+ }
+ resetAlarm = ((ad->times % 31) == 0) ? PR_TRUE : PR_FALSE;
+
+ interval = (ad->period + ad->rate - 1) / ad->rate;
+ if (!late && (interval > 10))
+ {
+ interval &= (now & 0x03) + 1;
+ PR_WaitCondVar(ad->cv, interval);
+ }
+
+ PR_Unlock(ad->ml);
+
+ if (rv != PR_SUCCESS)
+ {
+ if (!debug_mode) {
+ failed_already=1;
+ }
+ else {
+ printf("AlarmFn: notify status: FAIL\n");
+ }
+
+ }
+
+ if (resetAlarm)
+ {
+ ad->rate += 3;
+ ad->late = ad->times = 0;
+ if (PR_ResetAlarm(id, ad->period, ad->rate) != PR_SUCCESS)
+ {
+ if (!debug_mode) {
+ failed_already=1;
+ }
+ else {
+ printf("AlarmFn: Resetting alarm status: FAIL\n");
+ }
+
+ keepGoing = PR_FALSE;
+ }
+
+ }
+
+ return keepGoing;
+} /* AlarmFn1 */
+
+static PRIntervalTime Alarms1(PRUint32 loops)
+{
+ PRAlarm *alarm;
+ AlarmData ad;
+ PRIntervalTime overhead, timein = PR_IntervalNow();
+ PRIntervalTime duration = PR_SecondsToInterval(3);
+
+ PRLock *ml = PR_NewLock();
+ PRCondVar *cv = PR_NewCondVar(ml);
+
+ ad.ml = ml;
+ ad.cv = cv;
+ ad.rate = 1;
+ ad.times = loops;
+ ad.late = ad.times = 0;
+ ad.duration = duration;
+ ad.timein = PR_IntervalNow();
+ ad.period = PR_SecondsToInterval(1);
+
+ alarm = PR_CreateAlarm();
+
+ (void)PR_SetAlarm(
+ alarm, ad.period, ad.rate, AlarmFn1, &ad);
+
+ overhead = PR_IntervalNow() - timein;
+
+ PR_Lock(ml);
+ while ((PRIntervalTime)(PR_IntervalNow() - ad.timein) < duration) {
+ PR_WaitCondVar(cv, PR_INTERVAL_NO_TIMEOUT);
+ }
+ PR_Unlock(ml);
+
+ timein = PR_IntervalNow();
+ (void)PR_DestroyAlarm(alarm);
+ PR_DestroyCondVar(cv);
+ PR_DestroyLock(ml);
+ overhead += (PR_IntervalNow() - timein);
+
+ return duration + overhead;
+} /* Alarms1 */
+
+static PRBool AlarmFn2(PRAlarmID *id, void *clientData, PRUint32 late)
+{
+ PRBool keepGoing;
+ PRStatus rv = PR_SUCCESS;
+ AlarmData *ad = (AlarmData*)clientData;
+ PRIntervalTime interval, now = PR_IntervalNow();
+
+ PR_Lock(ad->ml);
+ ad->times += 1;
+ keepGoing = ((PRIntervalTime)(now - ad->timein) < ad->duration) ?
+ PR_TRUE : PR_FALSE;
+ interval = (ad->period + ad->rate - 1) / ad->rate;
+
+ if (!late && (interval > 10))
+ {
+ interval &= (now & 0x03) + 1;
+ PR_WaitCondVar(ad->cv, interval);
+ }
+
+ if (!keepGoing) {
+ rv = PR_NotifyCondVar(ad->cv);
+ }
+
+ PR_Unlock(ad->ml);
+
+
+ if (rv != PR_SUCCESS) {
+ failed_already=1;
+ };
+
+ return keepGoing;
+} /* AlarmFn2 */
+
+static PRIntervalTime Alarms2(PRUint32 loops)
+{
+ PRStatus rv;
+ PRAlarm *alarm;
+ PRIntervalTime overhead, timein = PR_IntervalNow();
+ AlarmData ad;
+ PRIntervalTime duration = PR_SecondsToInterval(30);
+
+ PRLock *ml = PR_NewLock();
+ PRCondVar *cv = PR_NewCondVar(ml);
+
+ ad.ml = ml;
+ ad.cv = cv;
+ ad.rate = 1;
+ ad.times = loops;
+ ad.late = ad.times = 0;
+ ad.duration = duration;
+ ad.timein = PR_IntervalNow();
+ ad.period = PR_SecondsToInterval(1);
+
+ alarm = PR_CreateAlarm();
+
+ (void)PR_SetAlarm(
+ alarm, ad.period, ad.rate, AlarmFn2, &ad);
+
+ overhead = PR_IntervalNow() - timein;
+
+ PR_Lock(ml);
+ while ((PRIntervalTime)(PR_IntervalNow() - ad.timein) < duration) {
+ PR_WaitCondVar(cv, PR_INTERVAL_NO_TIMEOUT);
+ }
+ PR_Unlock(ml);
+
+ timein = PR_IntervalNow();
+
+ rv = PR_DestroyAlarm(alarm);
+ if (rv != PR_SUCCESS)
+ {
+ if (!debug_mode) {
+ failed_already=1;
+ }
+ else {
+ printf("***Destroying alarm status: FAIL\n");
+ }
+ }
+
+
+ PR_DestroyCondVar(cv);
+ PR_DestroyLock(ml);
+
+ overhead += (PR_IntervalNow() - timein);
+
+ return duration + overhead;
+} /* Alarms2 */
+
+static PRIntervalTime Alarms3(PRUint32 loops)
+{
+ PRIntn i;
+ PRStatus rv;
+ PRAlarm *alarm;
+ AlarmData ad[3];
+ PRIntervalTime duration = PR_SecondsToInterval(30);
+ PRIntervalTime overhead, timein = PR_IntervalNow();
+
+ PRLock *ml = PR_NewLock();
+ PRCondVar *cv = PR_NewCondVar(ml);
+
+ for (i = 0; i < 3; ++i)
+ {
+ ad[i].ml = ml;
+ ad[i].cv = cv;
+ ad[i].rate = 1;
+ ad[i].times = loops;
+ ad[i].duration = duration;
+ ad[i].late = ad[i].times = 0;
+ ad[i].timein = PR_IntervalNow();
+ ad[i].period = PR_SecondsToInterval(1);
+
+ /* more loops, faster rate => same elapsed time */
+ ad[i].times = (i + 1) * loops;
+ ad[i].rate = (i + 1) * 10;
+ }
+
+ alarm = PR_CreateAlarm();
+
+ for (i = 0; i < 3; ++i)
+ {
+ (void)PR_SetAlarm(
+ alarm, ad[i].period, ad[i].rate,
+ AlarmFn2, &ad[i]);
+ }
+
+ overhead = PR_IntervalNow() - timein;
+
+ PR_Lock(ml);
+ for (i = 0; i < 3; ++i)
+ {
+ while ((PRIntervalTime)(PR_IntervalNow() - ad[i].timein) < duration) {
+ PR_WaitCondVar(cv, PR_INTERVAL_NO_TIMEOUT);
+ }
+ }
+ PR_Unlock(ml);
+
+ timein = PR_IntervalNow();
+
+ if (debug_mode)
+ printf
+ ("Alarms3 finished at %u, %u, %u\n",
+ ad[0].timein, ad[1].timein, ad[2].timein);
+
+ rv = PR_DestroyAlarm(alarm);
+ if (rv != PR_SUCCESS)
+ {
+ if (!debug_mode) {
+ failed_already=1;
+ }
+ else {
+ printf("***Destroying alarm status: FAIL\n");
+ }
+ }
+ PR_DestroyCondVar(cv);
+ PR_DestroyLock(ml);
+
+ overhead += (duration / 3);
+ overhead += (PR_IntervalNow() - timein);
+
+ return overhead;
+} /* Alarms3 */
+
+static PRUint32 TimeThis(
+ const char *msg, PRUint32 (*func)(PRUint32 loops), PRUint32 loops)
+{
+ PRUint32 overhead, usecs;
+ PRIntervalTime predicted, timein, timeout, ticks;
+
+ if (debug_mode) {
+ printf("Testing %s ...", msg);
+ }
+
+ timein = PR_IntervalNow();
+ predicted = func(loops);
+ timeout = PR_IntervalNow();
+
+ if (debug_mode) {
+ printf(" done\n");
+ }
+
+ ticks = timeout - timein;
+ usecs = PR_IntervalToMicroseconds(ticks);
+ overhead = PR_IntervalToMicroseconds(predicted);
+
+ if(ticks < predicted)
+ {
+ if (debug_mode) {
+ printf("\tFinished in negative time\n");
+ printf("\tpredicted overhead was %d usecs\n", overhead);
+ printf("\ttest completed in %d usecs\n\n", usecs);
+ }
+ }
+ else
+ {
+ if (debug_mode)
+ printf(
+ "\ttotal: %d usecs\n\toverhead: %d usecs\n\tcost: %6.3f usecs\n\n",
+ usecs, overhead, ((double)(usecs - overhead) / (double)loops));
+ }
+
+ return overhead;
+} /* TimeThis */
+
+int prmain(int argc, char** argv)
+{
+ PRUint32 cpu, cpus = 0, loops = 0;
+
+ /* The command line argument: -d is used to determine if the test is being run
+ in debug mode. The regress tool requires only one line output:PASS or FAIL.
+ All of the printfs associated with this test has been handled with a if (debug_mode)
+ test.
+ Usage: test_name [-d]
+ */
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "Gdl:c:");
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) {
+ continue;
+ }
+ switch (opt->option)
+ {
+ case 'G': /* GLOBAL threads */
+ thread_scope = PR_GLOBAL_THREAD;
+ break;
+ case 'd': /* debug mode */
+ debug_mode = 1;
+ break;
+ case 'l': /* loop count */
+ loops = atoi(opt->value);
+ break;
+ case 'c': /* concurrency limit */
+ cpus = atoi(opt->value);
+ break;
+ default:
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+
+ if (cpus == 0) {
+ cpus = 1;
+ }
+ if (loops == 0) {
+ loops = 4;
+ }
+
+ if (debug_mode) {
+ printf("Alarm: Using %d loops\n", loops);
+ }
+
+ if (debug_mode) {
+ printf("Alarm: Using %d cpu(s)\n", cpus);
+ }
+
+ for (cpu = 1; cpu <= cpus; ++cpu)
+ {
+ if (debug_mode) {
+ printf("\nAlarm: Using %d CPU(s)\n", cpu);
+ }
+
+ PR_SetConcurrency(cpu);
+
+ /* some basic time test */
+ (void)TimeThis("ConditionNotify", ConditionNotify, loops);
+ (void)TimeThis("ConditionTimeout", ConditionTimeout, loops);
+ (void)TimeThis("Alarms1", Alarms1, loops);
+ (void)TimeThis("Alarms2", Alarms2, loops);
+ (void)TimeThis("Alarms3", Alarms3, loops);
+ }
+ return 0;
+}
+
+int main(int argc, char** argv)
+{
+ PR_Initialize(prmain, argc, argv, 0);
+ PR_STDIO_INIT();
+ if (failed_already) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+
+} /* main */
+
+
+/* alarmtst.c */