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 UNSPECIFIEDSD;
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: BOOLFALSE] =
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.