home *** CD-ROM | disk | FTP | other *** search
/ The Pier Shareware 6 / The_Pier_Shareware_Number_6_(The_Pier_Exchange)_(1995).iso / 024 / psi110g.zip / TIMER.C < prev    next >
C/C++ Source or Header  |  1994-04-17  |  6KB  |  243 lines

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