Signals.mesa
last edited by Levin on March 11, 1983 4:43 pm
DIRECTORY
Environment USING [Byte],
Frame
USING [
Alloc, Free, GetReturnFrame,GetReturnLink, MyGlobalFrame,
MyLocalFrame, SetReturnLink],
Mopcodes USING [zCATCH, zJ2, zJ9, zJB, zJW, zKFCB, zPORTI, zSLB],
PrincOps
USING [
ControlLink, Frame, FrameHandle, localbase, NullFrame, NullLink,
StateVector, BytePC],
RuntimeInternal USING [Codebase],
RuntimePrograms USING [],
SDDefs
USING [
SD, sError, sErrorList, sReturnError, sReturnErrorList, sSignal,
sSignalList, sUncaughtSignal, sUnnamedError],
TemporarySignals USING [];
Signals:
PROGRAM
IMPORTS Frame, RuntimeInternal
EXPORTS RuntimeInternal, RuntimePrograms, TemporarySignals =
BEGIN
BYTE: TYPE = Environment.Byte;
CatchPointer: TYPE = POINTER TO catch PrincOps.Frame;
CatchCall: TYPE = PROCEDURE [SIGNAL] RETURNS [ActionCode];
CatchContinue: TYPE = PROCEDURE;
ActionCode:
TYPE =
INTEGER;
reject: ActionCode = 0;
resume: ActionCode = 1;
exit: ActionCode = -1;
SendMsgSignal: PUBLIC SIGNAL RETURNS [UNSPECIFIED, UNSPECIFIED] = CODE;
signalling: CARDINAL = 177777B;
notSignalling: CARDINAL = 0;
--RuntimePrograms.--
InitializeSignals:
PUBLIC
PROCEDURE [] =
BEGIN OPEN SDDefs;
pSD: POINTER TO ARRAY [0..0) OF UNSPECIFIED ← SD;
pSD[sSignalList] ← SignalList;
pSD[sSignal] ← Signal;
pSD[sErrorList] ← ErrorList;
pSD[sError] ← Error;
pSD[sReturnErrorList] ← ReturnErrorList;
pSD[sReturnError] ← ReturnError;
pSD[sUnnamedError] ← UnnamedError;
END;
MarkSignalFrame:
PROCEDURE [value:
CARDINAL] =
MACHINE CODE BEGIN Mopcodes.zSLB, 3 --OFFSET[mark]-- END;
SignalHandler:
PROCEDURE [signal:
SIGNAL, message:
UNSPECIFIED, informational:
BOOL ←
FALSE] =
BEGIN
SignalFrame: TYPE = POINTER TO FRAME[SignalHandler];
frame, nextFrame: PrincOps.FrameHandle;
target, nextTarget: PrincOps.FrameHandle;
self: PrincOps.FrameHandle = Frame.MyLocalFrame[];
start: PrincOps.FrameHandle;
catchFrame: CatchPointer;
action: ActionCode;
unwinding: BOOLEAN;
catchPhrase: BOOLEAN;
catchFSIndex: BYTE;
catchPC, exitPC: PrincOps.BytePC;
catchState: PrincOps.StateVector;
MarkSignalFrame[signalling]; unwinding ← FALSE;
start ← GetFrame[self.returnlink]; target ← PrincOps.NullFrame;
DO
nextFrame ← start;
UNTIL nextFrame = target DO
frame ← nextFrame;
IF frame.accesslink = Frame.MyGlobalFrame[]
AND frame.mark
THEN
BEGIN
OPEN thisSignaller: LOOPHOLE[frame, SignalFrame];
IF unwinding
THEN
BEGIN
IF signal = thisSignaller.signal
THEN
nextTarget ←
IF thisSignaller.unwinding
THEN thisSignaller.nextTarget
ELSE thisSignaller.nextFrame;
IF thisSignaller.unwinding
THEN
BEGIN
IF thisSignaller.frame =
LOOPHOLE[frame.returnlink]
THEN
frame.returnlink ← [frame[thisSignaller.nextFrame]];
Frame.Free[thisSignaller.frame];
END;
nextFrame ← GetFrame[frame.returnlink];
END
ELSE
nextFrame ←
IF signal # thisSignaller.signal
THEN
IF thisSignaller.unwinding
THEN thisSignaller.nextFrame
ELSE GetFrame[frame.returnlink]
ELSE
IF thisSignaller.unwinding
THEN thisSignaller.nextTarget
ELSE thisSignaller.nextFrame;
END
ELSE nextFrame ← GetFrame[frame.returnlink];
IF unwinding AND nextTarget = frame THEN nextTarget ← nextFrame;
[catchPhrase, catchFSIndex, catchPC] ← CheckCatch[frame];
IF catchPhrase
THEN
BEGIN
catchFrame ← Frame.Alloc[catchFSIndex];
catchFrame^ ← PrincOps.Frame[
accesslink: frame.accesslink,
pc: catchPC,
returnlink: [frame[self]],
extensions: catch[unused: ,
staticlink: frame+PrincOps.localbase, messageval: message]];
action ←
LOOPHOLE[catchFrame, CatchCall]
[
IF unwinding
THEN
LOOPHOLE[
UNWIND]
ELSE signal
! SendMsgSignal => RESUME[message, signal]];
catchState ← STATE;
SELECT action
FROM
reject => NULL;
resume =>
IF unwinding
THEN ERROR ResumeError
ELSE
BEGIN
catchState.dest ← Frame.GetReturnLink[];
catchState.source ← PrincOps.NullLink;
RETURN WITH catchState;
END;
exit =>
IF ~informational
THEN
BEGIN
catchFrame is waiting to execute its exit jump
exitPC ← catchFrame.pc;
Frame.Free[catchFrame];
target ← LOOPHOLE[catchState.stk[0]-PrincOps.localbase];
nextTarget ← nextFrame;
unwinding ← TRUE; message ← NIL;
GO TO StartUnwind;
END;
ENDCASE;
END;
IF unwinding
THEN
BEGIN
IF frame = start THEN start ← nextFrame;
IF frame =
LOOPHOLE[self.returnlink]
THEN self.returnlink ← [frame[nextFrame]];
Frame.Free[frame];
END;
REPEAT
StartUnwind => NULL;
FINISHED => EXIT
ENDLOOP;
ENDLOOP;
SELECT
TRUE
FROM
unwinding => target.pc ← exitPC;
informational => NULL;
ENDCASE => UncaughtSignal[message, signal, frame]; -- formerly Punted if no uncaught signal catcher
RETURN
END;
CheckCatch:
PROCEDURE [frame: PrincOps.FrameHandle]
RETURNS [catchPhrase: BOOLEAN, fsIndex: BYTE, pc: PrincOps.BytePC] =
BEGIN OPEN Mopcodes;
code: LONG POINTER TO PACKED ARRAY [0..0) OF BYTE;
MarkSignalFrame[notSignalling];
code ← RuntimeInternal.Codebase[LOOPHOLE[frame.accesslink, PROGRAM]];
pc ← [frame.pc];
DO
SELECT code[pc]
FROM
zCATCH => BEGIN catchPhrase ← TRUE; EXIT END;
zPORTI => pc ← [pc + 1];
ENDCASE => BEGIN catchPhrase ← FALSE; EXIT END
ENDLOOP;
IF catchPhrase
THEN
BEGIN -- code[pc] points at zCatch
fsIndex ← code[pc+1];
SELECT code[pc ← [pc+2]]
FROM
zJB => pc ← [pc + 2];
IN [zJ2..zJ9] => pc ← [pc + 1];
zJW => pc ← [pc + 3];
ENDCASE
END;
RETURN
END;
GetFrame:
PROCEDURE [link: PrincOps.ControlLink]
RETURNS [PrincOps.FrameHandle] =
BEGIN
MarkSignalFrame[notSignalling];
DO
IF ~link.proc
THEN
IF link.indirect THEN link ← link.link^
ELSE --frame link-- RETURN[link.frame]
ELSE RETURN[PrincOps.NullFrame];
ENDLOOP;
END;
Signal:
PROCEDURE [signal:
SIGNAL, message:
UNSPECIFIED] =
BEGIN
MarkSignalFrame[notSignalling];
SignalHandler[signal, message];
END;
SignalList:
PROCEDURE [signal:
SIGNAL, message:
POINTER
TO
UNSPECIFIED] =
BEGIN
MarkSignalFrame[notSignalling];
SignalHandler[signal, message ! UNWIND => Frame.Free[message]];
Frame.Free[message];
RETURN
END;
-- Provisional informational signal logic --
InformationalSignal:
PUBLIC
PROCEDURE [signal:
SIGNAL] =
BEGIN
MarkSignalFrame[notSignalling];
SignalHandler[signal, -1, TRUE];
END;
ResumeError: PUBLIC SIGNAL = CODE;
Error:
PROCEDURE [signal:
SIGNAL, message:
UNSPECIFIED] =
BEGIN
MarkSignalFrame[notSignalling];
SignalHandler[signal, message];
ERROR ResumeError
END;
ErrorList:
PROCEDURE [signal:
SIGNAL, message:
POINTER
TO
UNSPECIFIED] =
BEGIN
MarkSignalFrame[notSignalling];
SignalHandler[signal, message !
UNWIND => Frame.Free[message]];
Frame.Free[message];
ERROR ResumeError
END;
ReturnError:
PROCEDURE [signal:
SIGNAL, message:
UNSPECIFIED] =
BEGIN
caller: PrincOps.FrameHandle = Frame.GetReturnFrame[];
Frame.SetReturnLink[caller.returnlink];
MarkSignalFrame[notSignalling];
SignalHandler[signal, message !
UNWIND => Frame.Free[caller]];
Frame.Free[caller];
ERROR ResumeError
END;
ReturnErrorList:
PROCEDURE [signal:
SIGNAL, message:
POINTER
TO
UNSPECIFIED] =
BEGIN
caller: PrincOps.FrameHandle = Frame.GetReturnFrame[];
Frame.SetReturnLink[caller.returnlink];
MarkSignalFrame[notSignalling];
SignalHandler[signal, message !
UNWIND => { Frame.Free[caller]; Frame.Free[message]; }];
Frame.Free[caller];
Frame.Free[message];
ERROR ResumeError
END;
UnnamedError:
PROCEDURE =
BEGIN
MarkSignalFrame[notSignalling];
SignalHandler[LOOPHOLE[-1], -1];
ERROR ResumeError
END;
UncaughtSignal:
PROCEDURE [msg, signal:
UNSPECIFIED, frame: PrincOps.FrameHandle] =
MACHINE CODE BEGIN Mopcodes.zKFCB, SDDefs.sUncaughtSignal END;
END.