-- Copyright (C) 1986 by Xerox Corporation. All rights reserved. -- CRuntimeB.mesa -- NFS 22-Jan-86 15:59:48 -- MEW 27-May-86 17:29:44 DIRECTORY BcdDefs USING [CTIndex, GFIndex, MTIndex], BcdOps USING [BcdBase, MTHandle], BcdOpsExtras USING [CTBaseFromBcd, GfiFromMti, MTBaseFromBcd, MthFromGfi], CBasics USING [MainProc], CRuntime USING [normalOutcome, ProgramExited, z], CRuntimeInternal USING [GlobalFrameHandle, ResetConfig, SetConfig], CString USING [CString], Frame USING [GetReturnFrame, ReadCodebaseLow, ReadGlobalLink, ReadGlobalWord, WriteCodebaseLow, WriteGlobalWord], LoadState USING [ GetModuleInfo, LockBcdInfo, LPBcdInfoTable, ModuleInfoRange, ModuleInfoSequenceHandle, ModuleInfosOfBcd, UnlockBcdInfo], LoadStateFormat USING [ModuleInfo], PrincOps USING [GlobalCodebase, GlobalFrameHandle, GlobalWord], Process USING [GetCurrent], SpecialRuntime USING [ProgramFromGlobalFrame], Stream USING [Handle], Table USING [Base]; CRuntimeB: MONITOR -- not CRuntimeInternal.lock IMPORTS BcdOpsExtras, CRuntime, CRuntimeInternal, Frame, LoadState, Process, SpecialRuntime EXPORTS CBasics, CRuntime, CRuntimeInternal = { OPEN CRuntime, CRuntimeInternal; GlobalFrameHandle: TYPE = PrincOps.GlobalFrameHandle; moduleTable: LONG POINTER TO ModuleTable; ModuleTable: TYPE = RECORD [ seq: SEQUENCE COMPUTED CARDINAL OF PrincOps.GlobalFrameHandle]; ControlList: TYPE = LONG POINTER TO ModuleRecord; ModuleRecord: TYPE = RECORD [gfi: BcdDefs.GFIndex, link: ControlList]; MainArgsNeeded: PUBLIC SIGNAL RETURNS [argC: CARDINAL, argV: LONG POINTER TO CString.CString] = CODE; CallMain: PUBLIC PROCEDURE [main: CBasics.MainProc] = { <<Note:Programs that have main procs. that take arc or argv parameters or that return values other than 0, must be invoked by the procedures Start or Restart, below. Otherwise there will be an uncaught signal.>> argc: CARDINAL; argv: LONG POINTER TO CString.CString; retval: INTEGER ← 0; IF main.args # neither THEN [argc, argv] ← SIGNAL MainArgsNeeded; WITH m: main SELECT FROM neither => retval ← m.main0[]; justArgC => retval ← m.main1[argc]; both => retval ← m.main2[argc, argv]; ENDCASE => ERROR; IF retval # normalOutcome THEN ERROR ProgramExited[retval]; }; Start: PUBLIC PROCEDURE [ gf: GlobalFrameHandle, argc: CARDINAL, argv: LONG POINTER TO CString.CString, stdin, stdout, stderr: Stream.Handle] RETURNS [outcome: INTEGER ← normalOutcome] = { ENABLE { ProgramExited => {outcome ← status; CONTINUE; }; MainArgsNeeded => RESUME [argc, argv]; }; p: PROGRAM = SpecialRuntime.ProgramFromGlobalFrame[gf]; SetConfig[gf, stdin, stdout, stderr]; ResetUserAbort[]; START p; }; StartConfig: PUBLIC PROCEDURE = { gf: GlobalFrameHandle = Frame.ReadGlobalLink[Frame.GetReturnFrame[]]; moduleInfo: LoadStateFormat.ModuleInfo = LoadState.GetModuleInfo[gf]; moduleSeq: LoadState.ModuleInfoSequenceHandle; controlModules: ControlList; bcdInfo: LoadState.LPBcdInfoTable; bcd: BcdOps.BcdBase; mth: BcdOps.MTHandle; moduleSeq ← LoadState.ModuleInfosOfBcd[moduleInfo.index, z]; moduleTable ← LOOPHOLE[z.NEW[ModuleTable [moduleSeq.length]]]; bcdInfo ← LoadState.LockBcdInfo[].bcdInfo; bcd ← bcdInfo[moduleInfo.index].base; FOR i: LoadState.ModuleInfoRange IN [0..moduleSeq.length) DO gf: GlobalFrameHandle = moduleSeq[i].gf; moduleTable[moduleSeq[i].cgfi - 1] ← gf; mth ← BcdOpsExtras.MthFromGfi[bcd, moduleSeq[i].cgfi]; IF mth.tableCompiled THEN LOOP; -- no gf[0] to erase!! gf[0] ← NIL; -- so start trap doesn't think there is a control list. ENDLOOP; controlModules ← GetControlModules[bcd]; LoadState.UnlockBcdInfo[]; StartModules[controlModules, gf ! ProgramExited => {CONTINUE; }]; z.FREE[@moduleSeq]; z.FREE[@moduleTable]; }; Restart: PUBLIC PROCEDURE [ gf: GlobalFrameHandle, argc: CARDINAL, argv: LONG POINTER TO CString.CString, stdin, stdout, stderr: Stream.Handle] RETURNS [outcome: INTEGER ← normalOutcome] = { moduleInfo: LoadStateFormat.ModuleInfo = LoadState.GetModuleInfo[gf]; moduleSeq: LoadState.ModuleInfoSequenceHandle; p: PROGRAM = SpecialRuntime.ProgramFromGlobalFrame[gf]; BEGIN ENABLE { MainArgsNeeded => RESUME [argc, argv]; ProgramExited => {outcome ← status; CONTINUE; }; }; ResetConfig[gf, stdin, stdout, stderr]; -- Reset started and out flag of every module in configuration, and build -- correspondence between gfi and GFrame. moduleSeq ← LoadState.ModuleInfosOfBcd[moduleInfo.index, z]; FOR i: LoadState.ModuleInfoRange IN [0..moduleSeq.length) DO globalCodeBase: PrincOps.GlobalCodebase; gf: GlobalFrameHandle = moduleSeq[i].gf; globalWord: PrincOps.GlobalWord ← Frame.ReadGlobalWord[gf]; globalWord.started ← FALSE; Frame.WriteGlobalWord[word: globalWord, gf: gf]; globalCodeBase.offset ← Frame.ReadCodebaseLow[gf]; globalCodeBase.out ← TRUE; Frame.WriteCodebaseLow[gf: gf, u: globalCodeBase.offset]; ENDLOOP; gf[0] ← NIL; -- so start trap doesn't think there is a control list. ResetUserAbort[]; START p; END; z.FREE[@moduleSeq]; }; GetControlModules: PROCEDURE [bcd: BcdOps.BcdBase] RETURNS [control: ControlList ← NIL] = { TraverseControls: PROCEDURE [cti: BcdDefs.CTIndex] = { FOR i: NATURAL IN [0..ctb[cti].nControls) DO WITH c: ctb[cti].controls[i] SELECT FROM config => TraverseControls[c.cti]; module => AttachControl[BcdOpsExtras.GfiFromMti[c.mti]]; ENDCASE => ERROR; ENDLOOP; }; AttachControl: PROCEDURE [gfi: BcdDefs.GFIndex] = { newModule: ControlList = LOOPHOLE[z.NEW[ModuleRecord ← [gfi, NIL]]]; IF control = NIL THEN control ← last ← newModule ELSE {last.link ← newModule; last ← newModule; }; }; ctb: Table.Base = BcdOpsExtras.CTBaseFromBcd[bcd]; mtb: Table.Base = BcdOpsExtras.MTBaseFromBcd[bcd]; last: ControlList ← NIL; IF bcd.nConfigs = 0 THEN { control ← LOOPHOLE[z.NEW[ ModuleRecord ← [BcdOpsExtras.GfiFromMti[BcdDefs.MTIndex.FIRST], NIL]]]; RETURN; }; TraverseControls[BcdDefs.CTIndex.FIRST]; }; StartModules: PROCEDURE [ controls: ControlList, driver: GlobalFrameHandle ← NIL] = { WHILE controls # NIL DO ENABLE UNWIND => z.FREE[@controls]; next: ControlList = controls.link; gf: GlobalFrameHandle = moduleTable[controls.gfi - 1]; IF NOT Frame.ReadGlobalWord[gf].started AND gf # driver THEN { p: PROGRAM = SpecialRuntime.ProgramFromGlobalFrame[gf]; START p; }; z.FREE[@controls]; controls ← next; ENDLOOP; }; -- monitored data and entry procs. processesAborted: PUBLIC ProcessList ← NIL; ProcessList: TYPE = LONG POINTER TO ProcessEntry; ProcessEntry: PUBLIC TYPE = RECORD [p: PROCESS, link: ProcessList]; NoteAbortedProcess: PUBLIC ENTRY PROCEDURE [p: PROCESS] = { ENABLE UNWIND => NULL; -- Don't add if process already has pending abort. pl: ProcessList ← processesAborted; WHILE pl # NIL DO IF pl.p = p THEN RETURN; pl ← pl.link; ENDLOOP; pl ← z.NEW[ProcessEntry]; pl.link ← processesAborted; pl.p ← p; processesAborted ← pl; }; StopIfCurrentProcessAborted: PUBLIC ENTRY PROCEDURE = { ENABLE UNWIND => NULL; searcher, follower: ProcessList; p: PROCESS ← Process.GetCurrent[]; searcher ← processesAborted; follower ← NIL; WHILE searcher # NIL DO IF searcher.p = p THEN { IF follower = NIL THEN processesAborted ← searcher.link ELSE follower.link ← searcher.link; z.FREE[@searcher]; ERROR ABORTED; }; follower ← searcher; searcher ← searcher.link; ENDLOOP; }; ResetUserAbort: PROCEDURE = { -- Removes process from aborted process. StopIfCurrentProcessAborted[ ! ABORTED => CONTINUE]; }; }.