-- MesaRuntime>Signals.mesa (November 21, 1982 10:47 am by Levin) 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. LOG August 7, 1978 8:57 AM Sandman Got Codebase from RuntimeInternal instead of CodebaseDefs. August 30, 1978 2:06 PM Sandman Removed TrapDefs and PuntMesa. March 13, 1979 3:15 PM McJones Mesa 5. April 4, 1979 11:02 AM McJones Added (conditional) BytePC logic. September 21, 1979 2:37 PM McJones Removed (conditional) BytePC logic. May 3, 1980 11:07 AM Forrest Mesa 6.0 Conversion. January 15, 1981 4:09 PM Knutsen InitizeSignals[]. February 4, 1981 1:05 PM Knutsen PrincOps fields changed names. November 21, 1982 10:47 am Levin Add provisional informational signal stuff.