-- CedarSnapshotRegistry.mesa
-- last edited by Levin: September 7, 1982 1:00 pm
DIRECTORY
CedarSnapshot USING [CheckpointProc, RollbackProc],
CedarSnapshotPrivate USING [],
Heap USING [systemZone],
Inline USING [LongCOPY];
CedarSnapshotRegistry: MONITOR
IMPORTS Heap, Inline
EXPORTS CedarSnapshot, CedarSnapshotPrivate =
BEGIN
Registry: TYPE = LONG POINTER TO Procs;
Procs: TYPE = RECORD [
nProcs: CARDINAL ← 0,
procs: SEQUENCE nSlots: CARDINAL OF RegisteredProc ← NULL];
RegisteredProc: TYPE = PROC;
initialProcs: CARDINAL = 10;
incrementProcs: CARDINAL = 5;
checkpointRegistry, rollbackRegistry: Registry ← NIL;
ProcAlreadyRegistered: ERROR = CODE;
ProcNotRegistered: ERROR = CODE;
-- Procedures exported to CedarSnapshot
Register: PUBLIC ENTRY PROC [
c: CedarSnapshot.CheckpointProc ← NIL, r: CedarSnapshot.RollbackProc ← NIL] =
{AddProc[@checkpointRegistry, LOOPHOLE[c]]; AddProc[@rollbackRegistry, LOOPHOLE[r]]};
Deregister: PUBLIC ENTRY PROC [
c: CedarSnapshot.CheckpointProc ← NIL, r: CedarSnapshot.RollbackProc ← NIL] =
{RemoveProc[@checkpointRegistry, LOOPHOLE[c]]; RemoveProc[@rollbackRegistry, LOOPHOLE[r]]};
-- Procedures exported to CedarSnapshotPrivate
-- The enumerators call the caller-supplied procedure outside the monitor, permitting
-- Register/Deregister to be called from within the enumeration.
EnumerateCheckpointProcs: PUBLIC PROC [proc: PROC [CedarSnapshot.CheckpointProc]] = {
i: CARDINAL ← LAST[CARDINAL];
p: CedarSnapshot.CheckpointProc;
GetNext: ENTRY PROC RETURNS [p: CedarSnapshot.CheckpointProc] = INLINE {
p ← NIL;
i ← MIN[i, checkpointRegistry.nProcs];
IF i > 0 THEN {
i ← i - 1;
p ← LOOPHOLE[checkpointRegistry.procs[i]];
};
};
IF checkpointRegistry = NIL THEN RETURN;
UNTIL (p ← GetNext[]) = NIL DO proc[p]; ENDLOOP;
};
EnumerateRollbackProcs: PUBLIC PROC [proc: PROC [CedarSnapshot.RollbackProc]] = {
i: CARDINAL ← 0;
p: CedarSnapshot.RollbackProc;
GetNext: ENTRY PROC RETURNS [p: CedarSnapshot.RollbackProc] = INLINE {
p ← NIL;
IF i < rollbackRegistry.nProcs THEN {
p ← LOOPHOLE[rollbackRegistry.procs[i]];
i ← i + 1;
};
};
IF rollbackRegistry = NIL THEN RETURN;
UNTIL (p ← GetNext[]) = NIL DO proc[p]; ENDLOOP;
};
-- Private Procedures
AddProc: INTERNAL PROC [registry: LONG POINTER TO Registry, proc: RegisteredProc] = {
IF proc = NIL THEN RETURN;
IF registry↑ = NIL THEN registry↑ ← Heap.systemZone.NEW[Procs[initialProcs] ← []];
FOR i: CARDINAL IN [0..registry↑.nProcs) DO
IF registry↑.procs[i] = proc THEN ERROR ProcAlreadyRegistered;
ENDLOOP;
IF registry↑.nProcs = registry↑.nSlots THEN {
newRegistry: Registry ←
Heap.systemZone.NEW[Procs[registry↑.nSlots+incrementProcs] ← [nProcs: registry↑.nProcs]];
Inline.LongCOPY[from: @registry↑.procs[0], to: @newRegistry.procs[0],
nwords: registry↑.nSlots*SIZE[RegisteredProc]];
Heap.systemZone.FREE[registry];
registry↑ ← newRegistry;
};
registry↑.procs[registry↑.nProcs] ← proc;
registry↑.nProcs ← registry↑.nProcs + 1;
};
RemoveProc: INTERNAL PROC [registry: LONG POINTER TO Registry, proc: RegisteredProc] = {
state: {looking, compressing} ← looking;
FOR i: CARDINAL IN [0..registry↑.nProcs) DO
SELECT state FROM
looking => IF registry↑.procs[i] = proc THEN state ← compressing;
compressing => registry↑.procs[i - 1] ← registry↑.procs[i];
ENDCASE;
ENDLOOP;
IF state = looking THEN ERROR ProcNotRegistered;
registry↑.nProcs ← registry↑.nProcs - 1;
};
END.