Copied Types
EventProc: TYPE ~ CommTimer.EventProc;
Timer: TYPE ~ REF TimerObject;
TimerObject: PUBLIC TYPE ~ CommTimerPrivate.TimerObject;
Event: TYPE ~ CommTimer.Event;
EventObject: PUBLIC TYPE ~ CommTimerPrivate.EventObject;
Event Freelist
eventLock: Timer ¬ NEW[TimerObject[0]];
freeList: REF EventObject ¬ NIL;
AllocEvent:
ENTRY
PROC [lock: Timer ¬ eventLock]
RETURNS [e: Event] ~ {
IF freeList =
NIL
THEN {
e.ref ¬ NEW[EventObject];
}
ELSE {
e.ref ¬ freeList;
freeList ¬ e.ref.next;
e.ref.next ¬ NIL;
};
e.gen ¬ e.ref.gen;
};
FreeEvent:
ENTRY
PROC [lock: Timer ¬ eventLock, re:
REF EventObject] ~ {
re.gen ¬ re.gen.SUCC;
re.next ¬ freeList;
freeList ¬ re;
};
DoEvents:
PROC [list:
REF EventObject, doCalls:
BOOL ¬
TRUE] ~ {
WHILE list #
NIL
DO
e: REF EventObject ¬ list;
clientData: REF ¬ e.clientData;
proc: EventProc ¬ e.proc;
list ¬ list.next;
IF (proc # NIL) AND doCalls THEN proc[clientData];
FreeEvent[eventLock, e];
ENDLOOP;
};
Daemon:
PROC [t: Timer] ~ {
ENABLE ABORTED => CONTINUE;
Process.SetPriority[Process.priorityClient3];
DO
list: REF EventObject ¬ EntryWaitForEvent[t];
DoEvents[list];
ENDLOOP;
};
Operations
CreateTimer:
PUBLIC
PROC [grainSizeMsec:
INT, expectedWaitMsec:
INT]
RETURNS [t: Timer]
~ {
sizeOfWheel: CARDINAL;
IF grainSizeMsec < 0 THEN ERROR Error[LIST[$badGrainSize], "negative grain size"];
grainSizeMsec ¬ MAX[msecPerTick, grainSizeMsec];
expectedWaitMsec ¬ MAX[expectedWaitMsec, grainSizeMsec];
sizeOfWheel ¬ expectedWaitMsec / grainSizeMsec;
IF sizeOfWheel < maxSizeOfWheel
THEN sizeOfWheel ¬ sizeOfWheel + sizeOfWheel/2;
sizeOfWheel ¬ MIN[sizeOfWheel, maxSizeOfWheel];
t ¬ NEW[TimerObject[sizeOfWheel]];
t.grainSizeMsec ¬ grainSizeMsec;
t.nextMsec ¬ MsecSinceBoot[];
TRUSTED { Process.EnableAborts[@t.wakeup] };
t.daemon ¬ FORK Daemon[t];
};
EntryDestroyTimer:
ENTRY
PROC [lock: Timer] ~ {
lock.destroyed ¬ TRUE;
};
DestroyTimer:
PUBLIC
PROC [t: Timer, doEvents:
BOOL] ~ {
p: PROCESS;
EntryDestroyTimer[t];
IF (p ¬ t.daemon) #
NIL
THEN
TRUSTED {
Process.Abort[p];
Process.Detach[p];
};
FOR i:
CARDINAL
IN [0..t.wheelSize)
DO
list: REF EventObject;
list ¬ t.wheel[i]; t.wheel[i] ¬ NIL;
DoEvents[list, doEvents];
ENDLOOP;
};
GrainSizeMsec: PUBLIC PROC [t: Timer] RETURNS [grainSizeMsec: INT]
~ { RETURN[t.grainSizeMsec] };
EntryScheduleEvent:
PUBLIC
ENTRY
PROC [lock: Timer, waitMsec:
INT, e: Event]
RETURNS [Event]
~ {
index: CARDINAL;
IF lock.destroyed THEN RETURN [CommTimer.nullEvent];
e.ref.whenMsec ¬ waitMsec + lock.nextMsec;
index ¬ ((waitMsec / lock.grainSizeMsec) + lock.wheelIndex) MOD lock.wheelSize;
e.ref.next ¬ lock.wheel[index];
lock.wheel[index] ¬ e.ref;
RETURN [e];
};
ScheduleEvent:
PUBLIC
PROC [t: Timer, waitMsec:
INT, proc: EventProc, clientData:
REF]
RETURNS [Event]
~ {
e: Event ¬ AllocEvent[eventLock];
e.ref.proc ¬ proc;
e.ref.clientData ¬ clientData;
IF waitMsec > 0
THEN {
e ¬ EntryScheduleEvent[t, waitMsec, e];
IF CommTimer.IsNullEvent[e] THEN ERROR Error[LIST[$staleTimer], "timer destroyed"];
}
ELSE {
DoEvents[e.ref];
};
RETURN[ e ];
};
EntryCancelEvent:
ENTRY
PROC [lock: Timer ¬ eventLock, e: Event] ~ {
IF e.gen # e.ref.gen THEN RETURN;
e.ref.proc ¬ NIL;
e.ref.clientData ¬ NIL;
};
CancelEvent:
PUBLIC
PROC [t: Timer, e: Event] ~ {
EntryCancelEvent[eventLock, e];
};
EntryMsecUntilOccurs:
ENTRY
PROC [lock: Timer ¬ eventLock, t: Timer, e: Event]
RETURNS [
INT] ~ {
RETURN[ IF e.ref.gen = e.gen THEN e.ref.whenMsec - t.nextMsec ELSE 0 ];
};
MsecUntilOccurs:
PUBLIC
PROC [t: Timer, e: Event]
RETURNS [
INT] ~ {
RETURN[ EntryMsecUntilOccurs[eventLock, t, e] ];
};
}.