-- 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.