<> <> <> <> DIRECTORY Basics USING [BYTE], MesaRuntimeInit USING [], PrincOps USING [BytePC, ControlLink, --FieldDescriptor, --Frame, FrameHandle, localbase, markOffset, NullFrame, NullLink, RawBytes, SD, sError, sErrorList, sReturnError, sReturnErrorList, sSignal, sSignalList, StateVector, sUnnamedError, zCATCH, zJ2, zJ9, zJB, zJW, zLADRB, zPORTI, zWF], PrincOpsUtils USING [Alloc, Codebase, Free, GetReturnFrame, GetReturnLink, MyGlobalFrame, MyLocalFrame, SetReturnLink], RuntimeError USING [UCSProc]; SignalsImpl: MONITOR IMPORTS PrincOpsUtils EXPORTS MesaRuntimeInit, RuntimeError = BEGIN <<>> <> <<>> BYTE: TYPE = Basics.BYTE; CatchPointer: TYPE = POINTER TO catch PrincOps.Frame; CatchCall: TYPE = PROC [SIGNAL ANY RETURNS ANY] RETURNS [ActionCode]; CatchContinue: TYPE = PROC; ActionCode: TYPE = INTEGER; reject: ActionCode = 0; resume: ActionCode = 1; exit: ActionCode = -1; <> <<>> ucsHandler: RuntimeError.UCSProc _ NIL; <<>> <> <<>> SendMsgSignal: PUBLIC SIGNAL RETURNS [message: WORD, signal: SIGNAL ANY RETURNS ANY] = CODE; ResumeError: PUBLIC SIGNAL = CODE; UNCAUGHT: PUBLIC ERROR [signal: SIGNAL ANY RETURNS ANY, parameters: WORD] = CODE; InformationalSignal: PUBLIC SAFE PROC [signal: SIGNAL] = TRUSTED { MarkSignalHandlerFrame[FALSE]; SignalHandler[signal, LOOPHOLE[-1], TRUE]; }; RegisterUncaughtSignalHandler: PUBLIC ENTRY PROC [proc: RuntimeError.UCSProc] RETURNS [old: RuntimeError.UCSProc] = { old _ ucsHandler; ucsHandler _ proc; }; <<>> <> <<>> Error: PROC [signal: SIGNAL ANY RETURNS ANY, message: WORD] = { MarkSignalHandlerFrame[FALSE]; SignalHandler[signal, message]; ERROR ResumeError }; ErrorList: PROC [signal: SIGNAL ANY RETURNS ANY, message: POINTER TO WORD] = { MarkSignalHandlerFrame[FALSE]; SignalHandler[signal, LOOPHOLE[message] ! UNWIND => PrincOpsUtils.Free[message]]; PrincOpsUtils.Free[message]; ERROR ResumeError }; ReturnError: PROC [signal: SIGNAL ANY RETURNS ANY, message: WORD] = { caller: PrincOps.FrameHandle = PrincOpsUtils.GetReturnFrame[]; PrincOpsUtils.SetReturnLink[caller.returnlink]; MarkSignalHandlerFrame[FALSE]; SignalHandler[signal, message ! UNWIND => PrincOpsUtils.Free[caller]]; PrincOpsUtils.Free[caller]; ERROR ResumeError }; ReturnErrorList: PROC [signal: SIGNAL ANY RETURNS ANY, message: POINTER TO WORD] = { caller: PrincOps.FrameHandle = PrincOpsUtils.GetReturnFrame[]; PrincOpsUtils.SetReturnLink[caller.returnlink]; MarkSignalHandlerFrame[FALSE]; SignalHandler[signal, LOOPHOLE[message] ! UNWIND => {PrincOpsUtils.Free[caller]; PrincOpsUtils.Free[message]} ]; PrincOpsUtils.Free[caller]; PrincOpsUtils.Free[message]; ERROR ResumeError }; UnnamedError: PROC = { MarkSignalHandlerFrame[FALSE]; SignalHandler[LOOPHOLE[-1], LOOPHOLE[-1]]; ERROR ResumeError }; Signal: PROC [signal: SIGNAL ANY RETURNS ANY, message: WORD] = { MarkSignalHandlerFrame[FALSE]; SignalHandler[signal, message]; }; SignalList: PROC [signal: SIGNAL ANY RETURNS ANY, message: POINTER TO WORD] = { MarkSignalHandlerFrame[FALSE]; SignalHandler[signal, LOOPHOLE[message] ! UNWIND => PrincOpsUtils.Free[message]]; PrincOpsUtils.Free[message]; }; <<>> <> MarkSignalHandlerFrame: PROC [value: BOOL] = MACHINE CODE { PrincOps.zLADRB, 0; PrincOps.zWF, --PrincOps.FieldDescriptor[offset: PrincOps.markOffset, posn: 0, size: 1]-- PrincOps.markOffset, 0; }; SignalHandler: PROC [signal: SIGNAL ANY RETURNS ANY, message: WORD, informational: BOOL _ FALSE] = { SignalFrame: TYPE = POINTER TO FRAME[SignalHandler]; frame, nextFrame: PrincOps.FrameHandle; target, nextTarget: PrincOps.FrameHandle; self: PrincOps.FrameHandle = PrincOpsUtils.MyLocalFrame[]; start: PrincOps.FrameHandle; catchFrame: CatchPointer; action: ActionCode; unwinding: BOOL; catchPhrase: BOOL; catchFSIndex: BYTE; catchPC, exitPC: PrincOps.BytePC; catchState: PrincOps.StateVector; MarkSignalHandlerFrame[TRUE]; unwinding _ FALSE; start _ GetFrame[self.returnlink]; target _ PrincOps.NullFrame; DO nextFrame _ start; UNTIL nextFrame = target DO frame _ nextFrame; IF frame.accesslink = PrincOpsUtils.MyGlobalFrame[] AND frame.mark THEN { OPEN thisSignaller: LOOPHOLE[frame, SignalFrame]; IF unwinding THEN { IF signal = thisSignaller.signal THEN nextTarget _ IF thisSignaller.unwinding THEN thisSignaller.nextTarget ELSE thisSignaller.nextFrame; IF thisSignaller.unwinding THEN { IF thisSignaller.frame = LOOPHOLE[frame.returnlink] THEN frame.returnlink _ [frame[thisSignaller.nextFrame]]; PrincOpsUtils.Free[thisSignaller.frame]; }; nextFrame _ GetFrame[frame.returnlink]; } 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; } ELSE nextFrame _ GetFrame[frame.returnlink]; IF unwinding AND nextTarget = frame THEN nextTarget _ nextFrame; [catchPhrase, catchFSIndex, catchPC] _ CheckCatch[frame]; IF catchPhrase THEN { catchFrame _ PrincOpsUtils.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 { catchState.dest _ PrincOpsUtils.GetReturnLink[]; catchState.source _ PrincOps.NullLink; RETURN WITH catchState }; exit => IF ~informational THEN { <> exitPC _ catchFrame.pc; PrincOpsUtils.Free[catchFrame]; target _ LOOPHOLE[catchState.stk[0]-PrincOps.localbase]; nextTarget _ nextFrame; unwinding _ TRUE; message _ 0; GO TO StartUnwind; }; ENDCASE; }; IF unwinding THEN { IF frame = start THEN start _ nextFrame; IF frame = LOOPHOLE[self.returnlink] THEN self.returnlink _ [frame[nextFrame]]; PrincOpsUtils.Free[frame]; }; REPEAT StartUnwind => NULL; FINISHED => EXIT ENDLOOP; ENDLOOP; SELECT TRUE FROM unwinding => target.pc _ exitPC; informational OR signal = LOOPHOLE[UNCAUGHT] => NULL; -- does an implicit RESUME ENDCASE => { <> Uncaught: TYPE = SIGNAL [SIGNAL ANY RETURNS ANY, WORD]; LOOPHOLE[UNCAUGHT, Uncaught][signal, message]; ucsHandler[message, signal, frame]; }; }; CheckCatch: PROC [frame: PrincOps.FrameHandle] RETURNS [catchPhrase: BOOL, fsIndex: BYTE, pc: PrincOps.BytePC] = { code: LONG POINTER TO PrincOps.RawBytes; MarkSignalHandlerFrame[FALSE]; code _ LOOPHOLE[PrincOpsUtils.Codebase[frame.accesslink]]; pc _ [frame.pc]; DO SELECT code[pc] FROM PrincOps.zCATCH => {catchPhrase _ TRUE; EXIT}; PrincOps.zPORTI => pc _ [pc + 1]; ENDCASE => {catchPhrase _ FALSE; EXIT}; ENDLOOP; IF catchPhrase THEN { <> fsIndex _ code[pc+1]; SELECT code[pc _ [pc+2]] FROM PrincOps.zJB => pc _ [pc + 2]; IN [PrincOps.zJ2..PrincOps.zJ9] => pc _ [pc + 1]; PrincOps.zJW => pc _ [pc + 3]; ENDCASE; }; }; GetFrame: PROC [link: PrincOps.ControlLink] RETURNS [PrincOps.FrameHandle] = { <> DO IF ~link.proc THEN IF link.indirect THEN link _ link.link^ ELSE --frame link-- RETURN[link.frame] ELSE RETURN[PrincOps.NullFrame]; ENDLOOP; }; <> Initialize: PROC = { pSD: POINTER TO ARRAY NAT OF PROC ANY RETURNS ANY _ LOOPHOLE[PrincOps.SD]; pSD[PrincOps.sSignalList] _ SignalList; pSD[PrincOps.sSignal] _ Signal; pSD[PrincOps.sErrorList] _ ErrorList; pSD[PrincOps.sError] _ Error; pSD[PrincOps.sReturnErrorList] _ ReturnErrorList; pSD[PrincOps.sReturnError] _ ReturnError; pSD[PrincOps.sUnnamedError] _ UnnamedError; }; Initialize[]; END.