home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Libraries / stdwin / Ports / x11 / timer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-10-18  |  5.4 KB  |  225 lines  |  [TEXT/????]

  1. /* X11 STDWIN -- Alarm timers (BSD-specific) */
  2.  
  3. #ifdef AMOEBA
  4. #include "amtimer.c"
  5. #else /* !AMOEBA */
  6.  
  7. #include "x11.h"
  8.  
  9. #include <errno.h>
  10.  
  11. /* Alarm timer values must be stored as absolute times,
  12.    but since they are in tenths of a second and stored in a long,
  13.    there isn't enough space to store the true absolute time.
  14.    Therefore, they are stored relative to the second when the
  15.    first call to wsettimer was made, which is saved in torigin */
  16.  
  17. static long torigin;        /* Seconds */
  18. static long nexttimer;        /* Deciseconds */
  19.  
  20. /* Compute a new value for nexttimer.
  21.    Return the relevant window as a convenience */
  22.  
  23. static WINDOW *
  24. setnexttimer()
  25. {
  26.     WINDOW *win= _wnexttimer();
  27.     
  28.     if (win == NULL)
  29.         nexttimer= 0;
  30.     else
  31.         nexttimer= win->timer;
  32.     _wdebug(3, "setnexttimer: nexttimer at %d for %x", nexttimer, win);
  33.     return win;
  34. }
  35.  
  36. /* Set the alarm timer for a given window */
  37.  
  38. void wsettimer(win, deciseconds)
  39.     WINDOW *win;
  40.     int deciseconds;
  41. {
  42.     _wdebug(3, "wsettimer: deciseconds=%d", deciseconds);
  43.     win->timer= 0;
  44.     if (deciseconds > 0) {
  45.         struct timeval tv;
  46.         struct timezone tz;
  47.         
  48.         if (gettimeofday(&tv, &tz) < 0) {
  49.             _wwarning("wsettimer: can't get time of day");
  50.         }
  51.         else {
  52.             if (torigin == 0) {
  53.                 torigin= tv.tv_sec;
  54.                 _wdebug(3, "wsettimer: torigin %d", torigin);
  55.             }
  56.             win->timer= deciseconds + 10 * (tv.tv_sec - torigin) +
  57.                 tv.tv_usec/100000;
  58.             _wdebug(4, "wsettimer(%d): timer set to %d",
  59.                 deciseconds, win->timer);
  60.         }
  61.     }
  62.     (void) setnexttimer();
  63. }
  64.  
  65. /* Return a pointer suitable as timeout parameter for BSD select(2).
  66.    If no alarms are currently set, return a NULL pointer */
  67.  
  68. static struct timeval *
  69. timeout()
  70. {
  71.     if (nexttimer == 0) {
  72.         _wdebug(4, "timeout: no timers set");
  73.         return NULL;
  74.     }
  75.     else {
  76.         static struct timeval tv;
  77.         struct timezone tz;
  78.         
  79.         if (gettimeofday(&tv, &tz) < 0) {
  80.             _wwarning("timeout: can't get time of day");
  81.             return NULL;
  82.         }
  83.         else {
  84.             long tout;
  85.             tout= nexttimer
  86.                 - (tv.tv_sec - torigin) * 10
  87.                 - tv.tv_usec / 100000;
  88.             if (tout <= 0)
  89.                 tv.tv_sec= tv.tv_usec= 0;
  90.             else {
  91.                 tv.tv_sec= tout / 10; 
  92.                 tv.tv_usec= (tout % 10) * 100000;
  93.             }
  94.             _wdebug(4, "timeout: delay %d sec %d usec",
  95.                 tv.tv_sec, tv.tv_usec);
  96.             return &tv;
  97.         }
  98.     }
  99. }
  100.  
  101. /* Check if an alarm has gone off, and if so, generate an appropriate event.
  102.    This can be called at any time, but for efficiency reasons it should
  103.    only be called when an alarm has actually gone of (i.e., select has
  104.    timed out).  If an alarm has gone off, it will always be found by
  105.    this function */
  106.  
  107. static bool
  108. dotimer(ep)
  109.     EVENT *ep;
  110. {
  111.     WINDOW *win= setnexttimer();
  112.     struct timeval *tp;
  113.     
  114.     if (win == NULL) {
  115.         _wdebug(1, "dotimer: no event found (spurious call)");
  116.         return FALSE;
  117.     }
  118.     tp= timeout();
  119.     if (tp == NULL) {
  120.         _wdebug(1, "dotimer: unexpected NULL timeout()");
  121.         return FALSE;
  122.     }
  123.     if (tp->tv_sec == 0 && tp->tv_usec == 0) {
  124.         _wdebug(3, "dotimer: reporting timer event");
  125.         ep->type= WE_TIMER;
  126.         ep->window= win;
  127.         win->timer= 0;
  128.         (void) setnexttimer();
  129.         return TRUE;
  130.     }
  131.     else {
  132.         _wdebug(1, "dotimer: it is not yet time");
  133.         return FALSE;
  134.     }
  135. }
  136.  
  137. /* Check for timer events.
  138.    Call this after XPending returns 0, just before calling XNextEvent */
  139.  
  140. bool
  141. _w_checktimer(ep, mayblock)
  142.     EVENT *ep;
  143.     bool mayblock;
  144. {
  145.     for (;;) {
  146.         struct timeval *tp= timeout();
  147.         /* This is naive.  BSD 4.3 really uses an array of longs
  148.            as arguments to select.  Hope there aren't >32 fds, or
  149.            the socket and pipe are among the first 32 files opened */
  150.         unsigned long rd, wd, xd;
  151.         int fd, nfd;
  152.         int nfound;
  153.         if (tp != NULL)
  154.             _wdebug(4, "_wchecktimer: sec=%d, usec=%d",
  155.                 tp->tv_sec, tp->tv_usec);
  156.         if (!mayblock) {
  157.             if (tp != NULL)
  158.                 _wdebug(4, "_wchecktimer: !mayblock");
  159.             return tp != NULL &&
  160.                 tp->tv_sec == 0 && tp->tv_usec == 0 &&
  161.                 dotimer(ep);
  162.         }
  163.         fd= _wd->fd;
  164.         rd= 1 << fd;
  165.         nfd= fd+1;
  166. #ifdef PIPEHACK
  167.         if (_wpipe[0] >= 0) {
  168.             rd |= (1 << _wpipe[0]);
  169.             if (_wpipe[0]+1 > nfd)
  170.                 nfd= _wpipe[0]+1;
  171.         }
  172. #endif
  173.         wd= xd= 0;
  174.         if (tp == NULL)
  175.             _wdebug(4, "wchecktimer: select w/o timeout");
  176.         else
  177.             _wdebug(4,
  178.                 "_wchecktimer: select call, sec=%d, usec=%d",
  179.                 tp->tv_sec, tp->tv_usec);
  180. #ifdef AMOEBA
  181.         /* Amoeba is far superior to unix:
  182.            we don't need something as silly as select... */
  183.         nfound= EIO;
  184. #else
  185.         nfound= select(nfd, &rd, &wd, &xd, tp);
  186. #endif
  187.         _wdebug(4, "_wchecktimer: select returned %d", nfound);
  188.         /* Note: if select returns negative, we also break
  189.            out of the loop -- better drop a timer event than
  190.            loop forever on a select error.
  191.            The only exception is EINTR, which may have been caused
  192.            by an application's signal handler */
  193.         if (nfound < 0) {
  194.             if (errno == EINTR) {
  195.                 _wdebug(4, "_wchecktimer: select interrupted");
  196.                 continue;
  197.             }
  198.             else {
  199. #ifdef AMOEBA
  200.                 if (errno != EIO)
  201. #endif
  202.                 _wwarning(
  203.                     "_wchecktimer: select failed, errno=%d",
  204.                     errno);
  205.             }
  206.         }
  207.         if (nfound != 0)
  208.             break;
  209.         if (dotimer(ep))
  210.             return TRUE;
  211.     }
  212.     _wdebug(4, "_wchecktimer: returning FALSE");
  213.     return FALSE;
  214. }
  215.  
  216. /* P.S.: It is not necessary to recompute nextalarm when windows are
  217.    deleted.  This can at most cause a spurious time-out, after which
  218.    dotimeout() is called again which recomputes nextalarm as a side
  219.    effect (twice, even).  Applications incur a slight overhead if they
  220.    delete a window with a timer set and no other windows have timers
  221.    set; in this case a larger part of the timeout code is called until
  222.    the alarm goes off (which is then ignored!). */
  223.  
  224. #endif /* !AMOEBA */
  225.