tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

alarm.c (12770B)


      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 /***********************************************************************
      7 **  1996 - Netscape Communications Corporation
      8 **
      9 ** Name: alarmtst.c
     10 **
     11 ** Description: Test alarms
     12 **
     13 ** Modification History:
     14 ** 13-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
     15 **           The debug mode will print all of the printfs associated with this
     16 *test.
     17 **           The regress mode will be the default mode. Since the regress tool
     18 *limits
     19 **           the output to a one line status:PASS or FAIL,all of the printf
     20 *statements
     21 **           have been handled with an if (debug_mode) statement.
     22 ** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been
     23 *updated to
     24 **          recognize the return code from tha main program.
     25 ***********************************************************************/
     26 
     27 /***********************************************************************
     28 ** Includes
     29 ***********************************************************************/
     30 
     31 #include "prlog.h"
     32 #include "prinit.h"
     33 #include "obsolete/pralarm.h"
     34 #include "prlock.h"
     35 #include "prlong.h"
     36 #include "prcvar.h"
     37 #include "prinrval.h"
     38 #include "prtime.h"
     39 
     40 /* Used to get the command line option */
     41 #include "plgetopt.h"
     42 #include <stdio.h>
     43 #include <stdlib.h>
     44 
     45 #if defined(XP_UNIX)
     46 #  include <sys/time.h>
     47 #endif
     48 
     49 static PRIntn debug_mode;
     50 static PRIntn failed_already = 0;
     51 static PRThreadScope thread_scope = PR_LOCAL_THREAD;
     52 
     53 typedef struct notifyData {
     54  PRLock* ml;
     55  PRCondVar* child;
     56  PRCondVar* parent;
     57  PRBool pending;
     58  PRUint32 counter;
     59 } NotifyData;
     60 
     61 static void Notifier(void* arg) {
     62  NotifyData* notifyData = (NotifyData*)arg;
     63  PR_Lock(notifyData->ml);
     64  while (notifyData->counter > 0) {
     65    while (!notifyData->pending) {
     66      PR_WaitCondVar(notifyData->child, PR_INTERVAL_NO_TIMEOUT);
     67    }
     68    notifyData->counter -= 1;
     69    notifyData->pending = PR_FALSE;
     70    PR_NotifyCondVar(notifyData->parent);
     71  }
     72  PR_Unlock(notifyData->ml);
     73 } /* Notifier */
     74 /***********************************************************************
     75 ** PRIVATE FUNCTION:    ConditionNotify
     76 ** DESCRIPTION:
     77 **
     78 ** INPUTS:      loops
     79 ** OUTPUTS:     None
     80 ** RETURN:      overhead
     81 ** SIDE EFFECTS:
     82 **
     83 ** RESTRICTIONS:
     84 **      None
     85 ** MEMORY:      NA
     86 ** ALGORITHM:
     87 **
     88 ***********************************************************************/
     89 
     90 static PRIntervalTime ConditionNotify(PRUint32 loops) {
     91  PRThread* thread;
     92  NotifyData notifyData;
     93  PRIntervalTime timein, overhead;
     94 
     95  timein = PR_IntervalNow();
     96 
     97  notifyData.counter = loops;
     98  notifyData.ml = PR_NewLock();
     99  notifyData.child = PR_NewCondVar(notifyData.ml);
    100  notifyData.parent = PR_NewCondVar(notifyData.ml);
    101  thread = PR_CreateThread(PR_USER_THREAD, Notifier, &notifyData,
    102                           PR_GetThreadPriority(PR_GetCurrentThread()),
    103                           thread_scope, PR_JOINABLE_THREAD, 0);
    104 
    105  overhead = PR_IntervalNow() - timein; /* elapsed so far */
    106 
    107  PR_Lock(notifyData.ml);
    108  while (notifyData.counter > 0) {
    109    notifyData.pending = PR_TRUE;
    110    PR_NotifyCondVar(notifyData.child);
    111    while (notifyData.pending) {
    112      PR_WaitCondVar(notifyData.parent, PR_INTERVAL_NO_TIMEOUT);
    113    }
    114  }
    115  PR_Unlock(notifyData.ml);
    116 
    117  timein = PR_IntervalNow();
    118 
    119  (void)PR_JoinThread(thread);
    120  PR_DestroyCondVar(notifyData.child);
    121  PR_DestroyCondVar(notifyData.parent);
    122  PR_DestroyLock(notifyData.ml);
    123 
    124  overhead += (PR_IntervalNow() - timein); /* more overhead */
    125 
    126  return overhead;
    127 } /* ConditionNotify */
    128 
    129 static PRIntervalTime ConditionTimeout(PRUint32 loops) {
    130  PRUintn count;
    131  PRIntervalTime overhead, timein = PR_IntervalNow();
    132 
    133  PRLock* ml = PR_NewLock();
    134  PRCondVar* cv = PR_NewCondVar(ml);
    135  PRIntervalTime interval = PR_MillisecondsToInterval(50);
    136 
    137  overhead = PR_IntervalNow() - timein;
    138 
    139  PR_Lock(ml);
    140  for (count = 0; count < loops; ++count) {
    141    overhead += interval;
    142    PR_ASSERT(PR_WaitCondVar(cv, interval) == PR_SUCCESS);
    143  }
    144  PR_Unlock(ml);
    145 
    146  timein = PR_IntervalNow();
    147  PR_DestroyCondVar(cv);
    148  PR_DestroyLock(ml);
    149  overhead += (PR_IntervalNow() - timein);
    150 
    151  return overhead;
    152 } /* ConditionTimeout */
    153 
    154 typedef struct AlarmData {
    155  PRLock* ml;
    156  PRCondVar* cv;
    157  PRUint32 rate, late, times;
    158  PRIntervalTime duration, timein, period;
    159 } AlarmData;
    160 
    161 static PRBool AlarmFn1(PRAlarmID* id, void* clientData, PRUint32 late) {
    162  PRStatus rv = PR_SUCCESS;
    163  PRBool keepGoing, resetAlarm;
    164  PRIntervalTime interval, now = PR_IntervalNow();
    165  AlarmData* ad = (AlarmData*)clientData;
    166 
    167  PR_Lock(ad->ml);
    168  ad->late += late;
    169  ad->times += 1;
    170  keepGoing =
    171      ((PRIntervalTime)(now - ad->timein) < ad->duration) ? PR_TRUE : PR_FALSE;
    172  if (!keepGoing) {
    173    rv = PR_NotifyCondVar(ad->cv);
    174  }
    175  resetAlarm = ((ad->times % 31) == 0) ? PR_TRUE : PR_FALSE;
    176 
    177  interval = (ad->period + ad->rate - 1) / ad->rate;
    178  if (!late && (interval > 10)) {
    179    interval &= (now & 0x03) + 1;
    180    PR_WaitCondVar(ad->cv, interval);
    181  }
    182 
    183  PR_Unlock(ad->ml);
    184 
    185  if (rv != PR_SUCCESS) {
    186    if (!debug_mode) {
    187      failed_already = 1;
    188    } else {
    189      printf("AlarmFn: notify status: FAIL\n");
    190    }
    191  }
    192 
    193  if (resetAlarm) {
    194    ad->rate += 3;
    195    ad->late = ad->times = 0;
    196    if (PR_ResetAlarm(id, ad->period, ad->rate) != PR_SUCCESS) {
    197      if (!debug_mode) {
    198        failed_already = 1;
    199      } else {
    200        printf("AlarmFn: Resetting alarm status: FAIL\n");
    201      }
    202 
    203      keepGoing = PR_FALSE;
    204    }
    205  }
    206 
    207  return keepGoing;
    208 } /* AlarmFn1 */
    209 
    210 static PRIntervalTime Alarms1(PRUint32 loops) {
    211  PRAlarm* alarm;
    212  AlarmData ad;
    213  PRIntervalTime overhead, timein = PR_IntervalNow();
    214  PRIntervalTime duration = PR_SecondsToInterval(3);
    215 
    216  PRLock* ml = PR_NewLock();
    217  PRCondVar* cv = PR_NewCondVar(ml);
    218 
    219  ad.ml = ml;
    220  ad.cv = cv;
    221  ad.rate = 1;
    222  ad.times = loops;
    223  ad.late = ad.times = 0;
    224  ad.duration = duration;
    225  ad.timein = PR_IntervalNow();
    226  ad.period = PR_SecondsToInterval(1);
    227 
    228  alarm = PR_CreateAlarm();
    229 
    230  (void)PR_SetAlarm(alarm, ad.period, ad.rate, AlarmFn1, &ad);
    231 
    232  overhead = PR_IntervalNow() - timein;
    233 
    234  PR_Lock(ml);
    235  while ((PRIntervalTime)(PR_IntervalNow() - ad.timein) < duration) {
    236    PR_WaitCondVar(cv, PR_INTERVAL_NO_TIMEOUT);
    237  }
    238  PR_Unlock(ml);
    239 
    240  timein = PR_IntervalNow();
    241  (void)PR_DestroyAlarm(alarm);
    242  PR_DestroyCondVar(cv);
    243  PR_DestroyLock(ml);
    244  overhead += (PR_IntervalNow() - timein);
    245 
    246  return duration + overhead;
    247 } /* Alarms1 */
    248 
    249 static PRBool AlarmFn2(PRAlarmID* id, void* clientData, PRUint32 late) {
    250  PRBool keepGoing;
    251  PRStatus rv = PR_SUCCESS;
    252  AlarmData* ad = (AlarmData*)clientData;
    253  PRIntervalTime interval, now = PR_IntervalNow();
    254 
    255  PR_Lock(ad->ml);
    256  ad->times += 1;
    257  keepGoing =
    258      ((PRIntervalTime)(now - ad->timein) < ad->duration) ? PR_TRUE : PR_FALSE;
    259  interval = (ad->period + ad->rate - 1) / ad->rate;
    260 
    261  if (!late && (interval > 10)) {
    262    interval &= (now & 0x03) + 1;
    263    PR_WaitCondVar(ad->cv, interval);
    264  }
    265 
    266  if (!keepGoing) {
    267    rv = PR_NotifyCondVar(ad->cv);
    268  }
    269 
    270  PR_Unlock(ad->ml);
    271 
    272  if (rv != PR_SUCCESS) {
    273    failed_already = 1;
    274  };
    275 
    276  return keepGoing;
    277 } /* AlarmFn2 */
    278 
    279 static PRIntervalTime Alarms2(PRUint32 loops) {
    280  PRStatus rv;
    281  PRAlarm* alarm;
    282  PRIntervalTime overhead, timein = PR_IntervalNow();
    283  AlarmData ad;
    284  PRIntervalTime duration = PR_SecondsToInterval(30);
    285 
    286  PRLock* ml = PR_NewLock();
    287  PRCondVar* cv = PR_NewCondVar(ml);
    288 
    289  ad.ml = ml;
    290  ad.cv = cv;
    291  ad.rate = 1;
    292  ad.times = loops;
    293  ad.late = ad.times = 0;
    294  ad.duration = duration;
    295  ad.timein = PR_IntervalNow();
    296  ad.period = PR_SecondsToInterval(1);
    297 
    298  alarm = PR_CreateAlarm();
    299 
    300  (void)PR_SetAlarm(alarm, ad.period, ad.rate, AlarmFn2, &ad);
    301 
    302  overhead = PR_IntervalNow() - timein;
    303 
    304  PR_Lock(ml);
    305  while ((PRIntervalTime)(PR_IntervalNow() - ad.timein) < duration) {
    306    PR_WaitCondVar(cv, PR_INTERVAL_NO_TIMEOUT);
    307  }
    308  PR_Unlock(ml);
    309 
    310  timein = PR_IntervalNow();
    311 
    312  rv = PR_DestroyAlarm(alarm);
    313  if (rv != PR_SUCCESS) {
    314    if (!debug_mode) {
    315      failed_already = 1;
    316    } else {
    317      printf("***Destroying alarm status: FAIL\n");
    318    }
    319  }
    320 
    321  PR_DestroyCondVar(cv);
    322  PR_DestroyLock(ml);
    323 
    324  overhead += (PR_IntervalNow() - timein);
    325 
    326  return duration + overhead;
    327 } /* Alarms2 */
    328 
    329 static PRIntervalTime Alarms3(PRUint32 loops) {
    330  PRIntn i;
    331  PRStatus rv;
    332  PRAlarm* alarm;
    333  AlarmData ad[3];
    334  PRIntervalTime duration = PR_SecondsToInterval(30);
    335  PRIntervalTime overhead, timein = PR_IntervalNow();
    336 
    337  PRLock* ml = PR_NewLock();
    338  PRCondVar* cv = PR_NewCondVar(ml);
    339 
    340  for (i = 0; i < 3; ++i) {
    341    ad[i].ml = ml;
    342    ad[i].cv = cv;
    343    ad[i].rate = 1;
    344    ad[i].times = loops;
    345    ad[i].duration = duration;
    346    ad[i].late = ad[i].times = 0;
    347    ad[i].timein = PR_IntervalNow();
    348    ad[i].period = PR_SecondsToInterval(1);
    349 
    350    /* more loops, faster rate => same elapsed time */
    351    ad[i].times = (i + 1) * loops;
    352    ad[i].rate = (i + 1) * 10;
    353  }
    354 
    355  alarm = PR_CreateAlarm();
    356 
    357  for (i = 0; i < 3; ++i) {
    358    (void)PR_SetAlarm(alarm, ad[i].period, ad[i].rate, AlarmFn2, &ad[i]);
    359  }
    360 
    361  overhead = PR_IntervalNow() - timein;
    362 
    363  PR_Lock(ml);
    364  for (i = 0; i < 3; ++i) {
    365    while ((PRIntervalTime)(PR_IntervalNow() - ad[i].timein) < duration) {
    366      PR_WaitCondVar(cv, PR_INTERVAL_NO_TIMEOUT);
    367    }
    368  }
    369  PR_Unlock(ml);
    370 
    371  timein = PR_IntervalNow();
    372 
    373  if (debug_mode)
    374    printf("Alarms3 finished at %u, %u, %u\n", ad[0].timein, ad[1].timein,
    375           ad[2].timein);
    376 
    377  rv = PR_DestroyAlarm(alarm);
    378  if (rv != PR_SUCCESS) {
    379    if (!debug_mode) {
    380      failed_already = 1;
    381    } else {
    382      printf("***Destroying alarm status: FAIL\n");
    383    }
    384  }
    385  PR_DestroyCondVar(cv);
    386  PR_DestroyLock(ml);
    387 
    388  overhead += (duration / 3);
    389  overhead += (PR_IntervalNow() - timein);
    390 
    391  return overhead;
    392 } /* Alarms3 */
    393 
    394 static PRUint32 TimeThis(const char* msg, PRUint32 (*func)(PRUint32 loops),
    395                         PRUint32 loops) {
    396  PRUint32 overhead, usecs;
    397  PRIntervalTime predicted, timein, timeout, ticks;
    398 
    399  if (debug_mode) {
    400    printf("Testing %s ...", msg);
    401  }
    402 
    403  timein = PR_IntervalNow();
    404  predicted = func(loops);
    405  timeout = PR_IntervalNow();
    406 
    407  if (debug_mode) {
    408    printf(" done\n");
    409  }
    410 
    411  ticks = timeout - timein;
    412  usecs = PR_IntervalToMicroseconds(ticks);
    413  overhead = PR_IntervalToMicroseconds(predicted);
    414 
    415  if (ticks < predicted) {
    416    if (debug_mode) {
    417      printf("\tFinished in negative time\n");
    418      printf("\tpredicted overhead was %d usecs\n", overhead);
    419      printf("\ttest completed in %d usecs\n\n", usecs);
    420    }
    421  } else {
    422    if (debug_mode)
    423      printf("\ttotal: %d usecs\n\toverhead: %d usecs\n\tcost: %6.3f usecs\n\n",
    424             usecs, overhead, ((double)(usecs - overhead) / (double)loops));
    425  }
    426 
    427  return overhead;
    428 } /* TimeThis */
    429 
    430 int prmain(int argc, char** argv) {
    431  PRUint32 cpu, cpus = 0, loops = 0;
    432 
    433  /* The command line argument: -d is used to determine if the test is being run
    434  in debug mode. The regress tool requires only one line output:PASS or FAIL.
    435  All of the printfs associated with this test has been handled with a if
    436  (debug_mode) test. Usage: test_name [-d]
    437  */
    438  PLOptStatus os;
    439  PLOptState* opt = PL_CreateOptState(argc, argv, "Gdl:c:");
    440  while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) {
    441    if (PL_OPT_BAD == os) {
    442      continue;
    443    }
    444    switch (opt->option) {
    445      case 'G': /* GLOBAL threads */
    446        thread_scope = PR_GLOBAL_THREAD;
    447        break;
    448      case 'd': /* debug mode */
    449        debug_mode = 1;
    450        break;
    451      case 'l': /* loop count */
    452        loops = atoi(opt->value);
    453        break;
    454      case 'c': /* concurrency limit */
    455        cpus = atoi(opt->value);
    456        break;
    457      default:
    458        break;
    459    }
    460  }
    461  PL_DestroyOptState(opt);
    462 
    463  if (cpus == 0) {
    464    cpus = 1;
    465  }
    466  if (loops == 0) {
    467    loops = 4;
    468  }
    469 
    470  if (debug_mode) {
    471    printf("Alarm: Using %d loops\n", loops);
    472  }
    473 
    474  if (debug_mode) {
    475    printf("Alarm: Using %d cpu(s)\n", cpus);
    476  }
    477 
    478  for (cpu = 1; cpu <= cpus; ++cpu) {
    479    if (debug_mode) {
    480      printf("\nAlarm: Using %d CPU(s)\n", cpu);
    481    }
    482 
    483    PR_SetConcurrency(cpu);
    484 
    485    /* some basic time test */
    486    (void)TimeThis("ConditionNotify", ConditionNotify, loops);
    487    (void)TimeThis("ConditionTimeout", ConditionTimeout, loops);
    488    (void)TimeThis("Alarms1", Alarms1, loops);
    489    (void)TimeThis("Alarms2", Alarms2, loops);
    490    (void)TimeThis("Alarms3", Alarms3, loops);
    491  }
    492  return 0;
    493 }
    494 
    495 int main(int argc, char** argv) {
    496  PR_Initialize(prmain, argc, argv, 0);
    497  if (failed_already) {
    498    return 1;
    499  } else {
    500    return 0;
    501  }
    502 
    503 } /* main */
    504 
    505 /* alarmtst.c */