home *** CD-ROM | disk | FTP | other *** search
/ HAM Radio 3 / hamradioversion3.0examsandprograms1992.iso / misc / 9q920411 / timer.c < prev    next >
C/C++ Source or Header  |  1991-12-18  |  6KB  |  258 lines

  1. /* General purpose software timer facilities
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4. #include <stdio.h>
  5. #include "global.h"
  6. #include "timer.h"
  7. #include "proc.h"
  8. #include "mbuf.h"
  9. #include "commands.h"
  10. #include "daemon.h"
  11. #include "hardware.h"
  12. #include "socket.h"
  13.  
  14. /* Head of running timer chain.
  15.  * The list of running timers is sorted in increasing order of expiration;
  16.  * i.e., the first timer to expire is always at the head of the list.
  17.  */
  18. static struct timer *Timers;
  19.  
  20. static void t_alarm __ARGS((void *x));
  21.  
  22. /* Process that handles clock ticks */
  23. void
  24. timerproc(i,v1,v2)
  25. int i;
  26. void *v1,*v2;
  27. {
  28.     register struct timer *t;
  29.     register struct timer *expired;
  30.     char i_state;
  31.     void (**vf)();
  32.  
  33.     for(;;){
  34.         i_state = dirps();    /* Tick is modified by an interrupt */
  35.         while(Tick == 0)
  36.             pwait(&Tick);
  37.         Tick = 0;
  38.         restore(i_state);
  39.  
  40.         if(!istate()){
  41.             restore(1);
  42.             printf("timer: ints were off!\n");
  43.         }
  44.  
  45.         /* Call the functions listed in config.c */
  46.         for(vf = Cfunc;*vf != NULL;vf++)
  47.             (*vf)();
  48.  
  49.         tflush();    /* Flush current session output */
  50.         pwait(NULL);    /* Let them all do their writes */
  51.         rflush();    /* Flush out buffered console stuff */
  52.         fflush(stdout);    /* And flush out stdout too */
  53.  
  54.         if(Timers == NULLTIMER)
  55.             continue;    /* No active timers, all done */
  56.  
  57.         /* Initialize null expired timer list */
  58.         expired = NULLTIMER;
  59.  
  60.         /* Move expired timers to expired list. Note use of
  61.          * subtraction and comparison to zero rather than the
  62.          * more obvious simple comparison; this avoids
  63.          * problems when the clock count wraps around.
  64.          */
  65.         while(Timers != NULLTIMER && (Clock - Timers->expiration) >= 0){
  66.             if(Timers->next == Timers){
  67.                 printf("PANIC: Timer loop at %lx\n",
  68.                  (long)Timers);
  69.                 iostop();
  70.                 exit(1);
  71.             }
  72.             /* Save Timers since stop_timer will change it */
  73.             t = Timers;
  74.             stop_timer(t);
  75.             t->state = TIMER_EXPIRE;
  76.             /* Add to expired timer list */
  77.             t->next = expired;
  78.             expired = t;
  79.         }
  80.         /* Now go through the list of expired timers, removing each
  81.          * one and kicking the notify function, if there is one
  82.          */
  83.         while((t = expired) != NULLTIMER){
  84.             expired = t->next;
  85.             if(t->func){
  86.                 (*t->func)(t->arg);
  87.             }
  88.         }
  89.         pwait(NULL);    /* Let them run before handling more ticks */
  90.     }
  91. }
  92. /* Start a timer */
  93. void
  94. start_timer(t)
  95. struct timer *t;
  96. {
  97.     register struct timer *tnext;
  98.     struct timer *tprev = NULLTIMER;
  99.  
  100.     if(t == NULLTIMER)
  101.         return;
  102.     if(t->state == TIMER_RUN)
  103.         stop_timer(t);
  104.     if(t->duration == 0)
  105.         return;        /* A duration value of 0 disables the timer */
  106.  
  107.     t->expiration = Clock + t->duration;
  108.     t->state = TIMER_RUN;
  109.  
  110.     /* Find right place on list for this guy. Once again, note use
  111.      * of subtraction and comparison with zero rather than direct
  112.      * comparison of expiration times.
  113.      */
  114.     for(tnext = Timers;tnext != NULLTIMER;tprev=tnext,tnext = tnext->next){
  115.         if((tnext->expiration - t->expiration) >= 0)
  116.             break;
  117.     }
  118.     /* At this point, tprev points to the entry that should go right
  119.      * before us, and tnext points to the entry just after us. Either or
  120.      * both may be null.
  121.      */
  122.     if(tprev == NULLTIMER)
  123.         Timers = t;        /* Put at beginning */
  124.     else
  125.         tprev->next = t;
  126.  
  127.     t->next = tnext;
  128. }
  129. /* Stop a timer */
  130. void
  131. stop_timer(timer)
  132. struct timer *timer;
  133. {
  134.     register struct timer *t;
  135.     struct timer *tlast = NULLTIMER;
  136.  
  137.     if(timer == NULLTIMER || timer->state != TIMER_RUN)
  138.         return;
  139.  
  140.     /* Verify that timer is really on list */
  141.     for(t = Timers;t != NULLTIMER;tlast = t,t = t->next)
  142.         if(t == timer)
  143.             break;
  144.  
  145.     if(t == NULLTIMER)
  146.         return;        /* Should probably panic here */
  147.  
  148.     /* Delete from active timer list */
  149.     if(tlast != NULLTIMER)
  150.         tlast->next = t->next;
  151.     else
  152.         Timers = t->next;    /* Was first on list */
  153.  
  154.     t->state = TIMER_STOP;
  155. }
  156. /* Return milliseconds remaining on this timer */
  157. int32
  158. read_timer(t)
  159. struct timer *t;
  160. {
  161.     int32 remaining;
  162.  
  163.     if(t == NULLTIMER || t->state != TIMER_RUN)
  164.         return 0;
  165.     remaining = t->expiration - Clock;
  166.     if(remaining <= 0)
  167.         return 0;    /* Already expired */
  168.     else
  169.         return remaining * MSPTICK;
  170. }
  171. void
  172. set_timer(t,interval)
  173. struct timer *t;
  174. int32 interval;
  175. {
  176.     if(t == NULLTIMER)
  177.         return;
  178.     /* Round the interval up to the next full tick, and then
  179.      * add another tick to guarantee that the timeout will not
  180.      * occur before the interval is up. This is necessary because
  181.      * we're asynchronous with the system clock.
  182.      */    
  183.     if(interval != 0)
  184.         t->duration = 1 + (interval + MSPTICK - 1)/MSPTICK;
  185.     else
  186.         t->duration = 0;
  187. }
  188. /* Delay process for specified number of milliseconds.
  189.  * Normally returns 0; returns -1 if aborted by alarm.
  190.  */
  191. int
  192. pause(ms)
  193. int32 ms;
  194. {
  195.     int val;
  196.  
  197.     if(Curproc == NULLPROC || ms == 0)
  198.         return 0;
  199.     alarm(ms);
  200.     /* The actual event doesn't matter, since we'll be alerted */
  201.     while(Curproc->alarm.state == TIMER_RUN){
  202.         if((val = pwait(Curproc)) != 0)
  203.             break;
  204.     }
  205.     alarm(0L); /* Make sure it's stopped, in case we were killed */    
  206.     return (val == EALARM) ? 0 : -1;
  207. }
  208. static void
  209. t_alarm(x)
  210. void *x;
  211. {
  212.     alert((struct proc *)x,EALARM);
  213. }
  214. /* Send signal to current process after specified number of milliseconds */
  215. void
  216. alarm(ms)
  217. int32 ms;
  218. {
  219.     if(Curproc != NULLPROC){
  220.         set_timer(&Curproc->alarm,ms);
  221.         Curproc->alarm.func = t_alarm;
  222.         Curproc->alarm.arg = (char *)Curproc;
  223.         start_timer(&Curproc->alarm);
  224.     }
  225. }
  226. /* Convert time count in seconds to printable days:hr:min:sec format */
  227. char *
  228. tformat(t)
  229. int32 t;
  230. {
  231.     static char buf[17],*cp;
  232.     unsigned int days,hrs,mins,secs;
  233.     int minus;
  234.  
  235.     if(t < 0){
  236.         t = -t;
  237.         minus = 1;
  238.     } else
  239.         minus = 0;
  240.  
  241.     secs = t % 60;
  242.     t /= 60;
  243.     mins = t % 60;
  244.     t /= 60;
  245.     hrs = t % 24;
  246.     t /= 24;
  247.     days = t;
  248.     if(minus){
  249.         cp = buf+1;
  250.         buf[0] = '-';
  251.     } else
  252.         cp = buf;
  253.     sprintf(cp,"%u:%02u:%02u:%02u",days,hrs,mins,secs);
  254.     
  255.     return buf;
  256. }
  257.     
  258.