-- run configuration subroutine for command interpreter part of -- silicon (pretty picture) program -- modified by E. McCreight, December 31, 1982 1:32 PM DIRECTORY BcdDefs, BcdOps, ChipUserInt, ControlDefs, DiskKDDefs, FrameDefs, FrameOps, LoaderOps, MiscDefs, ppdefs, ppMainDefs, ProcessDefs, ProcessOps, PSBDefs, SegmentDefs, Storage, StreamDefs, StringDefs, SwapperOps, TrapDefs; ppRunConfig: PROGRAM IMPORTS ChipUserInt, DiskKDDefs, FrameDefs, FrameOps, LoaderOps, ppdefs, SegmentDefs, Storage, StreamDefs, StringDefs, SwapperOps EXPORTS ppMainDefs SHARES SegmentDefs = PUBLIC BEGIN OPEN ppdefs, StringDefs, ChipUserInt, ppMainDefs; SubrList: TYPE = RECORD[next: SubrListPtr, name: STRING]; SubrListPtr: TYPE = POINTER TO SubrList; runningSubrs: SubrListPtr ← NIL; doRunConfig: cmdProc = BEGIN otherSubr: SubrListPtr; subr: SubrList ← [next: runningSubrs, name: NIL]; BEGIN ENABLE Punt, UNWIND => GOTO Finished; subr.name ← FixExtension[ RequestString["Type subroutine name:"L, "Must be .chipbcd file"L], ".chipbcd"]; FOR otherSubr ← runningSubrs, otherSubr.next WHILE otherSubr#NIL DO IF StringDefs.EquivalentString[subr.name, otherSubr.name] THEN BEGIN Explain["I can't run two copies of that subroutine at once!"]; GOTO Finished; END; ENDLOOP; IF runningSubrs#NIL THEN BEGIN comment: STRING ← [150]; comment.length ← 0; StringDefs.AppendString[to: comment, from: "I am already running "]; FOR otherSubr ← runningSubrs, otherSubr.next WHILE otherSubr#NIL DO StringDefs.AppendString[to: comment, from: otherSubr.name]; StringDefs.AppendString[to: comment, from: ", "]; ENDLOOP; StringDefs.AppendString[to: comment, from: "OK?"]; IF NOT HeSaysYes[comment] THEN GOTO Finished; END; IF LocalizeBcd[subr.name] THEN BEGIN p: PROCESS; runningSubrs ← @subr; p ← FORK DoRunBcd[subr.name]; JOIN p; END; refreshTypeInScreen[]; GOTO Finished; EXITS Finished => BEGIN IF subr.name#NIL THEN FreeString[subr.name]; runningSubrs ← subr.next; END; END; END; LocalizeBcd: PROCEDURE[s: STRING] RETURNS[worked: BOOLEAN] = BEGIN file: StreamDefs.StreamHandle; worked ← FALSE; file ← StreamDefs.NewWordStream[ name: s, access: StreamDefs.Read ! SegmentDefs.FileNameError => GOTO Missing]; file.destroy[file]; worked ← TRUE EXITS Missing => Explain["Can't find file"L, s]; END; -- of LocalizeBcd DoRunBcd: PROCEDURE [bcdname: STRING] = BEGIN OPEN StringDefs; VitalSigns: TYPE = RECORD [processes, modules, pages: CARDINAL]; GetVitalSigns: PROCEDURE RETURNS [vitalSigns: VitalSigns] = BEGIN OPEN ProcessOps, SegmentDefs; CheckSegment: PROCEDURE [seg: SegmentHandle] RETURNS [BOOLEAN] = BEGIN inc: CARDINAL ← 0; WITH s: seg SELECT FROM data => SELECT s.type FROM IN [FrameDS .. BitmapDS] => NULL; ENDCASE => inc ← s.pages; file => -- deal with AltoLoader bug that doesn't flush code after errors -- only works for single file bcds IF s.file = runFile AND s.class = code AND s.lock = 0 THEN DeleteFileSegment[@s] ELSE IF s.lock > 0 THEN inc ← s.pages; ENDCASE; vitalSigns.pages ← vitalSigns.pages + inc; RETURN[FALSE] END; -- of CheckSegment -- CountModule: PROCEDURE [f: ControlDefs.GlobalFrameHandle] RETURNS [BOOLEAN] = BEGIN vitalSigns.modules ← vitalSigns.modules + 1; RETURN[FALSE] END; -- of CountModule -- vitalSigns ← [0, 0, 0]; -- FOR p: PSBDefs.ProcessHandle ← FirstProcess↑, p + SIZE[PSBDefs.PSB] DO -- IF p.state = alive THEN vitalSigns.processes ← vitalSigns.processes + 1; -- IF p = LastProcess↑ THEN EXIT; -- ENDLOOP; [] ← DiskKDDefs.CloseDiskKD[]; [] ← SwapperOps.EnumerateObjects[segment, LOOPHOLE[CheckSegment]]; -- [] ← FrameDefs.EnumerateGlobalFrames[CountModule]; END; -- of GetVitalSigns RunBcd: PROCEDURE = BEGIN OPEN FrameDefs, LoaderOps, SegmentDefs; cm: ControlDefs.ControlModule; bcd: BcdOps.BcdBase; bcdseg: FileSegmentHandle; OurLoad: PROCEDURE RETURNS [worked: BOOLEAN] = -- This is derived from AltoLoader.Load and incorporates some bug fixes -- and some optimizations. BEGIN bcdseg ← NewFileSegment[runFile, 1, 1, Read]; BEGIN pages: CARDINAL; worked ← FALSE; MakeSwappedIn[bcdseg, DefaultMDSBase, HardUp ! SegmentFault => GO TO bogus]; bcd ← FileSegmentAddress[bcdseg]; IF bcd.versionIdent # BcdDefs.VersionID OR bcd.definitions THEN {Unlock[bcdseg]; GO TO bogus} ELSE IF (pages ← bcd.nPages) > 1 THEN BEGIN Unlock[bcdseg]; MoveFileSegment[bcdseg, 1, pages]; MakeSwappedIn[bcdseg, DefaultMDSBase, HardUp]; bcd ← FileSegmentAddress[bcdseg]; END; worked ← TRUE; EXITS bogus => DeleteFileSegment[bcdseg]; END; END; -- of OurLoad -- OurUnload: PROCEDURE = BEGIN Unlock[bcdseg]; DeleteFileSegment[bcdseg]; END; -- of OurUnload -- BEGIN ENABLE Punt => GOTO out; runFile ← NewFile[s, Read, OldFileOnly ! FileNameError => {Explain["File not found"L]; GO TO out}]; LockFile[runFile]; IF ~OurLoad[ ! InsufficientVM => {Explain["Program too large"L]; GO TO out}] THEN GO TO cantExecute; cm ← LoaderOps.New[bcd, TRUE, FALSE ! BadCode => GO TO cantExecute; StringDefs.StringBoundsFault => {Explain["Unexpected string bounds fault"L]; GO TO out}; VersionMismatch => {Explain["Interface versions don't match", name]; GO TO out}; FileNotFound => {Explain["Code-containing subordinate .bcd missing", name]; GO TO out}; InsufficientVM => {Explain["Insufficient VM -- suggest restart"L]; OurUnload[]; GO TO out} ]; IF cm = ControlDefs.NullControl THEN GO TO cantExecute; END; FrameOps.Start[cm ! UNWIND => UnNewConfig[cm.frame]]; UnNewConfig[cm.frame]; EXITS cantExecute => Explain["File doesn't look like kosher code"L ! Punt => CONTINUE]; out => NULL; END; -- of RunBcd -- s: STRING ← [100]; originalVitalSigns, newVitalSigns: VitalSigns; runFile: SegmentDefs.FileHandle ← NIL; AppendString[s, bcdname]; [] ← Storage.Prune[]; originalVitalSigns ← GetVitalSigns[]; RunBcd[ ! Punt -- quit from user -- , ABORTED -- Quit from debugger -- => CONTINUE]; newVitalSigns ← GetVitalSigns[]; IF newVitalSigns.modules ~= originalVitalSigns.modules OR newVitalSigns.pages ~= originalVitalSigns.pages -- OR newVitalSigns.processes # originalVitalSigns.processes -- -- OR clientWords # 0 -- -- OR clientPages # 0 -- THEN BEGIN -- IF newVitalSigns.processes > originalVitalSigns.processes+2 THEN -- Explain["Warning: Processes left over"L ! Punt => CONTINUE]; IF newVitalSigns.modules ~= originalVitalSigns.modules THEN Explain["Warning: Modules left over"L ! Punt => CONTINUE]; -- IF newVitalSigns.pages ~= originalVitalSigns.pages THEN -- Explain["Warning: Pages left over"L ! Punt => CONTINUE]; -- IF clientPages # 0 OR clientWords # 0 THEN -- Explain["Warning: Subroutine dynamic storage left over"L ! Punt => CONTINUE]; END; IF runFile ~= NIL THEN {SegmentDefs.UnlockFile[runFile]; SegmentDefs.ReleaseFile[runFile]}; END; -- of DoRunBcd -- END.