home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 15 / 15.iso / s / s300 / 1.ddi / CHAP7 / TIME.C < prev    next >
Encoding:
C/C++ Source or Header  |  1988-08-18  |  24.3 KB  |  1,055 lines

  1. /***********************************************************************
  2.  
  3. FILE
  4.     time.c  -  timing routines
  5.  
  6. ENTRY ROUTINES
  7.     chronos      -  timer interrupt service routine
  8.  
  9.     NewDTimer    -  allocate new countdown timer
  10.     FreeDTimer   -  deallocate countdown timer
  11.     SetDTimer    -  set countdown timer
  12.     ReadDTimer   -  read countdown timer
  13.     StopDTimer   -  freeze timer
  14.     StartDTimer  -  unfreeze timer
  15.  
  16.     CisDTimer    -  set tm_isf field to 0
  17.  
  18.     NewITimer    -  allocate new interval timer
  19.     FreeITimer   -  deallocate interval timer
  20.     SetITimer    -  set interval timer
  21.     ReadITimer   -  read interval timer
  22.  
  23.     ReadClock    -  time telling
  24.  
  25. PRIVATE ROUTINES
  26.     reset_dtimer  -  reset countdown timer
  27.     reset_itimer  -  reset interval timer
  28.  
  29. INITIALIZATION ROUTINES
  30.     InitTime     -  initialize timer module
  31.     InitSysTime  -  system initialization for task scheduling
  32.  
  33. DESCRIPTION
  34.     These routines implement multiple timers in software, using a
  35.     single hardware clock as the real-time base.  Actual and
  36.     simulation routines are included.  
  37.     
  38.     Note the implementation of multiple prioritized timer interrupts 
  39.     in chronos().  Only countdown timers are associated with interrupt
  40.     service routines.
  41.  
  42.     The first two timers are reserved by the kernel for time telling
  43.     and task scheduling.
  44.  
  45. LAST UPDATE
  46.     03 May 1985
  47.         restructure allocation routines
  48.     04 February 1986
  49.         put enable() & disable() in #if BACKGROUND
  50.     1 December 1987
  51.         implement tm_flag[]
  52.     26 January 1988
  53.         use the new void types and add ANSI features
  54.  
  55.     Copyright (c) 1985-1988  D.M. Auslander  and  C.H. Tham
  56.  
  57. ***********************************************************************/
  58.  
  59. #define KERNEL
  60.  
  61. /***********************************************************************
  62.                             I M P O R T S
  63. ***********************************************************************/
  64.  
  65. #include <stdio.h>
  66. #include <limits.h>            /* ANSI data size limits */
  67.  
  68. #ifndef INT_MAX
  69. #define INT_MAX        0x7FFF
  70. #endif
  71.  
  72. #ifndef LONG_MAX
  73. #define LONG_MAX    0x7FFFFFFL
  74. #endif
  75.  
  76. #include "envir.h"            /* environment definitions */
  77.  
  78. #include "config.h"            /* system configuration header */
  79. #include "8259.h"            /* hardware dependent declarations */
  80. #include "time.h"            /* time module declarations */
  81.  
  82. #ifdef ANSI
  83.  
  84. extern int  enable(void);    /* enable CPU interrupt response */
  85. extern int  disable(void);    /* disable CPU interrupt response */
  86. extern void seoi(int);        /* send specific EOI to 8259 */
  87. extern void panic(char *);    /* abort execution */
  88.  
  89. #else
  90.  
  91. extern int  enable();        /* enable CPU interrupt response */
  92. extern int  disable();        /* disable CPU interrupt response */
  93. extern void seoi();            /* send specific EOI to 8259 */
  94. extern void panic();        /* abort execution */
  95.  
  96. #endif
  97.  
  98. /***********************************************************************
  99.               F O R W A R D    D E C L A R A T I O N S
  100. ***********************************************************************/
  101.  
  102. #ifdef ANSI
  103.  
  104. static void    reset_dtimer(int);
  105. static void    reset_itimer(int);
  106.  
  107. #else
  108.  
  109. void    reset_dtimer();
  110. void    reset_itimer();
  111.  
  112. #endif
  113.  
  114. /***********************************************************************
  115.                      P R I V A T E    D A T A
  116. ***********************************************************************/
  117.  
  118. static long tm_dtime[MAXDTIMERS];    /* count down timers */
  119.  
  120. static int tm_used[MAXDTIMERS];        /* timer in use flag */
  121. static int tm_lock[MAXDTIMERS];        /* used for virtual time */
  122. static int tm_flag[MAXDTIMERS];        /* timeout flags */
  123. static int tm_pri[MAXDTIMERS];        /* priority (countdown only) */
  124.  
  125. static int tm_isf[MAXDTIMERS];        /* interrupt in service flag */
  126. static void (*tm_tsr[MAXDTIMERS])();    /* timeout service routines */
  127. static void *tm_argp[MAXDTIMERS];    /* ptr to arguments */
  128.  
  129. static long tm_itime[MAXITIMERS];    /* interval timers */
  130. static int tm_iused[MAXITIMERS];    /* interval timer in use flag */
  131.  
  132. static long clock;                    /* countdown since system started */
  133. static long mstick;                    /* milliseconds per tick */
  134.  
  135. #ifdef CLOTHO
  136.  
  137. #define ISF            0                /* whether to use tm_isf field */
  138. #define AUTO_EOI    0                /* enable and send EOI to 8259 */
  139.  
  140. #else
  141.  
  142. #define ISF            1                /* whether to use tm_isf field */
  143. #define AUTO_EOI    0                /* enable and send EOI to 8259 */
  144.  
  145. #endif
  146.  
  147. #define UNUSED        0                /* timer unused */
  148. #define USED        1                /* timer in use */
  149. #define UNLOCK        0                /* timer unlocked */
  150. #define LOCK        1                /* timer locked */
  151. #define FOREGROUND
  152.  
  153. /***********************************************************************
  154.                     E N T R Y    R O U T I N E S
  155. ***********************************************************************/
  156.  
  157. /*---------------------------------------------------------------------
  158. PROCEDURE
  159.     CHRONOS  -  Timer Interrupt Service Routine
  160.  
  161. SYNOPSIS
  162.     void chronos(void)
  163.  
  164. DESCRIPTION
  165.     First decrements count down timers.  Count down timers are only 
  166.     decremented if they are in used (ie. allocated to a task) and
  167.     if the timer is not locked.  Interval timers are the exception 
  168.     and are all incremented irregardless since its probably faster to
  169.     do so than check if they are in use.
  170.  
  171.     Next, the countdown timer array, tm_dtime[], is scanned for zero 
  172.     or negative times.  If time is zero or negative, see if user has 
  173.     specified an interrupt service routine (tm_tsr not NULL).  If so, 
  174.     set the In Service Flag (tm_isf) and execute the routine, clearing
  175.     tm_isf on completion.
  176.  
  177.     If two or more service routines are due for service, the one with
  178.     the highest priority will be executed first.  Only service routines
  179.     with equal or higher priority can interrupt a currently in service
  180.     routine.  Priority is set by the user when the timer is allocated.
  181.     The larger the number, the higher the priority.
  182.  
  183.     Service routines are passed a pointer which may point to a scalar
  184.     argument or an aggregate argument block (eg. structures).  This
  185.     pointer is cast to a char type pointer.
  186.  
  187.     Chronos() may be used in programs where the "interrupt" routine
  188.     never returns;  the "interrupt" service routine may be a task 
  189.     dispatcher or scheduler.  In such cases, two course of action are
  190.     possible depending on whether the dispatcher/scheduler.  In the
  191.     case of a background scheduler, we normally want to disable the 
  192.     in service flag and also reset the hardware interrupt controller.
  193.     This is to allow another timer interrupt to be generated and passed
  194.     to chronos() without the intervention of the dispatcher/scheduler.
  195.     For a foreground dispatcher/scheduler that uses the timer, it will
  196.     want to control exactly when it gives up control, so we do not want
  197.     to send EOI's or enable interrupts here, but allow the foreground
  198.     dispatcher/scheduler to do so with CisDTimer(). 
  199.     
  200.     The in-service-flag may be ignored by means of the ISF conditional
  201.     compilation switch.  The service routine has the task of reseting
  202.     the hardware interrupt controller.  CisDTimer()    performs both actions.
  203.  
  204.     Chronos() functions like a level triggered interrupt controller.
  205.     As long as other conditions are satisfied, a zero or negative
  206.     count will result in execution of the associated service routine.
  207.  
  208.     Note the use of register pointers for speed.
  209.  
  210.     New:    A timeout service routine is only invoked once when the
  211.             count-down timer times out.  The timer must be reset by
  212.             SetDTimer() before the timeout handler can be invoked again.
  213.  
  214. LAST UPDATE
  215.     28 February 1985
  216.         add ISF test
  217.     04 February 1986
  218.         use enable() and disable() only if BACKGROUND
  219.     1 December 1987
  220.         lock timer when isr active, release on reset
  221.     26 January 1988
  222.         use the new void pointer types
  223. ----------------------------------------------------------------------*/
  224.  
  225. void chronos()
  226. {
  227.     int maxpri;                    /* max. pri. of in-service routine */
  228.     int index;                    /* index into timer array */
  229.     int istat;                    /* interrupt status on entry */
  230.     int i;                        /* iteration counter */
  231.     register long *p;            /* fast pointer to timer times */
  232.  
  233.  
  234.     istat = disable();            /* critical section, disable interrupts */
  235.  
  236.  
  237.     ++clock;                    /* update clock */
  238.  
  239.     /*---------------------------------------------------------------
  240.         Upon system clock interrupt, increment all interval timers.
  241.         May be faster than checking if they are used b4 incrementing.
  242.     ----------------------------------------------------------------*/
  243.  
  244.     for (p = tm_itime, i = 0; i < MAXITIMERS; i++, p++)
  245.         ++(*p);
  246.  
  247.     /*---------------------------------------------------------------
  248.         If a countdown timer is active and it is not locked, its 
  249.         time value is decremented.  Does not check if timer has
  250.         timed out since this is taken care of by tm_flag[] and to
  251.         do so here will increase the overheads.  The tm_lock[]
  252.         check is needed because we may need to stop certain timers.
  253.         Have to check if timer is in use because a timeout service
  254.         routine may be attached to a timer.
  255.     ----------------------------------------------------------------*/
  256.  
  257.     for (p = tm_dtime, i = 0; i < MAXDTIMERS; i++, p++)
  258.         if ((tm_used[i] == USED) && (tm_lock[i] == UNLOCK))
  259.             --(*p);
  260.  
  261. #ifdef FOREGROUND        /* use timeout service routines */
  262.  
  263.     /*--------------------------------------------------------------
  264.         Find the highest priority of all timer interrupt routines
  265.         currently in service and set maxpri to that priority.
  266.     --------------------------------------------------------------*/
  267.  
  268.     maxpri = -INT_MAX;
  269.  
  270.     for (i = 0; i < MAXDTIMERS; i++)
  271.         if ((tm_isf[i] > 0) && (tm_pri[i] > maxpri))
  272.             maxpri = tm_pri[i];
  273.  
  274.     /*--------------------------------------------------------------
  275.         Find any pending service routine with greater or equal
  276.         priority.  If index >= 0, such a routine exists and index
  277.         is its offset in tm_tsr[].
  278.     --------------------------------------------------------------*/
  279.  
  280.     index = -1;
  281.  
  282.     for (i = 0; i < MAXDTIMERS; i++)
  283.     {
  284.         if ((tm_dtime[i] <= 0L) && (tm_pri[i] >= maxpri)
  285.             && (tm_isf[i] == 0) && (tm_tsr[i] != (void(*)())NULL)
  286.             && (tm_lock[i] == UNLOCK) && (tm_flag[i] == 0))
  287.         {
  288.             index = i;
  289.             maxpri = tm_pri[i];
  290.         }
  291.     }
  292.  
  293.     if (index >= 0)
  294.     {
  295. #if ISF
  296.         tm_isf[index] += 1;    /* indicate routine in service */
  297. #endif
  298. #if AUTO_EOI
  299.         enable();
  300.  
  301.         seoi(TMRVEC);            /* specific EOI to intrp. controller */
  302. #endif
  303.         tm_flag[index] = 1;        /* prevent further use until reset */
  304.  
  305.         (*(tm_tsr[index]))(tm_argp[index]);
  306.  
  307. #if AUTO_EOI
  308.         disable();
  309. #endif
  310. #if ISF
  311.         tm_isf[index] -= 1;    /* indicate routine done */
  312. #endif
  313.     }
  314.  
  315. #endif    /* ifdef FOREGROUND */
  316.  
  317.     if (istat)
  318.         enable();                /* release mutual exclusion */
  319.  
  320. }
  321.  
  322.  
  323.  
  324. /*----------------------------------------------------------------------
  325. FUNCTION
  326.     NewDTimer  -  allocate countdown timer
  327.  
  328. SYNOPSIS
  329.     int NewDTimer(func, argp, pri)
  330.     void (*func)(), *argp;
  331.     int pri;
  332.  
  333. PARAMETERS
  334.     func  -  pointer to service routine
  335.     argp  -  pointer to argument(s)
  336.     pri   -  priority
  337.  
  338. RETURNS
  339.     timer index if successful, -1 if not.
  340.  
  341. LAST UPDATE
  342.     26 January 1988
  343.         change func type to void
  344. ----------------------------------------------------------------------*/
  345.  
  346. int NewDTimer(func, argp, pri)
  347. void (*func)(), *argp;
  348. int pri;
  349. {
  350.     int i;                        /* iteration variable */
  351.     int istat;                    /* interrupt status */
  352.  
  353.  
  354.     istat = disable();        /* disable interrupts, critical section */
  355.  
  356.     for (i = 0; i < MAXDTIMERS; i++)
  357.         if (tm_used[i] != USED)
  358.             break;
  359.     
  360.     if (i < MAXDTIMERS)
  361.     {
  362.         tm_pri[i] = pri;
  363.         tm_tsr[i] = func;
  364.         tm_argp[i] = argp;
  365.         tm_lock[i] = UNLOCK;
  366.         tm_flag[i] = 0;
  367.         tm_used[i] = USED;
  368.     }
  369.     else
  370.         i = -1;
  371.  
  372.     if (istat)                /* exit critical section, re-enable intrp */
  373.         enable();
  374.  
  375.     return(i);
  376. }
  377.  
  378.  
  379.  
  380. /*----------------------------------------------------------------------
  381. PROCEDURE
  382.     FreeDTimer  -  free allocated timer
  383.  
  384. SYNOPSIS
  385.     void FreeITimer(timer)
  386.     int timer;
  387.  
  388. PARAMTERS
  389.     timer  -  timer index number
  390.  
  391. DESCRIPTION
  392.     Set associated used field to 0, indicating timer is free.  Note that
  393.     you MUST ensure that the timer you are returning is obtained with
  394.     NewDTimer.  Otherwise, you will screw-up the system for sure.
  395.  
  396. LAST UPDATE
  397.     3 May 1985
  398. ----------------------------------------------------------------------*/
  399.  
  400. void FreeDTimer(timer)
  401. int timer;
  402. {
  403.  
  404.     if ((timer < 0) || (timer >= MAXDTIMERS))
  405.     {
  406.         panic("FreeDTimer: nonexistant countdown timer");
  407.     }
  408.     else if (tm_used[timer] == USED)
  409.     {
  410.         reset_dtimer(timer);
  411.     }
  412.     else
  413.         panic("FreeDTimer: countdown timer not allocated");
  414.  
  415. }
  416.  
  417.  
  418.  
  419. /*----------------------------------------------------------------------
  420. PROCEDURE
  421.     SETDTIMER  -  set countdown timer
  422.  
  423. SYNOPSIS
  424.     void SetDTimer(n, ms)
  425.     int n;
  426.     long ms;
  427.  
  428. PARAMETERS
  429.     n   -  timer id
  430.     ms  -  time in milliseconds
  431.  
  432. DESCRIPTION
  433.     Set countdown timer 'n' for ms milliseconds.  If ms is less than
  434.     the resolution of the time-base, tm_dtime is set to zero.
  435.     A negative value of ms deallocates the timer.
  436.  
  437. LAST UPDATE
  438.     1 December 1987
  439.         reset tm_flag
  440. ----------------------------------------------------------------------*/
  441.  
  442. void SetDTimer(n, ms)
  443. int n; 
  444. long ms;
  445. {
  446.     int istat;        /* interrupt status */
  447.     long tmp;        /* temporary to hold tick calculations */
  448.  
  449.  
  450.     if ((n < 0) || (n >= MAXDTIMERS))
  451.         panic("SetDTimer: nonexistent timer");
  452.     else if (tm_used[n] == UNUSED)
  453.         panic("SetDTimer: timer not allocated");
  454.  
  455.     tmp = ms / mstick;
  456.  
  457.     istat = disable();        /* begin mutual exclusion */
  458.  
  459.     tm_flag[n] = 0;            /* reset tm_flag */
  460.  
  461.     if (ms >= 0L)
  462.     {
  463.         tm_dtime[n] = tmp;
  464.     }
  465.     else        /* release timer */
  466.     {
  467.         tm_used[n] = UNUSED;
  468.         tm_tsr[n] = (void(*)())NULL;
  469.     }
  470.  
  471.     if (istat)
  472.         enable();            /* release mutual exclusion */
  473.  
  474. }
  475.  
  476.  
  477.  
  478. /*----------------------------------------------------------------------
  479. FUNCTION
  480.     ReadDTimer  -  read countdown timer
  481.  
  482. SYNOPSIS
  483.     long ReadDTimer(n)
  484.     int n;
  485.  
  486. PARAMETER
  487.     n  -  timer number
  488.  
  489. RETURNS
  490.     time in milliseconds
  491.  
  492. REMARKS
  493.     The time left is only accurate to the precision allowed by the
  494.     system clock rate.  If quantization is 10 ms, then ReadDTimer() 
  495.     will report 10 ms even if actual time left is 1 ms.
  496.  
  497. LAST UPDATE
  498.     12 February 1985  by  author
  499. ----------------------------------------------------------------------*/
  500.  
  501. long ReadDTimer(n)
  502. int n;
  503. {
  504.  
  505.     if ((n < 0) || (n >= MAXDTIMERS))
  506.         panic("ReadDTimer: nonexistant timer");
  507.  
  508.     return(tm_dtime[n] * mstick);
  509. }
  510.  
  511.  
  512.  
  513. /*----------------------------------------------------------------------
  514. PROCEDURE
  515.     STOPDTIMER  -  stop timer from counting down
  516.  
  517. SYNOPSIS
  518.     void StopDTimer(n)
  519.     int n;
  520.  
  521. PARAMETER
  522.     n  -  timer number
  523.  
  524. DESCRIPTION
  525.     This routine should only be used by the system to freeze timers
  526.     used by background process for virtual timing, ie. time proceeds
  527.     only when that process is running.  An important use is for
  528.     background scheduling.
  529.  
  530.     As this is an internal system routine, error checking is lax.
  531.  
  532. SEE ALSO
  533.     StartDTimer() to restart stopped timers
  534.  
  535. LAST UPDATE
  536.     12 February 1985
  537. ----------------------------------------------------------------------*/
  538.  
  539. void StopDTimer(n)
  540. int n;
  541. {
  542.     int istat;                /* interrupt status */
  543.  
  544.  
  545.     if ((n < 0) || (n >= MAXDTIMERS))
  546.         panic("StopDTimer: nonexistent timer");
  547.     
  548.     istat = disable();
  549.  
  550.     tm_lock[n] = LOCK;
  551.  
  552.     if (istat)
  553.         enable();
  554. }
  555.  
  556.  
  557.  
  558. /*----------------------------------------------------------------------
  559. PROCEDURE
  560.     STARTDTIMER  -  stop timer from counting down
  561.  
  562. SYNOPSIS
  563.     void StartDTimer(n)
  564.     int n;
  565.  
  566. PARAMETER
  567.     n  -  timer number
  568.  
  569. REMARKS
  570.     This routine should only be used by the system to restart timers
  571.     frozen by a StopDTimer call.
  572.  
  573. SEE ALSO
  574.     StopDTimer() to stop timers
  575.  
  576. LAST UPDATE
  577.     12 February 1985  by  author
  578. ----------------------------------------------------------------------*/
  579.  
  580. void StartDTimer(n)
  581. int n;
  582. {
  583.     int istat;            /* interrupt status */
  584.  
  585.  
  586.     if ((n < 0) || (n >= MAXDTIMERS))
  587.         panic("StartDTimer: nonexistent timer");
  588.     
  589.     istat = disable();
  590.  
  591.     tm_lock[n] = UNLOCK;
  592.  
  593.     if (istat)
  594.         enable();
  595.  
  596. }
  597.  
  598.  
  599.  
  600. /*----------------------------------------------------------------------
  601. PROCEDURE
  602.     CISDTIMER  -  clear in service flags (software and hardware)
  603.  
  604. SYNOPSIS
  605.     void CisDTimer(n)
  606.     int n;
  607.  
  608. PARAMTER
  609.     n  -  countdown timer number
  610.  
  611. REMARKS
  612.     The purpose is to allow another invokation of the timeout service
  613.     routine at the next timer interrupt.
  614.  
  615. LAST UPDATE
  616.     1 December 1987
  617.         clear tm_flag
  618. ----------------------------------------------------------------------*/
  619.  
  620. void CisDTimer(n)
  621. int n;
  622. {
  623.     int istat;            /* interrupt status */
  624.  
  625.     
  626.     if ((n < 0) || (n >= MAXDTIMERS))
  627.         panic("CisDTimer: nonexistant timer");
  628.     
  629.     istat = disable();
  630.  
  631.     tm_isf[n] = 0;
  632.     tm_flag[n] = 0;
  633.  
  634.     seoi(TMRVEC);    /* send specific EOI to interrupt controller */
  635.  
  636.     if (istat)
  637.         enable();
  638.  
  639. }
  640.  
  641.  
  642.  
  643. /*---------------------------------------------------------------------
  644. PROCEDURE
  645.     SETTSR  -  install timeout service routine
  646.  
  647. SYNOPSIS
  648.     void SetTsr(n, func, argp, pri)
  649.     void (*func)(), *argp;
  650.     int n, pri;
  651.  
  652. PARAMETERS
  653.     n     -  timer id
  654.     func  -  pointer to service routine
  655.     argp  -  pointer to argument structure
  656.     pri   -  priority
  657.  
  658. REMARKS
  659.     There had better be no mistakes when specifying timer.
  660.  
  661. LAST UPDATE
  662.     26 January 1988
  663.         use the new void types
  664. ----------------------------------------------------------------------*/
  665.  
  666. void SetTsr(n, func, argp, pri)
  667. void (*func)(), *argp;
  668. int n, pri;
  669. {
  670.     int istat;                /* interrupt status */
  671.  
  672.  
  673.     if ((n < 0) || (n >= MAXDTIMERS))
  674.         panic("SetTsr:  nonexistant timer");
  675.     
  676.     istat = disable();
  677.  
  678.     tm_pri[n] = pri;
  679.     tm_tsr[n] = func;
  680.     tm_argp[n] = argp;
  681.     tm_lock[n] = UNLOCK;
  682.     tm_flag[n] = 0;
  683.     tm_used[n] = USED;
  684.  
  685.     if (istat)
  686.         enable();
  687.  
  688. }
  689.  
  690.  
  691.  
  692. /*----------------------------------------------------------------------
  693. FUNCTION
  694.     TIMEUP  -  has timer run out?
  695.  
  696. SYNOPSIS
  697.     int TimeUp(n)
  698.     int n;
  699.  
  700. PARAMETER
  701.     n  -  timer number
  702.  
  703. RETURNS
  704.     0  if timer has not timed out
  705.     1  if it has timed out
  706.  
  707. LAST UPDATE
  708.     29 January 1988
  709.         created as this makes more sense than reading the timer
  710. ----------------------------------------------------------------------*/
  711.  
  712. int TimeUp(n)
  713. int n;
  714. {
  715.  
  716.     if ((n < 0) || (n >= MAXDTIMERS))
  717.         panic("TimeUp:  nonexistant timer");
  718.  
  719.     return(tm_dtime[n] <= 0L ? 1 : 0);
  720. }
  721.  
  722.  
  723.  
  724. /*----------------------------------------------------------------------
  725. FUNCTION
  726.     NewITimer  -  allocate interval timer
  727.  
  728. SYNOPSIS
  729.     int NewITimer()
  730.  
  731. RETURNS
  732.     timer index if successful, -1 if not.
  733.  
  734. LAST UPDATE
  735.     3 May 1985
  736. ----------------------------------------------------------------------*/
  737.  
  738. int NewITimer()
  739. {
  740.     int istat;                    /* interrupt status */
  741.     int i;                        /* iteration variable */
  742.  
  743.  
  744.     istat = disable();    /* disable interrupts, critical section */
  745.  
  746.     for (i = 0; i < MAXITIMERS; i++)
  747.         if (tm_iused[i] != USED)
  748.             break;
  749.     
  750.     if (i < MAXITIMERS)
  751.     {
  752.         reset_itimer(i);
  753.  
  754.         tm_iused[i] = USED;
  755.     }
  756.     else
  757.         i = -1;
  758.  
  759.     if (istat)            /* exit critical section, re-enable intrp */
  760.         enable();
  761.  
  762.     return(i);
  763. }
  764.  
  765.  
  766.  
  767. /*----------------------------------------------------------------------
  768. PROCEDURE
  769.     FreeITimer  -  free allocated interval timer
  770.  
  771. SYNOPSIS
  772.     void FreeITimer(timer)
  773.     int timer;
  774.  
  775. PARAMTERS
  776.     timer  -  timer index number
  777.  
  778. DESCRIPTION
  779.     Set associated used field to 0, indicating timer is free.  Note that
  780.     you MUST ensure that the timer you are returning is obtained with
  781.     NewITimer.  Otherwise, you will screw-up the system for sure.
  782.  
  783. LAST UPDATE
  784.     3 May 1985  by  author
  785. ----------------------------------------------------------------------*/
  786.  
  787. void FreeITimer(timer)
  788. int timer;
  789. {
  790.  
  791.     if ((timer < 0) || (timer >= MAXITIMERS))
  792.     {
  793.         panic("FreeITimer: nonexistant interval timer");
  794.     }
  795.     else if (tm_iused[timer] == USED)
  796.     {
  797.         reset_itimer(timer);
  798.     }
  799.     else
  800.         panic("FreeITimer: interval timer not allocated");
  801.  
  802. }
  803.  
  804.  
  805.  
  806. /*----------------------------------------------------------------------
  807. PROCEDURE
  808.     SetITimer  -  set interval timer
  809.  
  810. SYNOPSIS
  811.     void SetITimer(n);
  812.     int n;
  813.  
  814. PARAMETERS
  815.     n   -  timer id
  816.  
  817. REMARKS
  818.     Set interval time value to 0.
  819.  
  820. LAST UPDATE
  821.     13 October 1984
  822. ----------------------------------------------------------------------*/
  823.  
  824. void SetITimer(n)
  825. int n;
  826. {
  827.  
  828.     if ((n < 0) || (n >= MAXITIMERS))
  829.         panic("SetITimer: nonexistant timer");
  830.     
  831.     tm_itime[n] = 0;
  832.  
  833. }
  834.  
  835.  
  836.  
  837. /*----------------------------------------------------------------------
  838. FUNCTION
  839.     ReadITimer  -  read interval timer
  840.  
  841. SYNOPSIS
  842.     long ReadITimer(n);
  843.     int n;
  844.  
  845. PARAMETERS
  846.     n   -  timer id
  847.  
  848. RETURNS
  849.     interval value in milliseconds
  850.  
  851. LAST UPDATE
  852.     13 October 1984
  853. ----------------------------------------------------------------------*/
  854.  
  855. long ReadITimer(n)
  856. int n;
  857. {
  858.     
  859.     if ((n < 0) || (n >= MAXITIMERS))
  860.         panic("ReadITimer: nonexistant timer");
  861.     
  862.     return(tm_itime[n] * mstick);
  863. }
  864.  
  865.  
  866.  
  867. /*----------------------------------------------------------------------
  868. FUNCTION
  869.     ReadClock  -  read system time
  870.  
  871. SYNOPSIS
  872.     long ReadClock()
  873.  
  874. RETURNS
  875.     time elasped in milliseconds since system is born
  876.  
  877. LAST UPDATE
  878.     12 February 1985
  879. ----------------------------------------------------------------------*/
  880.  
  881. long ReadClock()
  882. {
  883.  
  884.     return(clock * mstick);
  885. }
  886.  
  887.  
  888.  
  889. /***********************************************************************
  890.                     P R I V A T E    R O U T I N E S 
  891. ***********************************************************************/
  892.  
  893. /*----------------------------------------------------------------------
  894. PROCEDURE
  895.     reset_dtimer  -  reset countdown timer
  896.  
  897. SYNOPSIS
  898.     static reset_dtimer(n)
  899.     int n;
  900.  
  901. PARAMETER
  902.     n  -  timer id
  903.  
  904. LAST UPDATE
  905.     1 December 1987
  906.         clear tm_flag
  907. ----------------------------------------------------------------------*/
  908.  
  909. static void reset_dtimer(n)
  910. int n;
  911. {
  912.  
  913.     tm_dtime[n] = LONG_MAX;
  914.     tm_used[n] = UNUSED;
  915.     tm_lock[n] = UNLOCK;
  916.     tm_flag[n] = 0;
  917.     tm_pri[n] = PZERO - 1;
  918.     tm_isf[n] = 0;
  919.     tm_tsr[n] = (void(*)())NULL;
  920.     tm_argp[n] = (void *)NULL;
  921.  
  922. }
  923.  
  924.  
  925.  
  926. /*----------------------------------------------------------------------
  927. PROCEDURE
  928.     reset_itimer  -  reset interval timer
  929.  
  930. SYNOPSIS
  931.     static void reset_itimer(n)
  932.     int n;
  933.  
  934. PARAMETER
  935.     n  -  timer id
  936.  
  937. LAST UPDATE
  938.     12 February 1985
  939. ----------------------------------------------------------------------*/
  940.  
  941. static void reset_itimer(n)
  942. int n;
  943. {
  944.  
  945.     tm_itime[n] = 0L;
  946.     tm_iused[n] = UNUSED;
  947.  
  948. }
  949.  
  950.  
  951. /***********************************************************************
  952.             I N I T I A L I Z A T I O N    R O U T I N E S
  953. ***********************************************************************/
  954.  
  955. /*----------------------------------------------------------------------
  956. PROCEDURE
  957.     INITTIME  -  initialize this module
  958.  
  959. SYNOPSIS
  960.     void InitTime(ms)
  961.     long ms;
  962.  
  963. PARAMETER
  964.     ms  -  milliseconds per tick
  965.  
  966. LAST UPDATE
  967.     12 February 1985
  968.         separate countdown and interval timers.
  969. ----------------------------------------------------------------------*/
  970.  
  971. void InitTime(ms)
  972. long ms;
  973. {
  974.     int i;                    /* iteration variable */
  975.  
  976.  
  977.     mstick = ms;
  978.     clock = 0L;
  979.  
  980.  
  981.     for (i = 0; i < MAXDTIMERS; i++)
  982.     {
  983.         reset_dtimer(i);
  984.     }
  985.  
  986.     for (i = 0; i < MAXITIMERS; i++)
  987.     {
  988.         reset_itimer(i);
  989.     }
  990.  
  991. }
  992.  
  993.  
  994. #ifdef CLOTHO        /* used by clotho kernel only */
  995.  
  996. extern void InitSysTime(void (*)());
  997.  
  998. /*----------------------------------------------------------------------
  999. PROCEDURE
  1000.     INITSYSTIME  -  allocate and initialize timers for system
  1001.  
  1002. SYNOPSIS
  1003.     void InitSysTime(dispatcher)
  1004.     void (*dispatcher)();
  1005.  
  1006. PARAMETER
  1007.     dispatcher  -  pointer to clotho's scheduler/dispatcher
  1008.  
  1009. REMARKS
  1010.     timer 0  -  reserved for normal dispatcher
  1011.     timer 1  -  reserved for control-task dispatcher/scheduler
  1012.  
  1013. LAST UPDATE
  1014.     12 February 1985
  1015. ----------------------------------------------------------------------*/
  1016.  
  1017. void InitSysTime(dispatcher)
  1018. void (*dispatcher)();
  1019. {
  1020.  
  1021.     if ((SLC_TIMER >= MAXDTIMERS) || (STL_TIMER >= MAXDTIMERS))
  1022.         panic("InitSysTime: check SLC_TIMER & STL_TIMER < MAXDTIMERS");
  1023.  
  1024.     tm_used[SLC_TIMER] = USED;
  1025.     tm_lock[SLC_TIMER] = UNLOCK;
  1026.     tm_flag[SLC_TIMER] = 0;
  1027.  
  1028.     tm_used[STL_TIMER] = USED;
  1029.     tm_lock[STL_TIMER] = UNLOCK;
  1030.     tm_flag[STL_TIMER] = 0;
  1031.  
  1032. #ifdef FOREGROUND
  1033.  
  1034.     /*****  set up timer for time-slice priority dispatcher  *****/
  1035.  
  1036.     tm_tsr[SLC_TIMER] = dispatcher;
  1037.     tm_argp[SLC_TIMER] = (void *)SLC_TIMER;
  1038.     tm_pri[SLC_TIMER] = PZERO + 1;    /* has low priority */
  1039.     tm_dtime[SLC_TIMER] = 0;        /* start background next */
  1040.  
  1041.  
  1042.     /*****  set up timer for control-task STL dispatcher  *****/
  1043.  
  1044.     tm_tsr[STL_TIMER] = dispatcher;
  1045.     tm_argp[STL_TIMER] = (void *)STL_TIMER;
  1046.     tm_pri[STL_TIMER] = INT_MAX;        /* has very high priority */
  1047.     tm_dtime[STL_TIMER] = LONG_MAX;
  1048.  
  1049. #endif    /* ifdef FOREGROUND */
  1050.  
  1051. }
  1052.  
  1053. #endif    /* ifdef CLOTHO */
  1054. 
  1055.