<<>> <> <> <> <> <> <> <> <> <> DIRECTORY PortableCedarRuntimeSupport, RuntimeError, SignalStatistics; SignalsImpl: CEDAR PROGRAM -- MONITOR IMPORTS RuntimeError EXPORTS PortableCedarRuntimeSupport, RuntimeError, SignalStatistics ~ BEGIN OPEN PCRS: PortableCedarRuntimeSupport; <> checking: BOOL = TRUE; <> ucsHandler: RuntimeError.UCSProc ¬ InitialUCSHandler; <<>> SigInfo: TYPE ~ RECORD [ sig: ExceptAny, arg: POINTER, rtns: POINTER, informational: BOOL ]; InformationalSignal: PUBLIC SAFE PROC [signal: SIGNAL] = TRUSTED { <> SignalHandler[signal, NIL, NIL, TRUE]; }; RegisterUncaughtSignalHandler: PUBLIC -- ENTRY -- PROC [proc: RuntimeError.UCSProc] RETURNS [old: RuntimeError.UCSProc] = { old ¬ ucsHandler; ucsHandler ¬ proc; }; InitialUCSHandler: RuntimeError.UCSProc ~ { CallDebugger[]; }; CatchProc: TYPE ~ PCRS.Handler; HandlerAction: TYPE = PCRS.HandlerAction; NoHandler: CatchPhrase = NIL; <> signalSpy: PROC ¬ NIL; RegisterSignalSpy: PUBLIC -- ENTRY -- PROC [new: PROC] RETURNS [old: PROC] ~ { old ¬ signalSpy; signalSpy ¬ new; }; SignalHandler: PROC [sig: ExceptAny, arg: POINTER, rtns: POINTER, informational: BOOL ¬ FALSE] ~ TRUSTED { action: PCRS.HandlerAction; catchProc: PCRS.Handler; warmestHandler: CatchPhrase ¬ NIL; selfObj: SignallerStateObject ¬ []; self: SignallerState ¬ LOOPHOLE[@selfObj]; exitTo: INT; spy: PROC ~ signalSpy; IF spy # NIL THEN spy[]; self.signal ¬ sig; TRUSTED { OPEN self; unwinding ¬ FALSE; warmestHandler ¬ WarmestHandler[]; -- in the current thread <> <> start ¬ warmestHandler; nextCatchPhrase ¬ start; UNTIL (nextCatchPhrase = target) OR unwinding DO thisSignaller: SignallerState; <> currentCatchPhrase ¬ nextCatchPhrase; thisSignaller ¬ currentCatchPhrase.signallerState; IF thisSignaller # NIL THEN { <> <> IF signal ~= thisSignaller.signal THEN { nextCatchPhrase ¬ Parent[currentCatchPhrase]; } ELSE { nextCatchPhrase ¬ thisSignaller.nextCatchPhrase; }; <> <> <> } ELSE -- currentCatchPhrase.signallerState = NIL -- <> { nextCatchPhrase ¬ Parent[currentCatchPhrase]; }; <> IF (catchProc ¬ currentCatchPhrase.catchProc) # NIL THEN { <> ENABLE { RuntimeError.SendMsg => RESUME[self.signal, arg, rtns]; -- GetSignal is SIGNALled by an ANY-catcher to request the details of the signal it is processing -- }; <> hotHandler: CatchPhrase ¬ WarmestHandler[]; <> hotHandler.signallerState ¬ self; [action, exitTo] ¬ catchProc[context: currentCatchPhrase.catchContext, except: signal, rtnPtr: rtns, argPtr: arg ! RuntimeError.Resume => TRUSTED { action ¬ resume; CONTINUE }]; SELECT action FROM reject => NULL; resume => { <> RETURN }; exit => IF ~informational THEN { target ¬ currentCatchPhrase; unwinding ¬ TRUE; arg ¬ NIL; }; <> <> ENDCASE; }; ENDLOOP; <> SELECT TRUE FROM unwinding => NULL; informational OR signal = LOOPHOLE[UNCAUGHT] => NULL; <> <> ENDCASE => { <> Uncaught: TYPE = SIGNAL [SIGNAL ANY RETURNS ANY, WORD]; LOOPHOLE[UNCAUGHT, Uncaught][signal, LOOPHOLE[arg]]; <> <> TRUSTED {ucsHandler[msg: LOOPHOLE[arg], signal: signal, frame: NIL]}; }; IF unwinding THEN { <> <> <> <> <> <> <> <> UnwindTo[LOOPHOLE[target]]; RestartHandlee[GetNextHandlee[NIL], target.jmpBufPtr, exitTo] }; }; }; Parent: PROC [catchPhrase: CatchPhrase] RETURNS [parent: CatchPhrase] ~ TRUSTED { <> env: DynamicFrame ~ LOOPHOLE[catchPhrase]; RETURN[LOOPHOLE[LookupInDynamicEnvironment[MesaHandlerKey, env.next]]]; }; WarmestHandler: PROC [] RETURNS [CatchPhrase] ~ { env: DynamicFrame ~ GetDynamicEnvironment[]; RETURN[LOOPHOLE[LookupInDynamicEnvironment[MesaHandlerKey, env]]]; }; MesaUnwinderProc: TYPE ~ POINTER TO MesaUnwinderProcBody; MesaUnwinderProcBody: TYPE ~ RECORD [ codeBody: WORD, catchPhrase: CatchPhrase ]; MesaUnwinder: PROC [self: MesaUnwinderProc] ~ TRUSTED { -- XR¬MesaUnwinder cp: CatchPhrase ¬ self.catchPhrase; catchProc: PCRS.Handler; action: PCRS.HandlerAction; IF (catchProc ¬ cp.catchProc) # NIL THEN TRUSTED { ENABLE { RuntimeError.SendMsg => RESUME[LOOPHOLE[UNWIND], NIL, NIL]; -- GetSignal is SIGNALled by an ANY-catcher to request the details of the signal it is processing -- }; <> [action, ] ¬ catchProc[context: cp.catchContext, except: LOOPHOLE[UNWIND], rtnPtr: NIL, argPtr: NIL ! RuntimeError.Resume => {action ¬ resume; CONTINUE }]; SELECT action FROM reject => NULL; resume => ERROR RuntimeError.ResumeFault; exit => ERROR RuntimeError.UnwindFault; ENDCASE; }; }; <> <> SignalEnvironment: TYPE = REF SignalEnvironmentObject; SignalEnvironmentObject: TYPE = MACHINE DEPENDENT RECORD [ unixTrapHandler: PROC, aborted: ERROR, abstractionFault: ERROR, arithmeticFault: ERROR, assignRefCompositeFault: ERROR, boundsFault: ERROR, divideCheck: SAFE SIGNAL, invalidProcess: ERROR [process: PROCESS], linkageFault: ERROR, narrowFault: ERROR, narrowRefFault: ERROR [ref: REF, type: RuntimeError.Type], nestedProcFault: ERROR [proc: RuntimeError.ProcAny], nilFault: ERROR, resumeFault: ERROR, sendMsg: SIGNAL RETURNS [signal: SIGNAL ANY RETURNS ANY, args, results: POINTER], stackFault: ERROR, startFault: SIGNAL [dest: PROGRAM], unboundProcedureFault: SIGNAL [dest: PROC ANY RETURNS ANY] RETURNS [PROC ANY RETURNS ANY], uncaught: ERROR [signal: SIGNAL ANY RETURNS ANY, parameters: WORD], unnamedError: ERROR, unnamedSignal: SIGNAL, unwind: ERROR, unwindFault: ERROR, zeroDivisor: SAFE SIGNAL ]; <<>> <> DefSetSignalEnvironment: PROC [] = TRUSTED MACHINE CODE { "+"; "typedef struct {\n"; " int *unixTrapHandler;\n"; " unsigned aborted;\n"; " unsigned abstractionFault;\n"; " unsigned arithmeticFault;\n"; " unsigned assignRefCompositeFault;\n"; " unsigned boundsFault;\n"; " unsigned divideCheck;\n"; " unsigned invalidProcess;\n"; " unsigned linkageFault;\n"; " unsigned narrowFault;\n"; " unsigned narrowRefFault;\n"; " unsigned nestedProcFault;\n"; " unsigned nilFault;\n"; " unsigned resumeFault;\n"; " unsigned sendMsg;\n"; " unsigned stackFault;\n"; " unsigned startFault;\n"; " unsigned unboundProcedureFault;\n"; " unsigned uncaught;\n"; " unsigned unnamedError;\n"; " unsigned unnamedSignal;\n"; " unsigned Unwind;\n"; " unsigned unwindFault;\n"; " unsigned zeroDivisor;\n"; " } SignalEnvironmentObject;\n"; "typedef SignalEnvironmentObject *SignalEnvironment;\n"; "unsigned XR_UnnamedSignal;\n"; "unsigned XR_UnnamedError;\n"; "unsigned XR_Unwind;\n"; "unsigned XR_Aborted;\n"; "unsigned XR_Uncaught;\n"; "unsigned XR_NarrowFault;\n"; "unsigned XR_NarrowRefFault;\n"; "unsigned XR_InvalidProcess;\n"; "SignalEnvironment XR_SigEnv;\n"; "static void XR_SetSignalEnvironment(env)\n"; " SignalEnvironment env;\n"; " {\n"; " XR_SigEnv = env;\n"; " XR_UnnamedError = env-> unnamedError;\n"; " XR_UnnamedSignal = env->unnamedSignal;\n"; " XR_Unwind = env->Unwind;\n"; " XR_Aborted = env->aborted;\n"; " XR_Uncaught = env->uncaught;\n"; " XR_NarrowFault = env->narrowFault;\n"; " XR_NarrowRefFault = env->narrowRefFault;\n"; " XR_InvalidProcess = env->invalidProcess;\n"; " };\n"; "."; }; ExceptAny: TYPE ~ SIGNAL ANY RETURNS ANY; noCP: CatchPhrase ~ NIL; MesaHandlerKey: WORD ~ CODE; DisabledMesaHandlerKey: WORD ~ CODE; UnwindFrameKey: WORD ¬ GetUnwindFrameKey[]; DynamicFrame: TYPE ~ POINTER TO DynamicFrameObject; DynamicFrameObject: TYPE ~ RECORD [ next: DynamicFrame, key: WORD, data: WORD ]; UnwindFrame: TYPE ~ POINTER TO UnwindFrameObject; UnwindFrameObject: TYPE ~ RECORD [ next: DynamicFrame, key: WORD, unwinder: PROC, rewinder: PROC ]; assertUnwindFrameObjectSize: [0..4] = WORDS[UnwindFrameObject]; <> CatchPhrase: TYPE ~ POINTER TO CatchPhraseObject; CatchPhraseObject: TYPE ~ RECORD [ dynamicFrame: DynamicFrameObject, jmpBufPtr: POINTER, catchProc: PCRS.Handler, catchContext: POINTER, signallerState: REF SignallerStateObject ]; assertCatchPhraseObjectSize: [0..7] = WORDS[CatchPhraseObject]; <> SignallerState: TYPE = REF SignallerStateObject; SignallerStateObject: TYPE ~ RECORD [ startMark: CARD32 ¬ 0FF00FF00H, start: CatchPhrase ¬ noCP, signal: ExceptAny ¬ NIL, currentCatchPhrase: CatchPhrase ¬ noCP, nextCatchPhrase: CatchPhrase ¬ noCP, target, nextTarget: CatchPhrase ¬ noCP, unwinding: BOOL ¬ FALSE, endMark: CARD32 ¬ 0FF11FF11H ]; RaiseErrorProc: TYPE = PROC [which: ExceptAny, args: POINTER]; RaiseSignalProc: TYPE = PROC [which: ExceptAny, rtns: POINTER, args: POINTER]; <> CallDebugger: PROC [] RETURNS [] ~ TRUSTED MACHINE CODE { "XR_CallDebugger" }; SetSignalEnvironment: PROC [env: SignalEnvironment] ~ TRUSTED MACHINE CODE { "XR_SetSignalEnvironment" }; RaiseError: PUBLIC RaiseErrorProc = TRUSTED { -- XR¬RaiseError stats.errorsRaised ¬ stats.errorsRaised + 1; SignalHandler[which, args, NIL]; ERROR RuntimeError.ResumeFault }; RaiseSignal: PUBLIC RaiseSignalProc = TRUSTED { -- XR¬RaiseSignal stats.signalsRaised ¬ stats.signalsRaised + 1; SignalHandler[which, args, rtns]; }; RaiseUnnamedError: PROC [] RETURNS [CARD ¬ 0] ~ { -- XR¬RaiseUnnamedError <<--make this procedure PUBLIC when interface changes for any other reason>> RaiseError[LOOPHOLE[RuntimeError.UnnamedError], NIL] }; RaiseArithmeticFault: PUBLIC PROC [] RETURNS [CARD ¬ 0] ~ { -- XR¬RaiseArithmeticFault RaiseError[LOOPHOLE[RuntimeError.ArithmeticFault], NIL] }; RaiseBoundsFault: PUBLIC PROC [] RETURNS [CARD ¬ 0] ~ { -- XR¬RaiseBoundsFault RaiseError[LOOPHOLE[RuntimeError.BoundsFault], NIL] }; RaiseAbstractionFault: PUBLIC PROC [] RETURNS [] ~ { -- XR¬RaiseAbstractionFault RaiseError[LOOPHOLE[RuntimeError.AbstractionFault], NIL] }; SetupPushHandler: PROC [context: POINTER, proc: PCRS.Handler, catchPhrase: CatchPhrase, unwindFrame: UnwindFrame, unwinder: PROC, jmpBufPtr: POINTER ] ~ TRUSTED { -- XR¬SetupPushHandler prevEnv: DynamicFrame ¬ GetDynamicEnvironment[]; catchPhrase.dynamicFrame.next ¬ LOOPHOLE[unwindFrame]; catchPhrase.dynamicFrame.key ¬ MesaHandlerKey; catchPhrase.catchProc ¬ proc; catchPhrase.catchContext ¬ context; catchPhrase.signallerState ¬ NIL; catchPhrase.jmpBufPtr ¬ jmpBufPtr; unwindFrame.next ¬ prevEnv; unwindFrame.key ¬ UnwindFrameKey; unwindFrame.unwinder ¬ unwinder; unwindFrame.rewinder ¬ NIL; SetDynamicEnvironment[LOOPHOLE[catchPhrase]]; stats.newPushCount ¬ stats.newPushCount+1; }; PushAllocedHandler: PUBLIC PROC [context: POINTER, handler: PCRS.Handler, jmpBuf: POINTER] RETURNS [INT] ~ TRUSTED { -- XR¬PushAllocedHandler <> unwindFrame: UnwindFrame ¬ LOOPHOLE[NEW[UnwindFrameObject]]; catchPhrase: CatchPhrase ¬ LOOPHOLE[NEW[CatchPhraseObject]]; MesaProcObject: TYPE ~ RECORD [ codePointer: WORD, context: WORD ]; MesaProc: TYPE ~ POINTER TO MesaProcObject; prevEnv: DynamicFrame ¬ GetDynamicEnvironment[]; catchPhrase.dynamicFrame.next ¬ LOOPHOLE[unwindFrame]; catchPhrase.dynamicFrame.key ¬ MesaHandlerKey; catchPhrase.catchProc ¬ handler; catchPhrase.catchContext ¬ context; catchPhrase.signallerState ¬ NIL; catchPhrase.jmpBufPtr ¬ jmpBuf; unwindFrame.rewinder ¬ NIL; unwindFrame.next ¬ prevEnv; unwindFrame.key ¬ UnwindFrameKey; unwindFrame.unwinder ¬ LOOPHOLE[NEW[MesaProcObject ¬ [LOOPHOLE[MesaUnwinder, MesaProc].codePointer, LOOPHOLE[catchPhrase]]]]; SetDynamicEnvironment[LOOPHOLE[catchPhrase]]; stats.pushCount ¬ stats.pushCount+1; RETURN[0]; <> }; PopHandler: PUBLIC PROC [] RETURNS [] ~ TRUSTED { -- XR¬PopHandler env: DynamicFrame ¬ GetDynamicEnvironment[]; IF (env.key = MesaHandlerKey OR env.key = DisabledMesaHandlerKey) AND env.next.key=UnwindFrameKey THEN { SetDynamicEnvironment[env.next.next] } ELSE ERROR; }; <> XRThread: TYPE ~ POINTER; GetDynamicEnvironment: PROC [] RETURNS [DynamicFrame] ~ TRUSTED MACHINE CODE { "XR_GetDynamicEnvironment" }; GetDynamicEnvironmentOf: PROC [XRThread] RETURNS [DynamicFrame] ~ TRUSTED MACHINE CODE { "XR_GetDynamicEnvironmentOf" }; SetDynamicEnvironment: PROC [DynamicFrame] RETURNS [] ~ TRUSTED MACHINE CODE { "XR_SetDynamicEnvironment" }; LookupInDynamicEnvironment: PROC [key: WORD, de: DynamicFrame] RETURNS [DynamicFrame] ~ TRUSTED MACHINE CODE { "XR_LookupInDynamicEnvironment" }; UnwindTo: PROC [DynamicFrame] RETURNS [] ~ TRUSTED MACHINE CODE { "XR_UnwindTo" }; GetNextHandlee: PROC[thread: XRThread] RETURNS [XRThread]~ TRUSTED MACHINE CODE { "XR_GetNextHandlee" }; GetUnwindFrameKey: PROC[] RETURNS [WORD] ~ TRUSTED MACHINE CODE { "XR_GetUnwindFrameKey" }; RestartHandlee: PROC[thread: XRThread, jmpBuf: POINTER, exitTo: INT] ~ TRUSTED MACHINE CODE { "XR_RestartHandlee" }; <> stats: SignalStatistics.Stats ¬ []; GetStatistics: PUBLIC PROC [] RETURNS [SignalStatistics.Stats] ~ { RETURN [stats]; }; <> DefEnable: PROC [] = TRUSTED MACHINE CODE { "+"; "#include \n"; "typedef struct {fPt p; word c;} ProcDescBody;\n"; "extern word XR_Enable(body, handler, context)\n"; " fPt body;\n"; " fPt handler;\n"; " ptr context;\n"; " {\n"; " word rtnCode;\n"; " ptr beforeCall;\n"; " ProcDescBody pdDescBody;\n"; " ProcDescBody unwindDescBody;\n"; " word catchSpace[7];\n"; " struct XR_JmpBufRep jmpBuf;\n"; " word unwindSpace[4];\n"; " pdDescBody.p = handler;\n"; " pdDescBody.c = 1;\n"; " unwindDescBody.p = (fPt) XR_MesaUnwinder;\n"; <> " unwindDescBody.c = (word) catchSpace;\n"; " beforeCall = (ptr) XR_GetDynamicEnvironment();\n"; " XR_SetupPushHandler(context, &pdDescBody, catchSpace, unwindSpace, &unwindDescBody, &jmpBuf);\n"; " rtnCode = XR_setjmp(&jmpBuf);\n"; " if (rtnCode == 0) rtnCode = body(context);\n"; " { /* INLINE version of XR_PopHandler, no stats */ \n"; " ptr curr = (ptr) XR_GetDynamicEnvironment();\n"; " ptr prev = (ptr) *((ptr) *curr);\n"; " if (beforeCall != prev) XR_RaiseError(0,0);\n"; " XR_SetDynamicEnvironment(prev);\n"; " };\n"; " return (rtnCode);\n"; " };\n"; "extern word XR_UnwindFrameKey;\n"; "static word XR_GetUnwindFrameKey()\n"; " {\n"; " return( XR_UnwindFrameKey );\n"; " };\n"; "."; }; <> ExternalNames: PROC [] = TRUSTED MACHINE CODE { "^ExternalNames\n"; "RaiseError XR_RaiseError\n"; "RaiseSignal XR_RaiseSignal\n"; "RaiseUnnamedError XR_RaiseUnnamedError\n"; "RaiseArithmeticFault XR_RaiseArithmeticFault\n"; "RaiseBoundsFault XR_RaiseBoundsFault\n"; "RaiseAbstractionFault XR_RaiseAbstractionFault\n"; "SetupPushHandler XR_SetupPushHandler\n"; "PushAllocedHandler XR_PushAllocedHandler\n"; "PopHandler XR_PopHandler\n"; "PushUnwinder XR_PushUnwinder\n"; "PopUnwinder XR_PopUnwinder\n"; "GetUnwinderContext XR_GetUnwinderContext\n"; "MesaUnwinder XR_MesaUnwinder\n"; }; <> Initialize: PROC = { SetSignalEnvironment[ NEW[SignalEnvironmentObject ¬ [ aborted ~ RuntimeError.Aborted, abstractionFault ~ RuntimeError.AbstractionFault, arithmeticFault ~ RuntimeError.ArithmeticFault, assignRefCompositeFault ~ RuntimeError.AssignRefCompositeFault, boundsFault ~ RuntimeError.BoundsFault, divideCheck ~ RuntimeError.DivideCheck, invalidProcess ~ RuntimeError.InvalidProcess, linkageFault ~ RuntimeError.LinkageFault, narrowFault ~ RuntimeError.NarrowFault, narrowRefFault ~ RuntimeError.NarrowRefFault, nestedProcFault ~ RuntimeError.NestedProcFault, nilFault ~ RuntimeError.NilFault, resumeFault ~ RuntimeError.ResumeFault, sendMsg ~ RuntimeError.SendMsg, stackFault ~ RuntimeError.StackFault, startFault ~ RuntimeError.StartFault, unboundProcedureFault ~ RuntimeError.UnboundProcedureFault, uncaught ~ RuntimeError.Uncaught, unnamedError ~ RuntimeError.UnnamedError, unnamedSignal ~ RuntimeError.UnnamedSignal, unwind ~ RuntimeError.Unwind, unwindFault ~ RuntimeError.UnwindFault, zeroDivisor ~ RuntimeError.ZeroDivisor ]]]; DefEnable[]; DefSetSignalEnvironment[]; }; ExternalNames[]; Initialize[]; END.