-- File: CedarSnapshotCork.mesa -- last edited by Levin: November 9, 1982 4:16 pm DIRECTORY CedarSnapshotPrivate USING [], Environment USING [Base], Process USING [ DisableTimeout, GetPriority, InitializeCondition, InitializeMonitor, Priority, SetPriority --, Yield--], ProcessInternal USING [DisableInterrupts], ProcessOperations USING [EnableAndRequeue, ReadPSB], ProcessPriorities USING [priorityPageFaultLow], PSB USING [PDA], ResidentHeap USING [first64K, FreeNode, MakeNode], SpecialSpace USING [MakeProcedureResident, MakeProcedureSwappable], Zone USING [Status]; CedarSnapshotCork: MONITOR LOCKS corkHandle.LOCK USING corkHandle: CorkHandle IMPORTS Process, ProcessInternal, ProcessOperations, ResidentHeap, SpecialSpace EXPORTS CedarSnapshotPrivate = BEGIN -- We would like to keep the variables associated with the corking in the global frame and -- protect them in the obvious way with a module monitor. However, since 'state' and -- 'stateChange' must be resident (since the whole purpose of the Cork is to be runnable -- always and therefore never fault), the global frame would have to be pinned. We could -- arrange to package the CedarSnapshotImpl configuration to permit just this global frame -- to be pinned, but that's a considerable aggravation. (If we forge ahead fearlessly and -- call SpecialSpace.MakeGlobalFrameResident[CedarSnapshotCork], we will pin the entire -- configuration in which CedarSnapshotImpl is bound, because of the way MakeBoot and the -- space machinery work.) So, we instead allocate a small hunk of storage from ResidentHeap. -- If this configuration is ever packaged for other reasons, the code should be reworked to -- use variables in the global frame and a simple module monitor. CorkHandle: TYPE = LONG POINTER TO CorkObject; CorkRP: TYPE = Environment.Base RELATIVE POINTER TO CorkObject; CorkObject: PUBLIC TYPE = MONITORED RECORD [ oldPriority: Process.Priority, state: {initial, corked, uncork} _ initial, stateChange: CONDITION _ [timeout: 0], cork: PROCESS _ NULL, self: CorkRP ]; CorkRestOfWorld: PUBLIC PROC RETURNS [corkHandle: CorkHandle] = { EnsureCorked: ENTRY PROC [corkHandle: CorkHandle] = INLINE { corkHandle.cork _ FORK Cork[corkHandle]; UNTIL corkHandle.state = corked DO WAIT corkHandle.stateChange; ENDLOOP; }; corkRP: CorkRP; status: Zone.Status; [corkRP, status] _ ResidentHeap.MakeNode[SIZE[CorkObject]]; IF status ~= okay THEN ERROR; corkHandle _ @ResidentHeap.first64K[corkRP]; -- compiler won't permit: corkHandle^ _ [oldPriority: Process.GetPriority[], self: corkRP]; Process.InitializeMonitor[@corkHandle.LOCK]; corkHandle.oldPriority _ Process.GetPriority[]; corkHandle.state _ initial; Process.InitializeCondition[@corkHandle.stateChange, 0]; Process.DisableTimeout[@corkHandle.stateChange]; corkHandle.self _ corkRP; Process.SetPriority[ProcessPriorities.priorityPageFaultLow]; EnsureCorked[corkHandle]; -- The cork is now at the head of the ready list for priorityPageFaultLow, -- and since it never faults, it yields only to its own priority level, -- so nothing below priorityPageFaultLow will run. This is assumed to -- include the Ethernet driver(s), Cedar runtime processes, and anything -- else that uses the Space machinery. Note: we are careful not to use -- Heap.systemZone when the Cork is operational, since there is a small -- chance that one of the processes preempted by the Cork is holding the -- monitor for this zone. (Of course, some preempted processes may be -- holding other Pilot monitors, e.g., those in the FileMgr, but we -- can't do anything about that ... except hope for the best.) }; UncorkRestOfWorld: PUBLIC PROC [corkHandle: CorkHandle] = { IF corkHandle = NIL THEN RETURN; corkHandle.state _ uncork; JOIN corkHandle.cork; Process.SetPriority[corkHandle.oldPriority]; IF ResidentHeap.FreeNode[corkHandle.self] ~= okay THEN ERROR; }; Cork: PROC [corkHandle: CorkHandle] = { AnnounceCorked: ENTRY PROC [corkHandle: CorkHandle] = INLINE { corkHandle.state _ corked; NOTIFY corkHandle.stateChange; }; Yield: PROC = { -- stolen from Processes to ensure residency ProcessInternal.DisableInterrupts[]; ProcessOperations.EnableAndRequeue[@PSB.PDA.ready, @PSB.PDA.ready, ProcessOperations.ReadPSB[]]; }; -- implicit in FORK: Process.SetPriority[ProcessPriorities.priorityPageFaultLow]; SpecialSpace.MakeProcedureResident[Cork]; AnnounceCorked[corkHandle]; UNTIL corkHandle.state = uncork DO --Process.--Yield[]; ENDLOOP; SpecialSpace.MakeProcedureSwappable[Cork]; }; END.