DIRECTORY Process, Xl, XlTimeEvents; XlTimeEventsImpl: CEDAR MONITOR IMPORTS Process, Xl EXPORTS XlTimeEvents ~ BEGIN OPEN XlTimeEvents; actualTicks: PUBLIC CARD32 ¬ TicksSinceBoot[]; --May be late; see below. mSecPerFastTick: PUBLIC CARD32 ¬ MAX[TicksToMsec[700]/1000, 1]; --makes clock slow tehQueue: TEHandle ¬ NIL; fakeLimit: CARD32 ¬ Process.SecondsToTicks[3]; --limit the time period when timeout events are sent to limit actions of a quiescent system. fakeEvent: REF Xl.EventRep.local ~ NewFakeEvent[]; --used in case client checks event type NewFakeEvent: PROC [] RETURNS [e: REF Xl.EventRep.local] = { e ¬ NEW[Xl.EventRep.local]; e.who ¬ $TimeEnforcer }; TicksSinceBoot: PROC [] RETURNS [CARD32] = TRUSTED MACHINE CODE { "XR_TicksSinceBoot" }; TicksToMsec: PROC [t: CARD32] RETURNS [CARD32] = TRUSTED MACHINE CODE { "XR_TicksToMsec" }; NilProc: Xl.EventProcType = {}; Create: PUBLIC PROC [reportTQ: Xl.TQ, reportProc: Xl.EventProcType, reportData: REF ¬ NIL] RETURNS [teh: TEHandle] = { IF reportProc=NIL THEN reportProc ¬ NilProc; IF reportTQ=NIL THEN ERROR; teh ¬ NEW[TEHandleRec ¬ [tq: reportTQ, proc: reportProc, data: reportData]]; }; RealActivate: PUBLIC ENTRY PROC [teh: TEHandle] = { teh.active ¬ TRUE; IF ~teh.enqueued THEN { teh.enqueued ¬ TRUE; teh.next ¬ tehQueue; tehQueue ¬ teh }; }; Cleanup: PUBLIC ENTRY PROC = { WHILE tehQueue#NIL AND ~tehQueue.active DO teh: TEHandle ¬ tehQueue; teh.enqueued ¬ FALSE; tehQueue ¬ teh.next; teh.next ¬ NIL; ENDLOOP; BEGIN lag: TEHandle ¬ tehQueue; IF lag#NIL THEN { WHILE lag.next#NIL DO IF lag.next.active THEN lag ¬ lag.next ELSE { teh: TEHandle ¬ lag.next; teh.enqueued ¬ FALSE; lag.next ¬ teh.next; teh.next ¬ NIL; }; ENDLOOP }; END; }; TimeEnforceProcess: PROC [] = { count: INT ¬ 0; lastTicks: CARD32 ¬ actualTicks; thisTicks: CARD32 ¬ actualTicks; deltaTicks: Process.Ticks ~ MAX[Process.MsecToTicks[30], 1]; --pause length, set small maxDeltaTicks: CARD32 ~ MAX[Process.MsecToTicks[30], 1]; --prevent propagating fast clock; >=deltaTicks Process.SetPriority[Process.priorityClient3]; DO --forever Process.Pause[deltaTicks]; IF count<100 THEN count ¬ count+1 ELSE {count ¬ 0; Cleanup[]}; thisTicks ¬ TicksSinceBoot[]; actualTicks ¬ actualTicks + MIN[maxDeltaTicks, thisTicks-lastTicks]; lastTicks ¬ thisTicks; FOR teh: TEHandle ¬ tehQueue, teh.next WHILE teh#NIL DO IF teh.active THEN Visit[teh]; ENDLOOP; ENDLOOP; }; Visit: PROC [teh: TEHandle] = { IF teh.baseValid THEN { Xl.Enqueue[teh.tq, teh.proc, teh.data, fakeEvent]; IF (actualTicks-teh.lastWound <> ) > fakeLimit THEN { Xl.Enqueue[teh.tq, DeActivator, teh, fakeEvent]; }; } ELSE { teh.baseValid ¬ TRUE; teh.lastActualTicks ¬ actualTicks }; }; DeActivator: Xl.EventProcType = { teh: TEHandle ~ NARROW[clientData]; IF (actualTicks-teh.lastWound <> ) > fakeLimit THEN { teh.active ¬ FALSE }; }; TRUSTED {Process.Detach[FORK TimeEnforceProcess[]]}; END. J XlTimeEventsImpl.mesa Copyright Σ 1991, 1992 by Xerox Corporation. All rights reserved. Created by Christian Jacobi, September 26, 1991 4:33:22 pm PDT Christian Jacobi, May 28, 1993 12:54 pm PDT Actual PCR might temporarily make its clock run very fast to catch up missed interupts. We will simply ignore advancement larger then a certain limit. This limit may be too high and therefore not prevent actualTicks from temporarily running fast. However this limits the amount by which actualTicks may run fast to a period smaller then fakeLimit. --Removes inactive handles from list inspected at each wakeup --only visit if waiting at least a full delta to guarantee slowness of artificial clock --Use clients thread because of monitoring convention --De-activate on the clients thread so teh.active is monitored against Activate Κο•NewlineDelimiter –(cedarcode) style™codešœ™Kšœ Οeœ7™BKšœ>™>K™+K™—šΟk œ˜ Kšœ˜Kšœ˜Kšœ ˜ K˜—šΟnœžœž˜Kšžœ ˜Kšžœ˜—Kšžœžœ˜K˜šœ žœžœΟc˜HJšœΰ™ΰK˜—Kšœž œžœ ˜RKšœžœ˜Kšœ žœ \˜Œšœ žœ% '˜ZšŸ œžœžœžœ˜