-- RTStopProcessImpl.Mesa
-- last edited September 9, 1982 7:49 am by Paul Rovner
DIRECTORY
Process USING[Abort, Priority, priorityForeground],
ProcessOperations USING[IndexToHandle],
PSB USING[PDA],
RTBasic USING[TV],
RTProcess USING[Status, Valid, InvalidProcess, HandleToPSBI],
RTProcessPrivate USING[ProcessObject];
RTStopProcessImpl: MONITOR LOCKS h USING h: Handle
IMPORTS Process, ProcessOperations, RTProcess
EXPORTS RTProcess
= BEGIN OPEN RTProcess;
-- types
Handle: TYPE = REF Object;
Object: PUBLIC TYPE = RTProcessPrivate.ProcessObject;
-- SIGNALs
NotStopped: PUBLIC SIGNAL[h: Handle] = CODE;
InvalidPriority: PUBLIC SIGNAL[h: Handle, p: Process.Priority] = CODE;
NIY: SIGNAL = CODE;
-- PROCs
GetStatus: PUBLIC PROC[h: Handle] RETURNS[RTProcess.Status] =
{ IF NOT Valid[h] THEN RETURN[invalid];
IF h.stopState = stopped THEN RETURN[stopped];
ERROR NIY
};
Stop: PUBLIC PROC[h: Handle] =
{ IF NOT Valid[h] THEN ERROR InvalidProcess[h];
IF h.stopState # stoppable THEN RETURN;
-- Wait for h's priority to be <= Process.priorityForeground, then grab it with the Sponge.
-- Scan h's call stack until a client module is found, find the next clean point there and place a client BP
h.stopState ← stopping;
-- release the sponge
-- NOTE: Some time later, when the client BP is hit by the client process, remove the BP, h.stopState ← stopped, and cause the client process to WAIT h.resume.
};
Proceed: PUBLIC ENTRY PROC[h: Handle] =
{ IF NOT Valid[h] THEN ERROR InvalidProcess[h];
IF h.stopState = stopped
THEN {h.stopState ← stoppable; NOTIFY h.resume}
ELSE IF h.stopState = stopping
THEN {h.stopState ← stoppable;
-- remove the BP
}
ELSE SIGNAL NotStopped[h];
};
-- raises NotStopped
ReturnFrom: PUBLIC ENTRY PROC[h: Handle, frameFromWhichToReturn: RTBasic.TV, result: RTBasic.TV ← NIL] =
{ IF NOT Valid[h] THEN ERROR InvalidProcess[h];
IF h.stopState = stopped
THEN {h.stopState ← unwinding;
--remember "frameFromWhichToReturn" and "result";
Process.Abort[HandleToPSBI[h]]} -- NOTE 1, NOTE 3
ELSE SIGNAL NotStopped[h]; -- NOTE 2
};
-- raises NotStopped
Abort: PUBLIC ENTRY PROC[h: Handle] =
{ IF NOT Valid[h] THEN ERROR InvalidProcess[h];
IF h.stopState = stopped
THEN {h.stopState ← aborting;
Process.Abort[HandleToPSBI[h]]} -- NOTE 1, NOTE 3
ELSE IF h.stopState = stopping --and h is waiting on a CV
THEN {--remove the BP;
Process.Abort[HandleToPSBI[h]]}
ELSE SIGNAL NotStopped[h]; -- NOTE 2
};
-- raises NotStopped
TopFrame: PUBLIC PROC[h: Handle] RETURNS[RTBasic.TV--for a frame--] =
{ IF NOT Valid[h] THEN ERROR InvalidProcess[h];
IF h.stopState = stopped
THEN RETURN[NIL--find h's top client frame (skip back over BP handler frames)--]
ELSE IF h.stopState = stopping
THEN ERROR
ELSE ERROR NotStopped[h];
};
-- raises NotStopped, InvalidPriority, InvalidProcess
ChangePriority: PUBLIC PROC[h: Handle, new: Process.Priority]
RETURNS[old: Process.Priority] =
{ IF NOT Valid[h] THEN ERROR InvalidProcess[h];
IF new > Process.priorityForeground THEN ERROR InvalidPriority[h, new];
old ← PSB.PDA[ProcessOperations.IndexToHandle[HandleToPSBI[h]]].link.priority;
IF h.stopState = stopped
THEN SIGNAL NIY -- NOTE change h's priority: must its PSB be moved among system queues?
ELSE SIGNAL NotStopped[h]; -- NOTE 2
};
-- NOTE 1: Current catch phrases in the frame where the client BP was placed will not be executed.
-- In particular, ENABLE UNWIND => NULL in an ENTRY frame will not be executed, hence the monitor
-- lock will not be released. This will be fixed when the new instruction set is installed.
-- NOTE 2: The process may not have hit the BP yet, especially if it is still WAITing on a
-- CV or to enter a MONITOR.
-- NOTE 3: A catch phrase for ABORT in the stopper will
-- IF h.stopState = unwinding
-- THEN unwind frames through "frameFromWhichToReturn";
-- h.stopState ← stoppable;
-- fix the PSB (which was marked "aborted");
-- stuff "result" into a result record and return to the caller of "frameFromWhichToReturn"
-- ELSE IF h.stopState = aborting
-- THEN NULL
-- ELSE ERROR;
END.