home *** CD-ROM | disk | FTP | other *** search
-
- /*
- * @(#)timerCode.c 1.4 2/23/90
- */
-
- /* File: /u1/Eden/Kernel/MsgOps/TimerCode.c */
-
- /*
- * $Header: /u1/Eden/Source/MsgOps/RCS/TimerCode.v Revision 2.3 85/03/14 21:51:11 eric Exp$
- * INTERFACE: Defined by the exported procedures.
- *
- * FUNCTION: Provides the Message Module Timer Services.
- *
- * IMPORTS: /u1/Eden/Source/MsgOps/MsgDefs.h,
- * /u1/Eden/Source/MsgOps/Types.h,
- * /u1/Eden/ErrCodes/MMcodes.h,
- * /u1/Eden/Source/MsgOps/TimerTypes.h,
- * /u1/Eden/Source/ProcessA/Events.h,
- * signal.h, time, ctime, QueueTask.
- *
- * EXPORTS: MMSetTimer, MMCancelTimer, MMInitTimer,
- * MMPrintTimerElt, MMPrintTimer.
- *
- * DESIGN:
- *
- * $Log: /u1/Eden/Source/MsgOps/RCS/TimerCode.v $
- *
- * Revision 4.1 89/8/35 eric@diku.dk
- * Fixed missing #ifdef xkernel around all xgettime calls.
- *
- * Revision 4.0 88/7/11 cjeffery "RCS is for bozos!"
- * Modified to use xkernel timer calls.
- *
- * Revision 3.0 86/05/22 13:00:22 eric
- * Modified to use the newer 4.2bsd timer calls.
- *
- * Revision 2.3 85/03/11 00:35:42 eric
- * Fixed bugs in MXTraceMsg.
- *
- * Revision 2.2 85/02/22 00:35:42 eric
- * Fixed bug in CancelTimer: The resetting of the alarm was sometimes
- * done with a value < MINTIME - i.e., zero thereby CANCELLING the
- * alarm and leaving the remaining timers stranded.
- * Changed MXTraceMsg numbers to correspond more closely to the msgCode.c
- * definitions.
- *
- * Revision 2.1 84/02/16 21:51:11 oystr
- * Version 2 baseline.
- *
- * Revision 1.9 84/02/16 15:12:35 eric
- * Proper port cleanup on port death implemented (ipc emergency signal
- * handling).
- *
- * Minor fixes:
- * Signal handlers now 'proctect' QueueTask via 'HoldSigs(); ... ; ReleaseSigs()'
- * Minor bug in TimerCode fixed.
- *
- * NOTE: The message module now makes heavy use of the HOTS table when
- * using the Ether. The HOTS table lookup routine has been optimized
- * new hashing function and a one-element cache.
- *
- * Revision 1.8 83/03/19 11:41:48 cady
- * Modified MMCancelTimer to allow NULL fParm pointer.
- *
- * Revision 1.7 83/03/04 15:30:15 cady
- * Fixed MMCancelTimer to cancel alarm or adjust for next request.
- *
- * Revision 1.6 83/03/03 13:47:50 cady
- * Fixed bugs introduced by last set of fixes.
- *
- * Revision 1.5 83/03/01 17:06:08 cady
- * Added MMPrintTimer routines.
- * Revised to allow cancel after timeout, but before handler executed.
- *
- * Revision 1.4 83/02/25 12:13:09 cady
- * No change.
- *
- * Revision 1.3 83/02/24 16:41:56 cady
- * Replaced conditional debug trace with dynamic trace.
- * Added conditional Kernel compilation.
- *
- * Revision 1.2 83/02/22 12:06:46 cady
- * Replaced #if Debug with #ifdef Debug.
- *
- * Revision 1.1 83/01/06 14:12:44 cady
- * Initial revision
- *
- * 4-Dec-1982 Initial implementation. S. Banawan
- */
-
- /****************************************************************/
- /* Message Module Timer Library */
- /****************************************************************/
-
- #include <sys/types.h>
- #include <sys/time.h>
-
- #ifndef mmMsgDefs
- #include "Kernel/h/mmMsgDefs.h"
- #endif
- #ifdef xkernel
- #include "userupi.h"
- #endif
-
- #include "Kernel/h/assert.h"
- #include "Kernel/h/mmTypes.h"
- #include "Kernel/h/mmCodes.h"
- #include "Kernel/h/timerTypes.h"
- #include "Kernel/h/kEvents.h"
- #include "Kernel/h/kmdTypes.h"
- #include "Kernel/h/expandArray.h"
- #include "Kernel/h/timeops.h"
- #include "Kernel/h/system.h"
- #include "Kernel/h/map.h"
-
- #include <signal.h>
-
-
-
- /****************************************************************/
- /* Static Local Variables */
- /****************************************************************/
-
-
- #define MAXTIMERS 1
- #define NONE -1
- #define MAXID 65535
- #define MINTIME 10000 /* Minimum scheduling time */
-
- /* Timer Request Entry */
-
- typedef struct timeval TimeValue;
-
- typedef struct
- {
- int Next;
- TimerId TimerID;
- TimeValue ExpireTime;
- Boolean Expired;
- Boolean Cancelled:1;
- HandlerPtr TimerHandler;
- integer Parm;
- } TimerElt;
-
- /* Fixed-size Table of Timer Requests: but dynamically expandable */
-
- static TimerElt *TimersArray;
- int cMMCurrentMaxTimers = MAXTIMERS;
-
- /* Linked Lists of Timer Request Entries */
-
- int NextTimer = NONE;
- int Avail = 0;
-
- /* Last Assigned Timer Id */
-
- TimerId IdCounter = MAXID;
-
- TimeValue minTime = {0, MINTIME};
- TimeValue zeroTimeValue = {0, 0};
-
- /* External routines */
-
- extern time_t time();
- extern char *ctime();
- extern void SetHandler();
- extern int perror();
-
- /* Forward decl.*/
- void TimerDump(), ActiveTimers();
-
- static char asciiTimeBuf[50];
-
- /*
- * MMAsciiTime (was MMPrintTimer)
- *
- * Returns a pointer to a static buffer containing the ASCII incoding
- * of the time given including the microsecond part (cf. ctime(3))
- */
- char *MMAsciiTime( fTime )
- TimeValue fTime;
- {
- char *cTimePtr;
-
- cTimePtr = ctime((time_t *) &fTime.tv_sec);
- (void) sprintf(asciiTimeBuf,
- "%.19s.%06d%s", cTimePtr, fTime.tv_usec, cTimePtr+19);
- return(asciiTimeBuf);
- }
-
-
- /*
- * MMPrintTime
- *
- * Prints the timeval as for ctime(3) but additionally inserts
- * the microsecond part.
- */
- void MMPrintTime( fTime )
- TimeValue fTime;
- {
- printf("%s", MMAsciiTime(fTime));
- }
-
-
- /*
- * MMPrintTimerElt
- */
- void MMPrintTimerElt( fTimer)
- int fTimer;
- {
- TimerElt *timer;
-
- timer = &TimersArray[fTimer];
- printf("Request %08x ", timer->TimerID);
- if ( timer->Cancelled ) printf("(cancelled) ");
- printf("expire%c",(timer->Expired?'d':'s'));
- MMPrintTime(timer->ExpireTime);
- }
-
- /*
- * MMPrintTimer
- */
- void MMPrintTimer()
- {
- int i;
-
- i = NextTimer;
- if ( i == NONE ) {
- printf("No pending timer requests.\n");
- } else {
- printf("\n");
- while ( i != NONE ) {
- MMPrintTimerElt( i );
- i = TimersArray[i].Next;
- }
- }
- }
-
- /*
- * NewTimerId
- * This routine generates a new timer ID whenever it is called.
- * The range of the identifiers is 1 to 2^16-1
- */
- static TimerId NewTimerId()
- {
- IdCounter = ( (IdCounter < MAXID) ? IdCounter+1 : 1 );
- return( IdCounter );
- }
-
- /*
- * AddMoreTimers
- *
- * Dynamically expand the number of timers.
- */
- static void AddMoreTimers()
- {
- register int oldCount, oldSize, i;
- TimeValue theTime;
- #ifndef xkernel
- struct timezone theZone;
- #endif
- oldCount = cMMCurrentMaxTimers;
- oldSize= oldCount * sizeof(TimerElt);
- cMMCurrentMaxTimers = oldCount + oldCount;
- MXTraceMsg(2, "Doubling the number of timers, now %d\n",
- cMMCurrentMaxTimers);
-
- ExpandArray((int **)&TimersArray, oldSize, oldSize+oldSize);
-
- /* add them to the list */
- #ifdef xkernel
- xgettime(&theTime);
- #else
- gettimeofday(&theTime, &theZone);
- #endif xkernel
- for ( i = oldCount; i < cMMCurrentMaxTimers-1 ; i++ ) {
- TimersArray[i].Next = i + 1;
- TimersArray[i].ExpireTime = theTime;
- }
- TimersArray[cMMCurrentMaxTimers-1].Next = NONE;
- TimersArray[cMMCurrentMaxTimers-1].ExpireTime = theTime;
- Avail = oldCount;
- }
-
- /*
- * FindTimerId
- */
- static Boolean FindTimerId( fTimerId, fPosition, fPrevious )
- TimerId fTimerId;
- int *fPosition, *fPrevious;
- {
- int pres, prev;
-
- prev = NONE;
- pres = NextTimer;
- while ( pres != NONE ){
- if ( TimersArray[pres].TimerID == fTimerId )
- break;
- else {
- prev = pres;
- pres = TimersArray[pres].Next;
- }
- }
- *fPosition = pres;
- *fPrevious = prev;
- return ( pres != NONE );
- }
-
- TimerInterrupt();
-
- /*
- * ScheduleAlarm
- */
- void ScheduleAlarm(fTimeValue)
- TimeValue fTimeValue;
- {
- #ifndef xkernel
- int result;
- struct itimerval oldValue;
- #endif
- struct itimerval newValue;
-
- newValue.it_interval = zeroTimeValue;
- newValue.it_value = fTimeValue;
- if (timeLess(fTimeValue, minTime)) {
- newValue.it_value = minTime;
- }
- MXTraceMsg(5, "ScheduleAlarm: %d.%d seconds.\n",
- newValue.it_value.tv_sec, newValue.it_value.tv_usec);
- #ifndef xkernel
- result = setitimer(ITIMER_REAL, &newValue, &oldValue);
- if (result < 0) {
- MXTraceMsg(1, "Could not setitimer\n");
- perror("setitimer");
- }
- assert (result == 0);
- #else
- xeventregister(TimerInterrupt, 0,
- newValue.it_value.tv_sec*1000+newValue.it_value.tv_usec/1000,
- EV_ONCE);
- #endif
- }
-
- void DeScheduleAlarm()
- {
- MXTraceMsg(5, "DeScheduleAlarm\n");
- ScheduleAlarm(zeroTimeValue);
- }
-
- /*
- * TimerHandler
- */
- static HResult TimerHandler( fTimerId )
- TimerId fTimerId;
- {
- register TimerElt *timer;
- int pres, prev;
- HandlerPtr handler;
- integer parm;
-
- MXTraceMsg(7, "TimerHandler( %d )\n", fTimerId);
-
- handler = NULL;
- HoldSigs();
- if ( FindTimerId( fTimerId, &pres, &prev ) ){
- timer = &TimersArray[pres];
- if ( ! timer->Cancelled ){
- handler = timer->TimerHandler;
- parm = timer->Parm;
- }
- if ( prev == NONE )
- NextTimer = timer->Next;
- else
- TimersArray[prev].Next = timer->Next;
- timer->Next = Avail;
- Avail = pres;
- }
- ReleaseSigs();
- if ( handler != NULL )
- (*handler)( parm, fTimerId );
- }
-
- /*
- * TimerInterrupt
- *
- * This routine is the handler for the alarm signal. It scans
- * all the TimersArray to determine if any timer has expired
- * and executes the associated handler.
- */
- TimerInterrupt()
- {
- int pres;
- TimeValue theTime, delta;
- register TimerElt *timer;
-
- #ifndef xkernel
- struct timezone theZone;
-
- gettimeofday(&theTime, &theZone);
- #else
- xgettime(&theTime);
- #endif xkernel
-
- MXTraceMsg(7, "TimerInterrupt() at %s", MMAsciiTime(theTime));
-
- pres = NextTimer;
- while( pres != NONE ){
- if ( timeLessEq(TimersArray[pres].ExpireTime, theTime) ){
- timer = &TimersArray[pres];
- if ( ! timer->Expired ) {
- MXTraceMsg(7, "Timer request %d expired at %s", timer->TimerID,
- MMAsciiTime(timer->ExpireTime));
- timer->Expired = True;
- HoldSigs(); /* Protect QueueTask against other signals. */
- QueueTask( (HandlerPtr)TimerHandler, (char *)timer->TimerID );
- ReleaseSigs();
- }
- pres = timer->Next;
- } else {
- timeSub(delta, TimersArray[pres].ExpireTime, theTime);
- if ( timeLess(delta, minTime) )
- delta = minTime;
- ScheduleAlarm(delta);
- break;
- }
- }
- }
-
- /*
- * MMInitTimer
- *
- * MMInitTimer initializes the Timer Services data structures.
- */
- void MMInitTimer()
- {
- int i;
- TimeValue theTime;
- #ifndef xkernel
- struct timezone theZone;
- #endif
-
- MXTraceMsg(4, "MMInitTimer() cMMCurrentMaxTimers = %d\n",
- cMMCurrentMaxTimers);
-
- CreateArray((int **)&TimersArray, cMMCurrentMaxTimers * sizeof(TimerElt));
- #ifdef xkernel
- xgettime(&theTime);
- #else
- gettimeofday(&theTime, &theZone);
- #endif xkernel
- for ( i = 0; i < cMMCurrentMaxTimers-1 ; i++ ) {
- TimersArray[i].Next = i + 1;
- TimersArray[i].ExpireTime = theTime;
- };
- TimersArray[cMMCurrentMaxTimers-1].Next = NONE;
- TimersArray[cMMCurrentMaxTimers-1].ExpireTime = theTime;
- NextTimer = NONE;
- Avail = 0;
- IdCounter = MAXID;
- KMDSetSnap(ActiveTimers);
- KMDSetSnap(TimerDump);
- #ifdef BSD
- SetHandler(SIGALRM, TimerInterrupt);
- #endif
- }
-
-
- #ifdef xkernel
- typedef struct {
- PFI f;
- int a;
- } timeoutGoody;
- Map tomap = NULL;
-
- xkTimeout(g)
- timeoutGoody *g;
- {
- extern int xkUtilsDebugging;
- if (xkUtilsDebugging) printf("Timeout handler\n");
- xkhandlerstart();
- g->f(g->a);
- Map_Delete(tomap, (int)g);
- free((char *) g);
- xkhandlerend();
- }
- #endif
-
- /*
- * MMSetMicroTimer
- *
- * This procedure is used to schedule execution of a particular
- * procedure at fDelta seconds into the future.
- * A timer identifier (fTimerID) is assigned to the request and
- * returned to the caller.
- *
- * Possible status codes:
- * MMSS_Success, MMSF_QOvfl, MMSF_BadDelta
- */
- KKStatus MMSetMicroTimer( fDelta, fDeltaUSec, fTimerHandler, fParm, fTimerID )
- int fDelta; /* Time in seconds */
- int fDeltaUSec; /* and microseconds */
- HandlerPtr fTimerHandler; /* Time-out Handler */
- int fParm; /* Handler Parameter */
- TimerId *fTimerID; /* RETURNS: Timer Request ID, can be NULL */
- {
- #ifdef xkernel
- EVENT foo;
- timeoutGoody *tg;
- #else
- TimeValue AlarmTime, currentTime;
- struct timezone theZone;
- register TimerElt *p;
- int prev, pres, i;
- Boolean FirstNonExpired;
- TimeValue delta;
- #endif
-
- MXTraceMsg(7, "MMSetMicroTimer( %d s, %d us, %d, %d )\n",
- fDelta, fDeltaUSec, fTimerHandler, fParm);
-
- #ifdef xkernel
- if (! tomap) tomap = Map_CreateSized(100);
- tg = (timeoutGoody *) malloc(sizeof(timeoutGoody));
- tg->f = fTimerHandler;
- tg->a = fParm;
- Map_Insert(tomap, (int)tg, (int)tg);
- foo = xeventregister((PFI)xkTimeout,tg,
- fDelta*1000+fDeltaUSec/1000, EV_ONCE);
- if(fTimerID) *fTimerID = (TimerId) foo;
- return (foo==(EVENT)-1)?MMSF_QOvfl:MMSS_Success;
- #else
-
- timeBuild(delta, fDelta, fDeltaUSec);
-
- /* Allocate next available timer slot */
-
- if ( timeLess(delta, minTime) ) delta = minTime;
- HoldSigs(); /* Disable interrupts */
- if ( Avail == NONE ) AddMoreTimers();
-
- i = Avail;
- Avail = TimersArray[Avail].Next;
- p = &TimersArray[i];
-
- /* Build timer request entry */
-
- #ifdef xkernel
- xgettime(¤tTime);
- #else
- gettimeofday(¤tTime, &theZone);
- #endif xkernel
- timeAdd(AlarmTime, currentTime, delta);
- p->TimerID = NewTimerId();
- p->ExpireTime = AlarmTime;
- p->Expired = False;
- p->Cancelled = False;
- p->TimerHandler = fTimerHandler;
- p->Parm = fParm;
-
- MXTraceMsg(7, "Timer request %d to expire at %s", p->TimerID,
- MMAsciiTime(AlarmTime));
-
- /* Insert new request into ordered list of requests.
- * Keep track of whether the new one is the First one in the list
- * which has not expired, so that we may reset the alarm if necessary.
- */
- prev = NONE;
- pres = NextTimer;
- FirstNonExpired = True; /* True, while new element is first non expired. */
- while( pres != NONE){
- if ( timeLessEq(TimersArray[pres].ExpireTime, AlarmTime) ) {
- FirstNonExpired &= TimersArray[pres].Expired;
- prev = pres;
- pres = TimersArray[pres].Next;
- } else
- break;
- }
- p->Next = pres;
- MXTraceMsg(8, "inserting after: %d before: %d, %s FirstNonExpired\n",
- prev, pres, (FirstNonExpired)? "is" : "is not");
-
- /* If new request is the next timeout, reset alarm */
-
- if ( FirstNonExpired ){ /* Reset alarm since new one is to go off first. */
- ScheduleAlarm( delta );
- }
- if (prev == NONE)
- /* Insert at front. */
- NextTimer = i;
- else /* Insert in middle. */
- TimersArray[prev].Next = i;
-
- /* Enable interrupts and return results */
-
- ReleaseSigs();
- if (fTimerID != NULL) *fTimerID = p->TimerID;
- return(MMSS_Success);
- #endif
- }
-
- /*
- * MMSetTimer
- *
- * This procedure is used to schedule execution of a particular
- * procedure at fDelta seconds into the future.
- * A timer identifier (fTimerID) is assigned to the request and
- * returned to the caller.
- *
- * Possible status codes:
- * MMSS_Success, MMSF_QOvfl, MMSF_BadDelta
- */
- KKStatus MMSetTimer( fDelta, fTimerHandler, fParm, fTimerID )
- unsigned fDelta; /* Time in seconds */
- HandlerPtr fTimerHandler; /* Time-out Handler */
- int fParm; /* Handler Parameter */
- TimerId *fTimerID; /* RETURNS: Timer Request ID */
- {
- MXTraceMsg(7, "MMSetTimer( %d, %d, %d )\n",
- fDelta, fTimerHandler, fParm);
- MMSetMicroTimer((int)fDelta, 0, fTimerHandler, fParm, fTimerID);
- }
-
- /*
- * MMCancelTimer
- *
- * This procedure allows the higher level routines to cancel an
- * outstanding timer request identified by fTimerId.
- *
- * Possible status codes:
- * MMSS_Success, MMSF_BadID
- */
- KKStatus MMCancelTimer( fTimerId, fParm )
- TimerId fTimerId; /* Timer Request */
- integer *fParm; /* Handler Parameter */
- {
- #ifndef xkernel
- KKStatus status;
- int prev, pres;
- TimeValue currentTime, delta;
- struct timezone theZone;
- #endif
- MXTraceMsg(7, "MMCancelTimer( %d, %d )\n", fTimerId, fParm);
- #ifdef xkernel
- return
- (xeventremoveevent((EVENT)fTimerId)== -1)?MMSF_BadID:MMSS_Success;
- #else
-
- HoldSigs(); /* Disable interrupts */
- status = MMSF_BadID;
-
- #ifdef xkernel
- xgettime(¤tTime);
- #else
- gettimeofday(¤tTime, &theZone);
- #endif xkernel
- if ( FindTimerId( fTimerId, &pres, &prev ) ){
- status = MMSS_Success;
- if ( fParm != NULL )
- *fParm = TimersArray[pres].Parm;
-
- /* If already expired, just set flag. */
- /* Otherwise, delete request. */
-
- if ( TimersArray[pres].Expired )
- TimersArray[pres].Cancelled = True;
- else {
- /* Cancel and remove from queue. */
- TimersArray[pres].Cancelled = True;
- if ( prev != NONE )
- TimersArray[prev].Next = TimersArray[pres].Next;
- else {
- NextTimer = TimersArray[pres].Next;
-
- /* Adjust alarm time for next request (if any) */
-
- if ( NextTimer == NONE ) {
- DeScheduleAlarm();
- } else {
- if ( timeGtr(TimersArray[NextTimer].ExpireTime,
- TimersArray[pres].ExpireTime )) {
- timeSub(delta, TimersArray[NextTimer].ExpireTime,
- currentTime);
- /* Reschedule alarm only if next time is not too close. */
- if (timeGtrEq(delta, minTime)) ScheduleAlarm(delta);
- }
- }
- }
- TimersArray[pres].Next = Avail;
- Avail = pres;
- }
- }
-
- /* Enable interrupts and return result */
-
- ReleaseSigs();
- return(status);
- #endif
- }
-
-
- /*
- * Snapshot handlers.
- *
- */
-
- /* Snapshot ALL Timers. */
- void TimerDump()
- {
- time_t theTime = time((time_t *) 0);
- int i;
-
- KMDPrint("Dump of timers in LNN %d at %24.24s\n", GetLNN(), ctime(&theTime));
- KMDPrint("NextTimer = %d, Avail = %d\n", NextTimer, Avail);
- KMDPrint("No. Next TimerId Handler Param ExpireTime\n");
- for (i=0; i < cMMCurrentMaxTimers; i++)
- KMDPrint("%2d %4d %8d 0x%08x 0x%08x %.26s %s %s\n", i,
- TimersArray[i].Next, TimersArray[i].TimerID,
- TimersArray[i].TimerHandler,
- TimersArray[i].Parm, MMAsciiTime(TimersArray[i].ExpireTime),
- TimersArray[i].Expired ? "Expired" : " ",
- TimersArray[i].Cancelled ? "Cancelled" : " ");
- }
-
- /* Snapshot Active Timers. */
- void ActiveTimers()
- {
- time_t theTime = time((time_t *) 0);
- int i;
-
- KMDPrint("Active timers in LNN %d at %24.24s\n", GetLNN(), ctime(&theTime));
- KMDPrint("No. Next TimerId Handler Param ExpireTime\n");
- for (i = NextTimer; i != NONE; i = TimersArray[i].Next)
- KMDPrint("%2d %4d %8d 0x%08x 0x%08x %.26s %s %s\n", i,
- TimersArray[i].Next, TimersArray[i].TimerID,
- TimersArray[i].TimerHandler,
- TimersArray[i].Parm, MMAsciiTime(TimersArray[i].ExpireTime),
- TimersArray[i].Expired ? "Expired" : " ",
- TimersArray[i].Cancelled ? "Cancelled" : " ");
- }
-
- #ifndef xkernel
- /*
- * xgettime is defined here so that we don't have to #ifdef xkernel
- * every where it is used.
- * xgettime is the x kernel's version of gettimeofday
- */
-
- void xgettime(fTimeValuePtr)
- TimeValue fTimeValuePtr;
- {
- TimeValue theTime;
- struct timezone theZone;
-
- /*
- * When the xkernel is not used, use gettimeofday as in the original
- * Emerald kernel (fix date: Aug. 25, 1989, Eric Jul, eric@diku.dk)
- */
- gettimeofday(&theTime, &theZone);
- }
- #endif xkernel
-