home *** CD-ROM | disk | FTP | other *** search
/ HAM Radio 1 / HamRadio.cdr / misc / tcpipsrc / timer.c < prev    next >
C/C++ Source or Header  |  1991-01-26  |  6KB  |  249 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 interval;
  16.  * i.e., the first timer to expire is always at the head of the list.
  17.  * For performance reasons, the intervals are incremental, so that only
  18.  * the first entry needs to be decremented on each tick. Hence there are
  19.  * special routines for reading the number of ticks remaining on a
  20.  * running timer; you can't just look at the field directly.
  21.  */
  22. static struct timer *Timers;
  23.  
  24. /* This variable keeps a running count of ticks since program startup */
  25. int32 Clock;
  26.  
  27. static void t_alarm(void *x);
  28.  
  29. /* Process that handles clock ticks */
  30. void
  31. timerproc(i,v1,v2)
  32. int i;
  33. void *v1,*v2;
  34. {
  35.     register struct timer *t;
  36.     register struct timer *expired;
  37.     char i_state;
  38.  
  39.     for(;;){
  40.         i_state = dirps();    /* Tick is modified by an interrupt */
  41.         while(Tick == 0)
  42.             pwait(&Tick);
  43.         Tick--;
  44.         restore(i_state);
  45.  
  46.         if(!istate()){
  47.             printf("timer: ints were off!\n");
  48.             restore(1);
  49.         }
  50.         refiq();    /* Replenish interrupt pool */
  51.         systick();    /* Machine-dependent per-tick stuff */
  52.         tflush();    /* Flush current session output */
  53.         pwait(NULL);    /* Let them all do their writes */
  54.         rflush();    /* Flush out buffered console stuff */
  55.         fflush(stdout);    /* And flush out stdout too */
  56.  
  57.         if(Timers == NULLTIMER)
  58.             continue;    /* Nothing to do on this tick */
  59.  
  60.         /* Decrement the first timer. If it expires,
  61.          * take it off the running list and put it
  62.          * on a singly linked list of expired timers
  63.          */
  64.         Timers->count--;
  65.  
  66.         /* Initialize null expired timer list */
  67.         expired = NULLTIMER;
  68.  
  69.         while(Timers != NULLTIMER && Timers->count <= 0){
  70.             if(Timers->next == Timers){
  71.                 printf("PANIC: Timer loop at %lx\n",
  72.                  (long)Timers);
  73.                 iostop();
  74.                 exit(1);
  75.             }
  76.             /* Save Timers since stop_timer will change it */
  77.             t = Timers;
  78.             stop_timer(t);
  79.             t->state = TIMER_EXPIRE;
  80.             /* Add to expired timer list */
  81.             t->next = expired;
  82.             expired = t;
  83.         }
  84.         /* Now go through the list of expired timers, removing each
  85.          * one and kicking the notify function, if there is one
  86.          */
  87.         while((t = expired) != NULLTIMER){
  88.             expired = t->next;
  89.             if(t->func){
  90.                 (*t->func)(t->arg);
  91.             }
  92.         }
  93.         pwait(NULL);    /* Let them run before handling more ticks */
  94.     }
  95. }
  96. /* Start a timer */
  97. void
  98. start_timer(t)
  99. struct timer *t;
  100. {
  101.     register struct timer *tnext,*tprev;
  102.     int32 tot;
  103.  
  104.     if(t == NULLTIMER)
  105.         return;
  106.     if(t->state == TIMER_RUN)
  107.         stop_timer(t);
  108.     if(t->start == 0)
  109.         return;        /* A start value of 0 disables the timer */
  110.  
  111.     t->state = TIMER_RUN;
  112.     /* Find right place on list for this guy */
  113.     tot = 0;
  114.     tprev = NULLTIMER;
  115.     for(tnext = Timers;tnext != NULLTIMER;tnext = tprev->next){
  116.         if(tnext->count + tot > t->start)
  117.             break;
  118.         tprev = tnext;
  119.         tot += tnext->count;
  120.     }
  121.     /* At this point, tprev points to the entry that should go right
  122.      * before us, and tnext points to the entry just after us. Either or
  123.      * both may be null.
  124.      */
  125.     t->count = t->start - tot;    /* Adjust for entries before us */
  126.     if((t->prev = tprev) == NULLTIMER)
  127.         Timers = t;        /* Put at beginning */
  128.     else
  129.         tprev->next = t;
  130.  
  131.     if((t->next = tnext) != NULLTIMER){
  132.         tnext->prev = t;
  133.         /* Adjust the following entry's count */
  134.         tnext->count -= t->count;
  135.     }
  136. }
  137. /* Stop a timer */
  138. void
  139. stop_timer(t)
  140. register struct timer *t;
  141. {
  142.     register struct timer *tp;
  143.  
  144.     if(t == NULLTIMER)
  145.         return;
  146.     if(t->state == TIMER_RUN){
  147.         /* Delete from active timer list */
  148.         if(t->next != NULLTIMER)
  149.             t->next->prev = t->prev;
  150.         if(t->prev != NULLTIMER)
  151.             t->prev->next = t->next;
  152.         else
  153.             Timers = t->next;
  154.         /* Adjust count for the next timer */
  155.         if((tp = t->next) != NULLTIMER)
  156.             tp->count += t->count;
  157.     }
  158.     t->state = TIMER_STOP;
  159. }
  160. /* Return milliseconds remaining on this timer */
  161. int32
  162. read_timer(t)
  163. struct timer *t;
  164. {
  165.     register struct timer *tp;
  166.     int32 tot;
  167.  
  168.     if(t == NULLTIMER || t->state != TIMER_RUN)
  169.         return 0;
  170.  
  171.     tot = 0;
  172.     for(tp = Timers;tp != NULLTIMER; tp = tp->next){
  173.         tot += tp->count;
  174.         if(tp == t)
  175.             break;
  176.     }
  177.     return tot * MSPTICK;
  178. }
  179. void
  180. set_timer(t,interval)
  181. struct timer *t;
  182. int32 interval;
  183. {
  184.     if(t == NULLTIMER)
  185.         return;
  186.     /* Round up small nonzero intervals to one tick */
  187.     if(interval > 0 && interval < MSPTICK)
  188.         t->start = 1;
  189.     else
  190.         t->start = interval/MSPTICK;
  191. }
  192. /* Delay process for specified number of milliseconds.
  193.  * Normally returns 0; returns -1 if aborted by alarm.
  194.  */
  195. int
  196. pause(ms)
  197. int32 ms;
  198. {
  199.     int val;
  200.  
  201.     if(Curproc == NULLPROC || ms == 0)
  202.         return 0;
  203.     alarm(ms);
  204.     /* The actual event doesn't matter, since we'll be alerted */
  205.     while(Curproc->alarm.state == TIMER_RUN){
  206.         if((val = pwait(Curproc)) != 0)
  207.             break;
  208.     }
  209.     alarm(0L); /* Make sure it's stopped, in case we were killed */    
  210.     return (val == EALARM) ? 0 : -1;
  211. }
  212. static void
  213. t_alarm(x)
  214. void *x;
  215. {
  216.     alert((struct proc *)x,EALARM);
  217. }
  218. /* Send signal to current process after specified number of milliseconds */
  219. void
  220. alarm(ms)
  221. int32 ms;
  222. {
  223.     if(Curproc != NULLPROC){
  224.         set_timer(&Curproc->alarm,ms);
  225.         Curproc->alarm.func = t_alarm;
  226.         Curproc->alarm.arg = (char *)Curproc;
  227.         start_timer(&Curproc->alarm);
  228.     }
  229. }
  230. /* Convert time count in seconds to printable days:hr:min:sec format */
  231. char *
  232. tformat(t)
  233. int32 t;
  234. {
  235.     static char buf[16];
  236.     unsigned int days,hrs,mins,secs;
  237.  
  238.     secs = t % 60;
  239.     t /= 60;
  240.     mins = t % 60;
  241.     t /= 60;
  242.     hrs = t % 24;
  243.     t /= 24;
  244.     days = t;
  245.     sprintf(buf,"%u:%02u:%02u:%02u",days,hrs,mins,secs);
  246.     return buf;
  247. }
  248.     
  249.