home *** CD-ROM | disk | FTP | other *** search
/ Media Share 9 / MEDIASHARE_09.ISO / hamradio / s920603.zip / TIMER.C < prev    next >
C/C++ Source or Header  |  1992-05-13  |  6KB  |  262 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.     void (**vf)();
  31.     int i_state;
  32.     int tmp;
  33.  
  34.     for(;;){
  35.         /* Atomic read and decrement of Tick */
  36.         for(;;){
  37.             i_state = dirps();
  38.             tmp = Tick;
  39.             if(tmp != 0){
  40.                 Tick--;
  41.                 restore(i_state);
  42.                 break;
  43.             }    
  44.             restore(i_state);
  45.             pwait(&Tick);
  46.         }
  47.         if(!istate()){
  48.             restore(1);
  49.             printf("timer: ints were off!\n");
  50.         }
  51.  
  52.         /* Call the functions listed in config.c */
  53.         for(vf = Cfunc;*vf != NULL;vf++)
  54.             (*vf)();
  55.  
  56.         pwait(NULL);    /* Let them all do their writes */
  57.  
  58.         if(Timers == NULLTIMER)
  59.             continue;    /* No active timers, all done */
  60.  
  61.         /* Initialize null expired timer list */
  62.         expired = NULLTIMER;
  63.  
  64.         /* Move expired timers to expired list. Note use of
  65.          * subtraction and comparison to zero rather than the
  66.          * more obvious simple comparison; this avoids
  67.          * problems when the clock count wraps around.
  68.          */
  69.         while(Timers != NULLTIMER && (Clock - Timers->expiration) >= 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;
  102.     struct timer *tprev = NULLTIMER;
  103.  
  104.     if(t == NULLTIMER)
  105.         return;
  106.     if(t->state == TIMER_RUN)
  107.         stop_timer(t);
  108.     if(t->duration == 0)
  109.         return;        /* A duration value of 0 disables the timer */
  110.  
  111.     t->expiration = Clock + t->duration;
  112.     t->state = TIMER_RUN;
  113.  
  114.     /* Find right place on list for this guy. Once again, note use
  115.      * of subtraction and comparison with zero rather than direct
  116.      * comparison of expiration times.
  117.      */
  118.     for(tnext = Timers;tnext != NULLTIMER;tprev=tnext,tnext = tnext->next){
  119.         if((tnext->expiration - t->expiration) >= 0)
  120.             break;
  121.     }
  122.     /* At this point, tprev points to the entry that should go right
  123.      * before us, and tnext points to the entry just after us. Either or
  124.      * both may be null.
  125.      */
  126.     if(tprev == NULLTIMER)
  127.         Timers = t;        /* Put at beginning */
  128.     else
  129.         tprev->next = t;
  130.  
  131.     t->next = tnext;
  132. }
  133. /* Stop a timer */
  134. void
  135. stop_timer(timer)
  136. struct timer *timer;
  137. {
  138.     register struct timer *t;
  139.     struct timer *tlast = NULLTIMER;
  140.  
  141.     if(timer == NULLTIMER || timer->state != TIMER_RUN)
  142.         return;
  143.  
  144.     /* Verify that timer is really on list */
  145.     for(t = Timers;t != NULLTIMER;tlast = t,t = t->next)
  146.         if(t == timer)
  147.             break;
  148.  
  149.     if(t == NULLTIMER)
  150.         return;        /* Should probably panic here */
  151.  
  152.     /* Delete from active timer list */
  153.     if(tlast != NULLTIMER)
  154.         tlast->next = t->next;
  155.     else
  156.         Timers = t->next;    /* Was first on list */
  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.     int32 remaining;
  166.  
  167.     if(t == NULLTIMER || t->state != TIMER_RUN)
  168.         return 0;
  169.     remaining = t->expiration - Clock;
  170.     if(remaining <= 0)
  171.         return 0;    /* Already expired */
  172.     else
  173.         return remaining * MSPTICK;
  174. }
  175. void
  176. set_timer(t,interval)
  177. struct timer *t;
  178. int32 interval;
  179. {
  180.     if(t == NULLTIMER)
  181.         return;
  182.     /* Round the interval up to the next full tick, and then
  183.      * add another tick to guarantee that the timeout will not
  184.      * occur before the interval is up. This is necessary because
  185.      * we're asynchronous with the system clock.
  186.      */    
  187.     if(interval != 0)
  188.         t->duration = 1 + (interval + MSPTICK - 1)/MSPTICK;
  189.     else
  190.         t->duration = 0;
  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[17],*cp;
  236.     unsigned int days,hrs,mins,secs;
  237.     int minus;
  238.  
  239.     if(t < 0){
  240.         t = -t;
  241.         minus = 1;
  242.     } else
  243.         minus = 0;
  244.  
  245.     secs = t % 60;
  246.     t /= 60;
  247.     mins = t % 60;
  248.     t /= 60;
  249.     hrs = t % 24;
  250.     t /= 24;
  251.     days = t;
  252.     if(minus){
  253.         cp = buf+1;
  254.         buf[0] = '-';
  255.     } else
  256.         cp = buf;
  257.     sprintf(cp,"%u:%02u:%02u:%02u",days,hrs,mins,secs);
  258.     
  259.     return buf;
  260. }
  261.     
  262.