home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume25 / pty4 / part05 / timer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-02-18  |  7.6 KB  |  342 lines

  1. /* timer.c, timer.h: timer libraries
  2. Daniel J. Bernstein, brnstnd@nyu.edu.
  3. Depends on sigsched.h, ralloc.h, sod.h.
  4. Requires BSD (interval timers, PROF and VTALRM signals, gettimeofday, etc.).
  5. 7/27/91: Baseline. timer 1.0, public domain.
  6. No known patent problems.
  7.  
  8. All signals defined here are thread-lowered signals.
  9.  
  10. Note that we use timer_clock instead of struct timeval since
  11. timer_clock has at least a prayer of being portable.
  12. This implementation, however, is BSD-only.
  13. */
  14.  
  15. #include <sys/types.h>
  16. #include <sys/time.h>
  17. #include <sys/times.h>
  18. #include <signal.h>
  19. #include "sigsched.h"
  20. #include "sod.h"
  21. #include "timer.h"
  22. #include "ralloc.h"
  23. #ifndef HZ
  24. #define HZ 60 /*XXX*/
  25. #endif
  26.  
  27. int timer_now(t,result)
  28. timer_type t;
  29. timer_clock *result;
  30. {
  31.  struct tms tms;
  32.  struct timeval tv;
  33.  
  34.  switch(t)
  35.   {
  36.    case TIMER_REAL:
  37.      if (gettimeofday(&tv,(struct timezone *) 0) == -1)
  38.        return -1;
  39.      result->sec = tv.tv_sec;
  40.      result->usec = tv.tv_usec;
  41.      break;
  42.    case TIMER_VIRTUAL:
  43.      times(&tms);
  44.      result->sec = tms.tms_utime / HZ;
  45.      result->usec = ((tms.tms_utime % HZ) * 1000000) / HZ;
  46.      break;
  47.    case TIMER_PROF:
  48.      times(&tms);
  49.      result->sec = (tms.tms_utime + tms.tms_stime) / HZ;
  50.      result->usec = (((tms.tms_utime + tms.tms_stime) % HZ) * 1000000) / HZ;
  51.      break;
  52.    default:
  53.      return -1;
  54.   }
  55.  return 0;
  56. }
  57.  
  58. void timer_sum(one,two,result)
  59. timer_clock *one;
  60. timer_clock *two;
  61. timer_clock *result;
  62. {
  63.  result->sec = one->sec + two->sec;
  64.  if ((result->usec = one->usec + two->usec) >= 1000000)
  65.   {
  66.    result->sec += 1;
  67.    result->usec -= 1000000;
  68.   }
  69. }
  70.  
  71. int timer_diff(one,two,result)
  72. timer_clock *one;
  73. timer_clock *two;
  74. timer_clock *result;
  75. {
  76.  if (one->sec > two->sec)
  77.   {
  78.    result->sec = one->sec - two->sec;
  79.    if (one->usec >= two->usec)
  80.      result->usec = one->usec - two->usec;
  81.    else
  82.     { --result->sec; result->usec = 1000000 - (two->usec - one->usec); }
  83.    return 1;
  84.   }
  85.  if (one->sec < two->sec)
  86.   {
  87.    result->sec = two->sec - one->sec;
  88.    if (two->usec >= one->usec)
  89.      result->usec = two->usec - one->usec;
  90.    else
  91.     { --result->sec; result->usec = 1000000 - (one->usec - two->usec); }
  92.    return -1;
  93.   }
  94.  if (one->usec > two->usec)
  95.   {
  96.    result->sec = 0;
  97.    result->usec = one->usec - two->usec;
  98.    return 1;
  99.   }
  100.  if (one->usec < two->usec)
  101.   {
  102.    result->sec = 0;
  103.    result->usec = two->usec - one->usec;
  104.    return 1;
  105.   }
  106.  result->sec = 0;
  107.  result->usec = 0;
  108.  return 0;
  109. }
  110.  
  111. /* Basic idea: For each kind of timer, keep a list of all scheduled */
  112. /* events. Set the interval timers to go off at the first events. */
  113.  
  114. struct kaboom { timer_clock when; ss_thread *t; int flagi; ss_id i; ss_idptr p; int wait; } ;
  115.  
  116. SODdecl(kaboomlist,struct kaboom);
  117.  
  118. /* XXX: should use priority queues here */
  119.  
  120. static int numwait = 0;
  121.  
  122. /* XXX: all these will have to change if TIMER_NUM changes */
  123. static kaboomlist thead[TIMER_NUM] = { 0, 0, 0 };
  124. static int tgoing[TIMER_NUM] = { 0, 0, 0 };
  125. static timer_clock twhen[TIMER_NUM];
  126. static int t2sig[TIMER_NUM] = { SIGALRM, SIGVTALRM, SIGPROF };
  127. static int t2it[TIMER_NUM] = { ITIMER_REAL, ITIMER_VIRTUAL, ITIMER_PROF };
  128.  
  129. static void kaboomcleanup()
  130. {
  131.  kaboomlist newhead;
  132.  kaboomlist k;
  133.  timer_type i;
  134.  
  135.  for (i = 0;i < TIMER_NUM;++i)
  136.   {
  137.    newhead = 0;
  138.    while (thead[i])
  139.     {
  140.      SODpop(thead[i],k);
  141.      if (SODdata(k).t) SODpush(newhead,k); else SODfree(k,rfree);
  142.     }
  143.    thead[i] = newhead;
  144.   }
  145. }
  146.  
  147. static void kaboom(t)
  148. timer_type t;
  149. {
  150.  kaboomlist k;
  151.  timer_clock dummy;
  152.  ss_thread *thread;
  153.  
  154.  ss_unsched(ss_signal(t2sig[t]),kaboom,t);
  155.  tgoing[t] = 0; /* timer's out */
  156.  for (k = thead[t];k;k = SODnext(k))
  157.    if (timer_diff(&(SODdata(k).when),twhen + t,&dummy) <= 0)
  158.     {
  159.      thread = SODdata(k).t; SODdata(k).t = 0;
  160.      if (SODdata(k).wait) --numwait; SODdata(k).wait = 0;
  161.      if (thread)
  162.        if (SODdata(k).flagi)
  163.      thread(SODdata(k).i);
  164.        else
  165.      thread(SODdata(k).p);
  166.      /* k may now be invalid. alternative: ss_schedonce(ss_asap(),...) */
  167.      break; /* important! */
  168.     }
  169.  kaboomcleanup();
  170.  if (kaboomresched(t) == -1)
  171.    ; /* XXXXXX: uh-oh */
  172. }
  173.  
  174. static int set_it(t,when)
  175. timer_type t;
  176. timer_clock *when;
  177. {
  178.  struct itimerval it;
  179.  timer_clock now;
  180.  timer_clock diff;
  181.  
  182.  if (timer_now(t,&now) == -1)
  183.    return -1;
  184.  if (timer_diff(when,&now,&diff) <= 0)
  185.   {
  186.    diff.sec = 0;
  187.    diff.usec = 1;
  188.   }
  189.  it.it_value.tv_sec = diff.sec; it.it_interval.tv_sec = 0;
  190.  it.it_value.tv_usec = diff.usec; it.it_interval.tv_usec = 0;
  191.  if (setitimer(t2it[t],&it,(struct itimerval *) 0) == -1)
  192.    return -1;
  193.  return 0;
  194. }
  195.  
  196. static int kaboomresched(t) /* XXX: implicit-static */
  197. timer_type t;
  198. {
  199.  timer_clock dummy;
  200.  kaboomlist k;
  201.  int resched;
  202.  
  203.  if (thead[t])
  204.   {
  205.    resched = 0;
  206.    for (k = thead[t];k;k = SODnext(k))
  207.      if (SODdata(k).t)
  208.        if (!tgoing[t] || timer_diff(&SODdata(k).when,twhen + t,&dummy) < 0)
  209.     {
  210.      resched = 1;
  211.      twhen[t] = SODdata(k).when; /*XXX: structure copying*/
  212.     }
  213.    if (resched)
  214.     {
  215.      if (tgoing[t])
  216.        ss_unsched(ss_signal(t2sig[t]),kaboom,t);
  217.      tgoing[t] = 1;
  218.      if (ss_schedwait(ss_signal(t2sig[t]),kaboom,t,numwait) == -1)
  219.        return -1; /*XXX*/
  220.      if (set_it(t,twhen + t) == -1)
  221.        return -1; /*XXX*/
  222.     }
  223.   }
  224.  return 0;
  225. }
  226.  
  227. static int timer_sched(x,t,flagi,i,p,wait)
  228. ss_extern *x;
  229. ss_thread *t;
  230. int flagi;
  231. ss_id i;
  232. ss_idptr p;
  233. int wait;
  234. {
  235.  timer_sig *tsig;
  236.  kaboomlist k;
  237.  int resched;
  238.  timer_clock dummy;
  239.  
  240.  k = SODalloc(kaboomlist,k,ralloc);
  241.  if (!k)
  242.    return -1;
  243.  tsig = (timer_sig *) x->u.c;
  244.  SODdata(k).when.sec = tsig->when.sec;
  245.  SODdata(k).when.usec = tsig->when.usec;
  246.  SODdata(k).t = t;
  247.  SODdata(k).flagi = flagi;
  248.  SODdata(k).i = i;
  249.  SODdata(k).p = p;
  250.  SODdata(k).wait = wait;
  251.  
  252.  resched = 0;
  253.  if (wait)
  254.    if (!numwait++)
  255.      resched = 1;
  256.  SODpush(thead[tsig->t],k);
  257.  if (!tgoing[tsig->t] || (timer_diff(&(SODdata(k).when),twhen + tsig->t,&dummy) < 0))
  258.    resched |= 2;
  259.  if (resched)
  260.   {
  261.    if (tgoing[tsig->t])
  262.      ss_unsched(ss_signal(t2sig[tsig->t]),kaboom,tsig->t);
  263.    if (ss_schedwait(ss_signal(t2sig[tsig->t]),kaboom,tsig->t,numwait) == -1)
  264.      return -1;
  265.    tgoing[tsig->t] = 1;
  266.    if (resched & 2) twhen[tsig->t] = SODdata(k).when; /*XXX: struct copying*/
  267.    if (set_it(tsig->t,twhen + tsig->t) == -1)
  268.      return -1;
  269.   }
  270.  return 0;
  271. }
  272.  
  273. static int timer_unsched(x,t,flagi,i,p)
  274. ss_extern *x;
  275. ss_thread *t;
  276. int flagi;
  277. ss_id i;
  278. ss_idptr p;
  279. {
  280.  timer_sig *tsig;
  281.  kaboomlist k;
  282.  struct kaboom *sk;
  283.  
  284.  tsig = (timer_sig *) x->u.c;
  285.  for (k = thead[tsig->t];k;k = SODnext(k))
  286.   {
  287.    sk = &(SODdata(k));
  288.    if ((sk->t == t) && (sk->flagi == flagi) && (sk->i == i) && (sk->p == p))
  289.      if ((sk->when.usec == tsig->when.usec) && (sk->when.sec == tsig->when.usec))
  290.       {
  291.        sk->t = 0;
  292.        if (sk->wait)
  293.      --numwait;
  294.        sk->wait = 0;
  295.       }
  296.   }
  297.  kaboomcleanup();
  298.  if (kaboomresched(tsig->t) == -1)
  299.    return -1;
  300.  return 0;
  301. }
  302.  
  303. void timer_setsig(tsig,t,when)
  304. timer_sig *tsig;
  305. timer_type t;
  306. timer_clock *when;
  307. {
  308.  tsig->x.sched = timer_sched;
  309.  tsig->x.unsched = timer_unsched;
  310.  tsig->x.u.c = (char *) tsig; /* my, aren't we the clever ones today */
  311.  tsig->t = t;
  312.  tsig->when.sec = when->sec;
  313.  tsig->when.usec = when->usec;
  314.  ss_externsetsig(&(tsig->sig),&(tsig->x));
  315. }
  316.  
  317. static int init = 0;
  318.  
  319. int timer_init()
  320. {
  321.  struct itimerval it;
  322.  it.it_value.tv_sec = 0; it.it_value.tv_usec = 0;
  323.  it.it_interval.tv_sec = 0; it.it_interval.tv_usec = 0;
  324.  if (init)
  325.    return 0;
  326.  init = 1;
  327.  if (ss_addsig(SIGALRM) == -1)
  328.    return -1;
  329.  if (setitimer(ITIMER_REAL,&it,(struct itimerval *) 0) == -1)
  330.    return -1;
  331.  if (ss_addsig(SIGPROF) == -1)
  332.    return -1;
  333.  if (setitimer(ITIMER_PROF,&it,(struct itimerval *) 0) == -1)
  334.    return -1;
  335.  if (ss_addsig(SIGVTALRM) == -1)
  336.    return -1;
  337.  if (setitimer(ITIMER_VIRTUAL,&it,(struct itimerval *) 0) == -1)
  338.    return -1;
  339.  /* we may end up receiving up to one of each signal, but that's okay */
  340.  return 0;
  341. }
  342.