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. NSignalsImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Levin on September 20, 1983 11:14 am Russ Atkinson (RRA) February 19, 1985 1:14:45 pm PST Types and Related Declarations Global Variables (protected by monitor) Exported to RuntimeError Language support routines Internal Procedures catchFrame is waiting to execute its exit jump We want to be able to RESUME UNCAUGHT, but we don't want a random catch phrase to do so. So, we declare it to be an ERROR in the interface, but raise it as a SIGNAL here. When (if) UNCAUGHT percolates to the top of the stack, it is implicitly resumed (see the preceding line of code). Control then passes to the statement following the invocation of UNCAUGHT, which calls the debugger (or whatever). code[pc] points at zCatch MarkSignalHandlerFrame[FALSE]; Initialization Κ v– "Cedar" style˜codešœ™Kšœ Οmœ1™K˜/Kšœžœ˜Kšœ žœ ˜FK˜Kšžœ ˜Kšœ˜K˜—š œžœ žœžœžœžœ žœžœžœ˜TKšœ>˜>Kšœ/˜/Kšœžœ˜šœžœ ˜'Kšœžœ=˜EKšœ˜—Kšœ˜Kšœ˜Kšžœ ˜Kšœ˜K˜—š  œžœ˜Kšœžœ˜Kšœžœžœ˜*Kšžœ ˜Kšœ˜K˜—š œžœ žœžœžœžœ žœ˜@Kšœžœ˜K˜Kšœ˜K˜—š  œžœ žœžœžœžœ žœžœžœ˜OKšœžœ˜Kšœžœ žœ!˜QKšœ˜Kšœ˜—K˜K™Kšœ™K˜š  œžœ žœžœžœ˜;Kšœ˜šœ ˜ KšŸK˜KKšœ˜—Kšœ˜K˜—š  œžœ žœžœžœžœ žœžœžœ˜dK˜Kš œ žœžœžœžœ˜4K˜K˜'K˜)K˜:K˜K˜K˜Kšœ žœ˜Kšœ žœ˜Kšœžœ˜K˜!K˜!K˜Kšœžœžœ˜1K˜Bšž˜K˜šžœž˜K˜šžœ2žœ žœ˜IKšžœžœ˜1šžœ žœ˜šžœž˜%šœ žœ˜'Kšžœ˜Kšžœ˜——šžœžœ˜!šžœžœž˜8K˜4—Kšœ(˜(Kšœ˜—K˜'Kšœ˜—šž˜šœ žœ ž˜2šžœ˜Kšžœ˜Kšžœ˜—šž˜šžœ˜Kšžœ˜Kšžœ˜————Kšœ˜—Kšžœ(˜,Kšžœ žœžœ˜AK˜9šžœ žœ˜Kšœ/˜/˜K˜K˜ K˜˜K˜<——šœ žœ˜*Kš žœ žœžœžœžœ˜.Kšœžœ˜,—Kšœ žœ˜šžœž˜Kšœ žœ˜˜ šžœ ˜ Kšžœžœ ˜šžœ˜Kšœ0˜0K˜&Kšžœžœ ˜Kšœ˜———˜šžœžœ˜Kšœ.™.K˜Kšœ˜Kšœ žœ'˜8K˜Kšœ žœ˜Kšœ ˜ Kšžœžœ ˜Kšœ˜——Kšžœ˜—Kšœ˜—šžœ žœ˜Kšžœžœ˜(Kšžœ žœžœ&˜OKšœ˜Kšœ˜—šž˜Kšœžœ˜Kšžœž˜—Kšžœ˜—Kšžœ˜—šžœžœž˜K˜ Kš œžœ žœžœžœŸ˜Qšžœ˜ Kšœ’™’Kšœ žœžœžœžœžœžœžœ˜7Kšžœžœ˜.Kšœ#˜#K˜——Kšœ˜K˜—š   œžœžœžœ žœ˜rKšœžœžœžœ˜(Kšœžœ˜Kšœžœ+˜:K˜šž˜šžœ ž˜Kšœ"žœžœ˜.Kšœ!˜!Kšžœžœžœ˜'—Kšžœ˜—šžœ žœ˜Kšœ™K˜šžœž˜Kšœ˜Kšžœ/˜1Kšœ˜Kšžœ˜—Kšœ˜—Kšœ˜K˜—š œžœžœ˜OKšœ™šž˜šžœ ˜ Kš žœžœžœŸœžœ ˜SKšžœžœ˜ —Kšžœ˜—Kšœ˜K˜K˜K˜—Kšœ™K˜š  œžœ˜Kšœžœžœžœžœžœžœžœžœžœžœ žœ˜JK˜'K˜K˜%K˜K˜1K˜)K˜+Kšœ˜K˜—K˜ K˜Kšžœ˜K˜K˜—…—4*ψ