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 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. ¬ SignalsImpl.mesa Copyright Σ 1987, 1989, 1991 by Xerox Corporation. All rights reserved. Carl Hauser, July 24, 1989 12:51:53 pm PDT Russ Atkinson (RRA) July 27, 1989 9:05:46 pm PDT Christian Jacobi, January 5, 1990 5:24:28 pm PST Chauser, February 22, 1991 10:51 am PST Foote, May 31, 1991 2:44 pm PDT Willie-s, August 5, 1991 5:34 pm PDT Michael Plass, December 13, 1991 3:22 pm PST Options Global Variables (protected by monitor) Who makes informational signals? What language feature? According to Dan Swinehart, this kind of signalling is done in code written by wizards and not produced by any Mesa language feature. The idea is to signal in such a way that if the signal is not caught, you don't end up in the debugger. SignalHandler First pass: find catch phrases, looking for GOTO out of one unwinding = FALSE walk from nextFrame toward "cool" end of stack, looking for target catchPhrase is for another instance of this (SignalHandler) procedure. choose our nextFrame different signals propagate through intervening frames from the Mesa 11.0 manual: "all of the routines whose frames lie beyond thisSignaller, up to the frame containing the catch phrase called by thisSignaller, have already had a chance to handle signal, so they are not given it again." I claim that all signals should propagate through intervening frames, or none. I lean to the side of none, but I'll leave this as-is for the time being. frame is NOT for another SignalHandler - just walk the stack to nextFrame Will this frame catch any signals? It may, depending on the body of the catch phrase (it may also raise signals!) call the catch phrase now WarmestHandler will give us the catchPhrase just pushed for the above ENABLE stuff our "self" record in the catchPhrase so later instances of the SignalHandler can find it. the handler has filled rtns^ with the results for signal's raiser ELSE Apparently, non-local GOTOs from a handlers for signals originated as informational are ignored and treated as REJECTs. What happened? does an implicit RESUME Informational signals are resumed either by an explicit resume in a catch phrase or when the signal has propagated to the top of the stack. IF signal = LOOPHOLE[UNCAUGHT] at this point, it was raised in the following ENDCASE (in a different invocation of SignalHandler), so upon resumption, that SignalHandler calls ucsHandler. 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). for now dummy msg parameter because the PrincOps world is so different. frame: NIL because I think that's what happens in PrincOps world. disable ordinary handlers in the stack to be unwound nextCatchPhrase _ start; UNTIL (nextCatchPhrase = target) DO nextCatchPhrase.dynamicFrame.key _ DisabledMesaHandlerKey; nextCatchPhrase _ Parent[nextCatchPhrase]; ENDLOOP; target.dynamicFrame.key _ DisabledMesaHandlerKey; propagate an UNWIND follows the caller pointer of frame call the catch phrase -- this is old-style, with UNWIND handling buried in normal catch phrases. Signalling types Maintain correspondence with declaration in DefSetSignalEnvironment below formerly from SignalSupport.c and SignalSupport.h: If this fails to compile, change the number in "unwindSpace[4]" in XR_Enable If this fails to compile, change the number in "catchSpace[7]" in XR_Enable XR routines --make this procedure PUBLIC when interface changes for any other reason the jmpBuf^ should be dynamically allocated (not on the stack) dead, but it keeps the compiler happy Thread state manipulation Statistics Embedded C procedure (for XR_Enable) n.b. the context for the unwinder is the catchPhrase, not the unwindFrame External names Initialization Κt•NewlineDelimiter –(cedarcode) style™head™Icodešœ Οeœ=™HL™*L™0L™0L™'L™L™$L™,—˜šΟk ˜ Lšœ˜Lšœ ˜ Lšœ˜——šΟn œžœžœΟc ˜%Lšžœ˜Lšžœ<˜Cšœž˜Lšžœžœ˜'—L˜—™Lšœ žœžœ˜—™'Lšœ5˜5L™šœ žœžœ˜Lšœ˜Lšœžœ˜Lšœžœ˜Lšœž˜Lšœ˜L˜—š Ÿœžœžœžœ žœžœ˜BL™¨Lšœžœžœžœ˜&Lšœ˜L˜—š Ÿœžœžœžœžœ ˜{Lšœ˜Lšœ˜Lšœ˜L˜—šŸœ˜+L˜L˜L˜—Lšœ žœžœ ˜šœžœžœ˜)L˜—LšŸ œžœ˜—™ Lšœ žœžœ˜šŸœžœ  œžœžœžœžœ˜NLšœ˜Lšœ˜L˜L˜—šŸ œžœžœžœžœžœžœ˜jLšœžœ˜Lšœ žœ ˜Lšœžœ˜"Lšœ#˜#Lšœžœ ˜*Lšœžœ˜ Lšœžœ ˜Lšžœžœžœ˜Lšœ˜šžœ˜ Lšžœ˜ Lšœ žœ˜Lšœ$ ˜L˜—Lš œžœžœžœžœ˜N—šœ ™ š Ÿ œžœžœžœžœžœ˜9L˜L˜L˜—š Ÿœžœžœžœžœ˜LL˜L˜L˜—š Ÿ œžœžœ œ  ˜>L˜,Lšœžœ˜ Lšžœ˜Lšœ˜—L˜š Ÿ œžœžœ œ  ˜BL˜.Lšœ!˜!Lšœ˜L˜—š Ÿœžœžœžœ  œ ˜JLšœH™HLšœ žœžœ˜4L˜L˜—š Ÿœžœžœžœžœ  œ ˜WLšœ žœ žœ˜7L˜L˜—š Ÿœžœžœžœžœ  œ ˜OLšœ žœžœ˜3L˜L˜—š Ÿœžœžœžœ  œ ˜QLšœ žœ!žœ˜8L˜L˜—šŸœžœ žœžœHžœ žœžœ œ ˜ΉLšœ0˜0Lšœ žœ˜6Lšœ.˜.Lšœ˜Lšœ#˜#Lšœžœ˜!Lšœ"˜"Lšœ˜Lšœ!˜!Lšœ ˜ Lšœžœ˜Lšœžœ˜-L˜*L˜L˜—šŸœžœžœ žœ žœžœžœžœžœ œ ˜L™>Lšœžœžœ˜