home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / oper_sys / emerald / emrldsys.lha / Kernel / MsgOps / timerCode.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-08-17  |  18.6 KB  |  761 lines

  1.  
  2. /*
  3.  * @(#)timerCode.c    1.4  2/23/90
  4.  */
  5.  
  6. /* File: /u1/Eden/Kernel/MsgOps/TimerCode.c */
  7.  
  8. /*
  9.  * $Header:   /u1/Eden/Source/MsgOps/RCS/TimerCode.v  Revision 2.3  85/03/14  21:51:11  eric Exp$
  10.  * INTERFACE:    Defined by the exported procedures.
  11.  *
  12.  * FUNCTION:    Provides the Message Module Timer Services.
  13.  *
  14.  * IMPORTS:    /u1/Eden/Source/MsgOps/MsgDefs.h,
  15.  *              /u1/Eden/Source/MsgOps/Types.h,
  16.  *              /u1/Eden/ErrCodes/MMcodes.h,
  17.  *              /u1/Eden/Source/MsgOps/TimerTypes.h,
  18.  *              /u1/Eden/Source/ProcessA/Events.h,
  19.  *              signal.h, time, ctime, QueueTask.
  20.  *
  21.  * EXPORTS:    MMSetTimer, MMCancelTimer, MMInitTimer,
  22.  *              MMPrintTimerElt, MMPrintTimer.
  23.  *
  24.  * DESIGN:
  25.  *
  26.  * $Log:    /u1/Eden/Source/MsgOps/RCS/TimerCode.v $
  27.  *
  28.  * Revision 4.1 89/8/35 eric@diku.dk
  29.  * Fixed missing #ifdef xkernel around all xgettime calls.
  30.  *
  31.  * Revision 4.0 88/7/11 cjeffery "RCS is for bozos!"
  32.  * Modified to use xkernel timer calls.
  33.  *
  34.  * Revision 3.0  86/05/22  13:00:22  eric
  35.  * Modified to use the newer 4.2bsd timer calls.
  36.  *
  37.  * Revision 2.3  85/03/11  00:35:42  eric
  38.  * Fixed bugs in MXTraceMsg.
  39.  *
  40.  * Revision 2.2  85/02/22  00:35:42  eric
  41.  * Fixed bug in CancelTimer:  The resetting of the alarm was sometimes
  42.  * done with a value < MINTIME - i.e., zero thereby CANCELLING the
  43.  * alarm and leaving the remaining timers stranded.
  44.  * Changed MXTraceMsg numbers to correspond more closely to the msgCode.c
  45.  * definitions.
  46.  *
  47.  * Revision 2.1  84/02/16  21:51:11  oystr
  48.  * Version 2 baseline.
  49.  * 
  50.  * Revision 1.9  84/02/16  15:12:35  eric
  51.  * Proper port cleanup on port death implemented (ipc emergency signal
  52.  * handling).
  53.  * 
  54.  * Minor fixes:
  55.  * Signal handlers now 'proctect' QueueTask via 'HoldSigs(); ... ; ReleaseSigs()'
  56.  * Minor bug in TimerCode fixed.
  57.  * 
  58.  * NOTE:  The message module now makes heavy use of the HOTS table when
  59.  * using the Ether.  The HOTS table lookup routine has been optimized
  60.  * new hashing function and a one-element cache.
  61.  * 
  62.  * Revision 1.8  83/03/19  11:41:48  cady
  63.  * Modified MMCancelTimer to allow NULL fParm pointer.
  64.  * 
  65.  * Revision 1.7  83/03/04  15:30:15  cady
  66.  * Fixed MMCancelTimer to cancel alarm or adjust for next request.
  67.  * 
  68.  * Revision 1.6  83/03/03  13:47:50  cady
  69.  * Fixed bugs introduced by last set of fixes.
  70.  * 
  71.  * Revision 1.5  83/03/01  17:06:08  cady
  72.  * Added MMPrintTimer routines.
  73.  * Revised to allow cancel after timeout, but before handler executed.
  74.  * 
  75.  * Revision 1.4  83/02/25  12:13:09  cady
  76.  * No change.
  77.  * 
  78.  * Revision 1.3  83/02/24  16:41:56  cady
  79.  * Replaced conditional debug trace with dynamic trace.
  80.  * Added conditional Kernel compilation.
  81.  * 
  82.  * Revision 1.2  83/02/22  12:06:46  cady
  83.  * Replaced #if Debug with #ifdef Debug.
  84.  * 
  85.  * Revision 1.1  83/01/06  14:12:44  cady
  86.  * Initial revision
  87.  * 
  88.  * 4-Dec-1982    Initial implementation. S. Banawan
  89.  */
  90.  
  91. /****************************************************************/
  92. /*                   Message Module Timer Library               */
  93. /****************************************************************/
  94.  
  95. #include <sys/types.h>
  96. #include <sys/time.h>
  97.  
  98. #ifndef mmMsgDefs
  99. #include "Kernel/h/mmMsgDefs.h"
  100. #endif
  101. #ifdef xkernel
  102. #include "userupi.h"
  103. #endif
  104.  
  105. #include "Kernel/h/assert.h"
  106. #include "Kernel/h/mmTypes.h"
  107. #include "Kernel/h/mmCodes.h"
  108. #include "Kernel/h/timerTypes.h"
  109. #include "Kernel/h/kEvents.h"
  110. #include "Kernel/h/kmdTypes.h"
  111. #include "Kernel/h/expandArray.h"
  112. #include "Kernel/h/timeops.h"
  113. #include "Kernel/h/system.h"
  114. #include "Kernel/h/map.h"
  115.  
  116. #include <signal.h>
  117.  
  118.  
  119.  
  120. /****************************************************************/
  121. /*                 Static Local Variables                       */
  122. /****************************************************************/
  123.  
  124.  
  125. #define MAXTIMERS 1
  126. #define NONE -1
  127. #define MAXID 65535
  128. #define MINTIME 10000    /* Minimum scheduling time */
  129.  
  130. /* Timer Request Entry */
  131.  
  132. typedef struct timeval TimeValue;
  133.  
  134. typedef struct
  135. {
  136.     int         Next;
  137.     TimerId     TimerID;
  138.     TimeValue   ExpireTime;
  139.     Boolean     Expired;
  140.     Boolean     Cancelled:1;
  141.     HandlerPtr  TimerHandler;
  142.     integer     Parm;
  143. } TimerElt;
  144.  
  145. /* Fixed-size Table of Timer Requests: but dynamically expandable */
  146.  
  147. static TimerElt *TimersArray;
  148. int              cMMCurrentMaxTimers = MAXTIMERS;
  149.  
  150. /* Linked Lists of Timer Request Entries */
  151.  
  152. int      NextTimer = NONE;
  153. int      Avail     = 0;
  154.  
  155. /* Last Assigned Timer Id */
  156.  
  157. TimerId  IdCounter = MAXID;
  158.  
  159. TimeValue       minTime = {0, MINTIME};
  160. TimeValue       zeroTimeValue = {0, 0};
  161.  
  162. /* External routines */
  163.  
  164. extern time_t  time();
  165. extern char *ctime();
  166. extern void SetHandler();
  167. extern int perror();
  168.  
  169. /* Forward decl.*/
  170. void TimerDump(), ActiveTimers();
  171.  
  172. static char asciiTimeBuf[50];
  173.  
  174. /*
  175.  * MMAsciiTime (was MMPrintTimer)
  176.  *
  177.  * Returns a pointer to a static buffer containing the ASCII incoding
  178.  * of the time given including the microsecond part (cf. ctime(3))
  179.  */
  180. char *MMAsciiTime( fTime )
  181. TimeValue fTime;
  182. {
  183.   char *cTimePtr;
  184.  
  185.   cTimePtr = ctime((time_t *) &fTime.tv_sec);
  186.   (void) sprintf(asciiTimeBuf,
  187.       "%.19s.%06d%s", cTimePtr, fTime.tv_usec, cTimePtr+19);
  188.   return(asciiTimeBuf);
  189. }
  190.  
  191.  
  192. /*
  193.  * MMPrintTime
  194.  *
  195.  * Prints the timeval as for ctime(3) but additionally inserts
  196.  * the microsecond part.
  197.  */
  198. void MMPrintTime( fTime )
  199. TimeValue fTime;
  200. {
  201.   printf("%s", MMAsciiTime(fTime));    
  202. }
  203.  
  204.  
  205. /*
  206.  * MMPrintTimerElt
  207.  */
  208. void MMPrintTimerElt( fTimer)
  209. int fTimer;
  210. {
  211.   TimerElt *timer;
  212.  
  213.   timer = &TimersArray[fTimer];
  214.   printf("Request %08x ", timer->TimerID);
  215.   if ( timer->Cancelled ) printf("(cancelled) ");
  216.   printf("expire%c",(timer->Expired?'d':'s'));
  217.   MMPrintTime(timer->ExpireTime);  
  218. }
  219.  
  220. /*
  221.  * MMPrintTimer
  222.  */
  223. void MMPrintTimer()
  224. {
  225.   int i;
  226.  
  227.   i = NextTimer;
  228.   if ( i == NONE ) {
  229.     printf("No pending timer requests.\n");
  230.   } else {
  231.     printf("\n");
  232.     while ( i != NONE ) {
  233.       MMPrintTimerElt( i );
  234.       i = TimersArray[i].Next;
  235.     }
  236.   }
  237. }
  238.  
  239. /*
  240.  * NewTimerId
  241.  *  This routine generates a new timer ID whenever it is called.
  242.  *  The range of the identifiers is 1 to 2^16-1
  243.  */
  244. static TimerId NewTimerId()
  245. {
  246.   IdCounter = ( (IdCounter < MAXID) ? IdCounter+1 : 1 );
  247.   return( IdCounter );
  248. }
  249.  
  250. /*
  251.  * AddMoreTimers
  252.  *
  253.  * Dynamically expand the number of timers.
  254.  */
  255. static void AddMoreTimers()
  256. {
  257.   register int    oldCount, oldSize, i;
  258.   TimeValue       theTime;
  259. #ifndef xkernel
  260.   struct timezone   theZone;
  261. #endif
  262.   oldCount = cMMCurrentMaxTimers;
  263.   oldSize= oldCount * sizeof(TimerElt);
  264.   cMMCurrentMaxTimers = oldCount + oldCount;
  265.   MXTraceMsg(2, "Doubling the number of timers, now %d\n",
  266.          cMMCurrentMaxTimers);
  267.  
  268.   ExpandArray((int **)&TimersArray, oldSize, oldSize+oldSize);
  269.  
  270.   /* add them to the list */
  271. #ifdef xkernel
  272.   xgettime(&theTime);
  273. #else
  274.   gettimeofday(&theTime, &theZone);
  275. #endif xkernel
  276.   for ( i = oldCount; i < cMMCurrentMaxTimers-1 ; i++ ) {
  277.     TimersArray[i].Next = i + 1;
  278.     TimersArray[i].ExpireTime = theTime;
  279.   }
  280.   TimersArray[cMMCurrentMaxTimers-1].Next = NONE;
  281.   TimersArray[cMMCurrentMaxTimers-1].ExpireTime = theTime;
  282.   Avail = oldCount;
  283. }
  284.  
  285. /*
  286.  * FindTimerId
  287.  */
  288. static Boolean FindTimerId( fTimerId, fPosition, fPrevious )
  289. TimerId  fTimerId;
  290. int     *fPosition, *fPrevious;
  291. {
  292.   int pres, prev;
  293.  
  294.   prev = NONE;
  295.   pres = NextTimer;
  296.   while ( pres != NONE ){
  297.     if ( TimersArray[pres].TimerID == fTimerId )
  298.       break;
  299.     else {
  300.       prev = pres;
  301.       pres = TimersArray[pres].Next;
  302.     }
  303.   }
  304.   *fPosition = pres;
  305.   *fPrevious = prev;
  306.   return ( pres != NONE );
  307. }
  308.  
  309. TimerInterrupt();
  310.  
  311. /*
  312.  * ScheduleAlarm
  313.  */
  314. void ScheduleAlarm(fTimeValue)
  315. TimeValue          fTimeValue;
  316. {
  317. #ifndef xkernel
  318.   int result;
  319.   struct itimerval oldValue;
  320. #endif
  321.   struct itimerval newValue;
  322.  
  323.   newValue.it_interval = zeroTimeValue;
  324.   newValue.it_value = fTimeValue;
  325.   if (timeLess(fTimeValue, minTime)) {
  326.     newValue.it_value = minTime;
  327.   }
  328.   MXTraceMsg(5, "ScheduleAlarm: %d.%d seconds.\n",
  329.          newValue.it_value.tv_sec, newValue.it_value.tv_usec);
  330. #ifndef xkernel
  331.   result = setitimer(ITIMER_REAL, &newValue, &oldValue);
  332.   if (result < 0) {
  333.     MXTraceMsg(1, "Could not setitimer\n");
  334.     perror("setitimer");
  335.   }
  336.   assert (result == 0);
  337. #else
  338.   xeventregister(TimerInterrupt, 0,
  339.          newValue.it_value.tv_sec*1000+newValue.it_value.tv_usec/1000,
  340.          EV_ONCE);
  341. #endif
  342. }
  343.  
  344. void DeScheduleAlarm()
  345. {
  346.   MXTraceMsg(5, "DeScheduleAlarm\n");
  347.   ScheduleAlarm(zeroTimeValue);
  348. }
  349.  
  350. /*
  351.  * TimerHandler
  352.  */
  353. static HResult TimerHandler( fTimerId )
  354. TimerId fTimerId;
  355. {
  356.   register TimerElt   *timer;
  357.   int         pres, prev;
  358.   HandlerPtr  handler;
  359.   integer     parm;
  360.  
  361.   MXTraceMsg(7, "TimerHandler( %d )\n", fTimerId);
  362.  
  363.   handler = NULL;
  364.   HoldSigs();
  365.   if ( FindTimerId( fTimerId, &pres, &prev ) ){
  366.     timer = &TimersArray[pres];
  367.     if ( ! timer->Cancelled ){
  368.       handler = timer->TimerHandler;
  369.       parm = timer->Parm;
  370.     }
  371.     if ( prev == NONE )
  372.       NextTimer = timer->Next;
  373.     else
  374.       TimersArray[prev].Next = timer->Next;
  375.     timer->Next = Avail;
  376.     Avail = pres;
  377.   }
  378.   ReleaseSigs();
  379.   if ( handler != NULL )
  380.     (*handler)( parm, fTimerId );
  381. }
  382.  
  383. /*
  384.  * TimerInterrupt
  385.  *
  386.  *  This routine is the handler for the alarm signal. It scans
  387.  *  all the TimersArray to determine if any timer has expired
  388.  *  and executes the associated handler.
  389.  */
  390. TimerInterrupt()
  391. {
  392.   int       pres;
  393.   TimeValue theTime, delta;
  394.   register TimerElt *timer;
  395.  
  396. #ifndef xkernel
  397.   struct timezone   theZone;
  398.  
  399.   gettimeofday(&theTime, &theZone);
  400. #else
  401.   xgettime(&theTime);
  402. #endif xkernel
  403.  
  404.   MXTraceMsg(7, "TimerInterrupt() at %s", MMAsciiTime(theTime));
  405.  
  406.   pres = NextTimer;
  407.   while( pres != NONE ){
  408.     if ( timeLessEq(TimersArray[pres].ExpireTime, theTime) ){
  409.       timer = &TimersArray[pres];
  410.       if ( ! timer->Expired ) { 
  411.     MXTraceMsg(7, "Timer request %d expired at %s", timer->TimerID,
  412.            MMAsciiTime(timer->ExpireTime));
  413.     timer->Expired = True;
  414.     HoldSigs(); /* Protect QueueTask against other signals. */
  415.     QueueTask( (HandlerPtr)TimerHandler, (char *)timer->TimerID );
  416.     ReleaseSigs();
  417.       }
  418.       pres = timer->Next;
  419.     } else {
  420.       timeSub(delta, TimersArray[pres].ExpireTime, theTime);
  421.       if ( timeLess(delta, minTime) )
  422.     delta = minTime;
  423.       ScheduleAlarm(delta);
  424.       break;
  425.     }
  426.   }
  427. }
  428.  
  429. /*
  430.  * MMInitTimer
  431.  *
  432.  * MMInitTimer initializes the Timer Services data structures.
  433.  */
  434. void MMInitTimer()
  435. {
  436.   int i;
  437.   TimeValue       theTime;
  438. #ifndef xkernel
  439.   struct timezone   theZone;
  440. #endif
  441.  
  442.   MXTraceMsg(4, "MMInitTimer()    cMMCurrentMaxTimers = %d\n",
  443.       cMMCurrentMaxTimers);
  444.  
  445.   CreateArray((int **)&TimersArray, cMMCurrentMaxTimers * sizeof(TimerElt));
  446. #ifdef xkernel
  447.   xgettime(&theTime);
  448. #else
  449.   gettimeofday(&theTime, &theZone);
  450. #endif xkernel
  451.   for ( i = 0; i < cMMCurrentMaxTimers-1 ; i++ ) {
  452.     TimersArray[i].Next = i + 1;
  453.     TimersArray[i].ExpireTime = theTime;
  454.   };
  455.   TimersArray[cMMCurrentMaxTimers-1].Next = NONE;
  456.   TimersArray[cMMCurrentMaxTimers-1].ExpireTime = theTime;
  457.   NextTimer = NONE;
  458.   Avail = 0;
  459.   IdCounter = MAXID;
  460.   KMDSetSnap(ActiveTimers);
  461.   KMDSetSnap(TimerDump);
  462. #ifdef BSD
  463.   SetHandler(SIGALRM, TimerInterrupt);
  464. #endif
  465. }
  466.  
  467.  
  468. #ifdef xkernel
  469. typedef struct {
  470.   PFI f;
  471.   int a;
  472. } timeoutGoody;
  473. Map tomap = NULL;
  474.  
  475. xkTimeout(g)
  476. timeoutGoody *g;
  477. {
  478.   extern int xkUtilsDebugging;
  479.   if (xkUtilsDebugging) printf("Timeout handler\n");
  480.   xkhandlerstart();
  481.   g->f(g->a);
  482.   Map_Delete(tomap, (int)g);
  483.   free((char *) g);
  484.   xkhandlerend();
  485. }
  486. #endif
  487.  
  488. /*
  489.  * MMSetMicroTimer
  490.  *
  491.  *  This procedure is used to schedule execution of a particular
  492.  *  procedure at fDelta seconds into the future.
  493.  *  A timer identifier (fTimerID) is assigned to the request and
  494.  *  returned to the caller.
  495.  *
  496.  *  Possible status codes:
  497.  *      MMSS_Success, MMSF_QOvfl, MMSF_BadDelta
  498.  */
  499. KKStatus MMSetMicroTimer( fDelta, fDeltaUSec, fTimerHandler, fParm, fTimerID )
  500. int        fDelta;        /* Time in seconds   */
  501. int        fDeltaUSec;    /* and microseconds  */
  502. HandlerPtr fTimerHandler; /* Time-out Handler  */
  503. int        fParm;         /* Handler Parameter */
  504. TimerId   *fTimerID;      /* RETURNS: Timer Request ID, can be NULL */
  505. {
  506. #ifdef xkernel
  507.   EVENT foo;
  508.   timeoutGoody *tg;
  509. #else
  510.   TimeValue AlarmTime, currentTime;
  511.   struct timezone   theZone;
  512.   register TimerElt *p;
  513.   int       prev, pres, i;
  514.   Boolean   FirstNonExpired;
  515.   TimeValue delta;
  516. #endif
  517.  
  518.   MXTraceMsg(7, "MMSetMicroTimer( %d s, %d us, %d, %d )\n",
  519.          fDelta, fDeltaUSec, fTimerHandler, fParm);
  520.  
  521. #ifdef xkernel
  522.   if (! tomap) tomap = Map_CreateSized(100);
  523.   tg = (timeoutGoody *) malloc(sizeof(timeoutGoody));
  524.   tg->f = fTimerHandler;
  525.   tg->a = fParm;
  526.   Map_Insert(tomap, (int)tg, (int)tg);
  527.   foo = xeventregister((PFI)xkTimeout,tg,
  528.                fDelta*1000+fDeltaUSec/1000, EV_ONCE);
  529.   if(fTimerID) *fTimerID = (TimerId) foo;
  530.   return (foo==(EVENT)-1)?MMSF_QOvfl:MMSS_Success;
  531. #else
  532.  
  533.   timeBuild(delta, fDelta, fDeltaUSec);
  534.  
  535.   /* Allocate next available timer slot */
  536.  
  537.   if ( timeLess(delta, minTime) ) delta = minTime;
  538.   HoldSigs();                   /* Disable interrupts */
  539.   if ( Avail == NONE ) AddMoreTimers();
  540.  
  541.   i = Avail;
  542.   Avail = TimersArray[Avail].Next;            
  543.   p = &TimersArray[i];
  544.  
  545.   /* Build timer request entry */
  546.  
  547. #ifdef xkernel
  548.   xgettime(¤tTime);
  549. #else
  550.   gettimeofday(¤tTime, &theZone);
  551. #endif xkernel
  552.   timeAdd(AlarmTime, currentTime, delta);
  553.   p->TimerID = NewTimerId();
  554.   p->ExpireTime = AlarmTime;
  555.   p->Expired = False;
  556.   p->Cancelled = False;
  557.   p->TimerHandler = fTimerHandler;
  558.   p->Parm = fParm;
  559.  
  560.   MXTraceMsg(7, "Timer request %d to expire at %s", p->TimerID,
  561.          MMAsciiTime(AlarmTime));
  562.  
  563.   /* Insert new request into ordered list of requests.
  564.    * Keep track of whether the new one is the First one in the list
  565.    * which has not expired, so that we may reset the alarm if necessary.
  566.    */
  567.   prev = NONE;
  568.   pres = NextTimer;
  569.   FirstNonExpired = True; /* True, while new element is first non expired. */
  570.   while( pres != NONE){
  571.     if ( timeLessEq(TimersArray[pres].ExpireTime, AlarmTime) ) {
  572.       FirstNonExpired &= TimersArray[pres].Expired;
  573.       prev = pres;
  574.       pres = TimersArray[pres].Next;
  575.     } else
  576.       break;
  577.   }
  578.   p->Next = pres;
  579.   MXTraceMsg(8, "inserting after: %d before: %d, %s FirstNonExpired\n",
  580.     prev, pres, (FirstNonExpired)? "is" : "is not");
  581.  
  582.   /* If new request is the next timeout, reset alarm */
  583.  
  584.   if ( FirstNonExpired ){  /* Reset alarm since new one is to go off first. */
  585.     ScheduleAlarm( delta );
  586.   }
  587.   if (prev == NONE)
  588.     /* Insert at front. */
  589.     NextTimer = i;
  590.   else /* Insert in middle. */
  591.     TimersArray[prev].Next = i;
  592.  
  593.   /* Enable interrupts and return results */
  594.  
  595.   ReleaseSigs();
  596.   if (fTimerID != NULL) *fTimerID = p->TimerID;
  597.   return(MMSS_Success);
  598. #endif
  599. }
  600.  
  601. /*
  602.  * MMSetTimer
  603.  *
  604.  *  This procedure is used to schedule execution of a particular
  605.  *  procedure at fDelta seconds into the future.
  606.  *  A timer identifier (fTimerID) is assigned to the request and
  607.  *  returned to the caller.
  608.  *
  609.  *  Possible status codes:
  610.  *      MMSS_Success, MMSF_QOvfl, MMSF_BadDelta
  611.  */
  612. KKStatus  MMSetTimer( fDelta, fTimerHandler, fParm, fTimerID )
  613. unsigned   fDelta;        /* Time in seconds   */
  614. HandlerPtr fTimerHandler; /* Time-out Handler  */
  615. int        fParm;         /* Handler Parameter */
  616. TimerId   *fTimerID;      /* RETURNS: Timer Request ID */
  617. {
  618.   MXTraceMsg(7, "MMSetTimer( %d, %d, %d )\n",
  619.          fDelta, fTimerHandler, fParm);
  620.   MMSetMicroTimer((int)fDelta, 0, fTimerHandler, fParm, fTimerID);
  621. }
  622.  
  623. /*
  624.  * MMCancelTimer
  625.  *
  626.  *  This procedure allows the higher level routines to cancel an
  627.  *  outstanding timer request identified by fTimerId.
  628.  *
  629.  *  Possible status codes:
  630.  *      MMSS_Success, MMSF_BadID
  631.  */
  632. KKStatus  MMCancelTimer( fTimerId, fParm )
  633. TimerId  fTimerId;  /* Timer Request     */
  634. integer *fParm;     /* Handler Parameter */
  635. {
  636. #ifndef xkernel
  637.   KKStatus status;
  638.   int      prev, pres;
  639.   TimeValue currentTime, delta;
  640.   struct timezone   theZone;
  641. #endif
  642.   MXTraceMsg(7, "MMCancelTimer( %d, %d )\n", fTimerId, fParm);
  643. #ifdef xkernel
  644.   return
  645.     (xeventremoveevent((EVENT)fTimerId)== -1)?MMSF_BadID:MMSS_Success;
  646. #else
  647.  
  648.   HoldSigs();               /* Disable interrupts */
  649.   status = MMSF_BadID;
  650.  
  651. #ifdef xkernel
  652.   xgettime(¤tTime);
  653. #else
  654.   gettimeofday(¤tTime, &theZone);
  655. #endif xkernel
  656.   if ( FindTimerId( fTimerId, &pres, &prev ) ){
  657.     status = MMSS_Success;
  658.     if ( fParm != NULL )
  659.       *fParm = TimersArray[pres].Parm;
  660.  
  661.     /* If already expired, just set flag.  */
  662.     /* Otherwise, delete request.          */
  663.  
  664.     if ( TimersArray[pres].Expired )
  665.       TimersArray[pres].Cancelled = True;
  666.     else {
  667.       /* Cancel and remove from queue. */
  668.       TimersArray[pres].Cancelled = True;
  669.       if ( prev != NONE )
  670.     TimersArray[prev].Next = TimersArray[pres].Next;
  671.       else {
  672.     NextTimer = TimersArray[pres].Next;
  673.  
  674.     /* Adjust alarm time for next request (if any) */
  675.  
  676.     if ( NextTimer == NONE ) {
  677.       DeScheduleAlarm();
  678.     } else {
  679.       if ( timeGtr(TimersArray[NextTimer].ExpireTime,
  680.                TimersArray[pres].ExpireTime )) {
  681.         timeSub(delta, TimersArray[NextTimer].ExpireTime,
  682.             currentTime);
  683.         /* Reschedule alarm only if next time is not too close. */
  684.         if (timeGtrEq(delta, minTime)) ScheduleAlarm(delta);
  685.       }
  686.     }
  687.       }
  688.       TimersArray[pres].Next = Avail;
  689.       Avail = pres;
  690.     }
  691.   }
  692.  
  693.   /* Enable interrupts and return result */
  694.  
  695.   ReleaseSigs();
  696.   return(status);
  697. #endif
  698. }
  699.  
  700.  
  701. /*
  702.  *      Snapshot handlers.
  703.  *
  704.  */
  705.  
  706. /* Snapshot ALL Timers. */
  707. void TimerDump()
  708. {
  709.   time_t theTime = time((time_t *) 0);
  710.   int i;
  711.  
  712.   KMDPrint("Dump of timers in LNN %d at %24.24s\n", GetLNN(), ctime(&theTime));
  713.   KMDPrint("NextTimer = %d,  Avail = %d\n", NextTimer, Avail);
  714.   KMDPrint("No. Next TimerId    Handler    Param        ExpireTime\n");
  715.   for (i=0; i < cMMCurrentMaxTimers; i++)
  716.     KMDPrint("%2d %4d %8d  0x%08x 0x%08x %.26s %s %s\n", i,
  717.          TimersArray[i].Next,  TimersArray[i].TimerID,
  718.          TimersArray[i].TimerHandler,
  719.          TimersArray[i].Parm,  MMAsciiTime(TimersArray[i].ExpireTime),
  720.          TimersArray[i].Expired ? "Expired" : " ",
  721.          TimersArray[i].Cancelled ? "Cancelled" : " ");
  722. }
  723.  
  724. /* Snapshot Active Timers. */
  725. void ActiveTimers()
  726. {
  727.   time_t theTime = time((time_t *) 0);
  728.   int i;
  729.  
  730.   KMDPrint("Active timers in LNN %d at %24.24s\n", GetLNN(), ctime(&theTime));
  731.   KMDPrint("No. Next TimerId    Handler    Param        ExpireTime\n");
  732.   for (i = NextTimer; i != NONE; i = TimersArray[i].Next)
  733.     KMDPrint("%2d %4d %8d  0x%08x 0x%08x %.26s %s %s\n", i,
  734.          TimersArray[i].Next,  TimersArray[i].TimerID,
  735.          TimersArray[i].TimerHandler,
  736.          TimersArray[i].Parm,  MMAsciiTime(TimersArray[i].ExpireTime),
  737.          TimersArray[i].Expired ? "Expired" : " ",
  738.          TimersArray[i].Cancelled ? "Cancelled" : " ");
  739. }
  740.  
  741. #ifndef xkernel
  742. /*
  743.  * xgettime is defined here so that we don't have to #ifdef xkernel
  744.  * every where it is used.
  745.  * xgettime is the x kernel's version of gettimeofday
  746.  */
  747.  
  748. void xgettime(fTimeValuePtr)
  749. TimeValue         fTimeValuePtr;
  750. {
  751.   TimeValue           theTime;
  752.   struct timezone       theZone;
  753.  
  754. /*
  755.    * When the xkernel is not used, use gettimeofday as in the original
  756.    * Emerald kernel (fix date: Aug. 25, 1989, Eric Jul, eric@diku.dk)
  757.    */
  758.   gettimeofday(&theTime, &theZone);
  759. }
  760. #endif xkernel
  761.