-- Copyright (C) 1986 by Xerox Corporation. All rights reserved. -- StartStateImpl.mesa -- NFS 27-May-86 13:35:44 -- MEW 23-May-86 17:09:01 DIRECTORY CRuntime USING [CleanUp, GlobalFrameHandle, RemoveConfig, Restart, Start, z], CString USING [CString], File USING [File], Heap USING [CreateUniform], MFile USING [GetCreateDate, Handle], MLoader USING [Error, Handle, Load, Object, Unload, VersionMismatch], MLoaderImpl USING [Handle], PrincOps USING [GlobalFrameHandle], Space USING [Error], SpecialMFile USING [GetCapaWithAccess], SpecialRuntime USING [GlobalFrameFromProgram], StartState USING [abortOutcome, EnumerateProc, normalOutcome], Stream USING [Handle], Time USING [Packed]; StartStateImpl: MONITOR IMPORTS CRuntime, Heap, MFile, MLoader, Space, SpecialMFile, SpecialRuntime EXPORTS StartState SHARES MLoaderImpl = { loadTableSize: CARDINAL = 50; LTIndex: TYPE = [0..loadTableSize); Handle: TYPE = LONG POINTER TO Object; Object: PUBLIC TYPE = RECORD [ file: File.File, create: Time.Packed, lh: MLoader.Handle, running: BOOLEAN, lti: LTIndex, link: Handle]; LoadTable: TYPE = ARRAY LTIndex OF Handle; loadTable: LONG POINTER TO LoadTable; zone: PUBLIC UNCOUNTED ZONE ¬ Heap.CreateUniform[ initial: 1, objectSize: Object.SIZE]; normalOutcome: INTEGER = StartState.normalOutcome; abortOutcome: INTEGER = StartState.abortOutcome; GetHandle: PUBLIC ENTRY PROCEDURE [file: MFile.Handle] RETURNS [h: Handle, canRestart: BOOLEAN] = { ENABLE UNWIND => NULL; ff: File.File = SpecialMFile.GetCapaWithAccess[file]; lti: LTIndex = LTHash[ff]; create: Time.Packed = MFile.GetCreateDate[file]; ssh: Handle ¬ loadTable[lti]; DO SELECT TRUE FROM ssh = NIL => { ssh ¬ zone.NEW[Object ¬ [ff, create, NIL, TRUE, lti, loadTable[lti]]]; loadTable[lti] ¬ ssh; canRestart ¬ FALSE; EXIT; }; ssh.file = ff AND ssh.create = create AND ~ssh.running => { ssh.running ¬ TRUE; canRestart ¬ ssh.lh # NIL; EXIT; }; ENDCASE => ssh ¬ ssh.link; ENDLOOP; RETURN[ssh, canRestart]; }; LTHash: PROCEDURE [file: File.File] RETURNS [LTIndex] = INLINE { RETURN[CARDINAL[LOOPHOLE[file.fileID, INT]] MOD loadTableSize]; }; LoadError: PUBLIC ERROR [message: LONG STRING] = CODE; VersionMismatch: PUBLIC SIGNAL [module: LONG STRING] = CODE; UnloadError: PUBLIC ERROR [ message: LONG STRING, instancesAlreadyUnloaded: CARDINAL] = CODE; Load: PUBLIC PROCEDURE [h: Handle, fh: MFile.Handle] = { ENABLE UNWIND => {ClearRunning[h]; SetLoadHandle[h, NIL]; }; h.lh ¬ MLoader.Load[ fh ! MLoader.Error => ERROR LoadError[ SELECT code FROM badCode => "not /-a code"L, invalidParameters => "not in valid bcd format"L, missingCode => "missing code"L, exportedTypeClash => "exported type clash"L, lookupFailure => "look up failure"L, gftFull => "out of space in MDS"L, loadStateFull => "load state full"L, ENDCASE => "unknown loader error"L]; MLoader.VersionMismatch => {SIGNAL VersionMismatch[module]; RESUME }; Space.Error => -- Since MLoader doesn't catch it ERROR LoadError["Space error while loading"L]]; }; Unload: PUBLIC ENTRY PROCEDURE [h: MLoader.Handle] = { ENABLE UNWIND => NULL; searcher, follower: Handle; ssh: Handle = HandleForMLoaderHandle[h]; IF ssh = NIL THEN ERROR UnloadError["Invalid Handle"L, 0]; IF ssh.running THEN ERROR UnloadError["Program running"L, 0]; searcher ¬ loadTable[ssh.lti]; follower ¬ NIL; UNTIL searcher = ssh DO follower ¬ searcher; searcher ¬ searcher.link; ENDLOOP; UnloadAndRemove[ssh, follower ! MLoader.Error => ERROR UnloadError[string, 0]]; }; HandleForMLoaderHandle: INTERNAL PROCEDURE [lh: MLoader.Handle] RETURNS [h: Handle] = { FOR lti: LTIndex IN LTIndex DO h ¬ loadTable[lti]; WHILE h # NIL DO IF h.lh = lh THEN RETURN; h ¬ h.link; ENDLOOP; ENDLOOP; }; UnloadFromFile: PUBLIC ENTRY PROC [file: MFile.Handle] RETURNS [instancesUnloaded: CARDINAL ¬ 0] = { -- Unloads every loaded instance. Does not compare create dates. ENABLE UNWIND => NULL; ff: File.File = SpecialMFile.GetCapaWithAccess[file]; lti: LTIndex = LTHash[ff]; searcher, follower: Handle; searcher ¬ loadTable[lti]; follower ¬ NIL; WHILE searcher # NIL DO IF searcher.file = ff AND searcher.lh # NIL THEN { IF searcher.running THEN ERROR UnloadError["Program instance running"L, instancesUnloaded]; UnloadAndRemove[ searcher, follower ! MLoader.Error => UnloadError[string, instancesUnloaded]]; instancesUnloaded ¬ instancesUnloaded.SUCC; searcher ¬ IF follower = NIL THEN loadTable[lti] ELSE follower.link; } ELSE {follower ¬ searcher; searcher ¬ searcher.link; }; ENDLOOP; }; UnloadAndRemove: INTERNAL PROCEDURE [h, precedingHandle: Handle] = { CRuntime.RemoveConfig[GFForHandle[h]]; MLoader.Unload[h.lh]; IF precedingHandle = NIL THEN loadTable[h.lti] ¬ h.link ELSE precedingHandle.link ¬ h.link; zone.FREE[@h]; }; UnloadUnstartedProgram: PUBLIC ENTRY PROC [h: Handle] = { <> ENABLE UNWIND => NULL; searcher, follower: Handle; searcher ¬ loadTable[h.lti]; follower ¬ NIL; UNTIL searcher = h DO follower ¬ searcher; searcher ¬ searcher.link; ENDLOOP; IF follower = NIL THEN loadTable[h.lti] ¬ h.link ELSE follower.link ¬ h.link; MLoader.Unload[h.lh ! MLoader.Error => ERROR UnloadError[string, 0]]; zone.FREE[@h]; }; Start: PUBLIC PROCEDURE [ h: Handle, argc: CARDINAL, argv: LONG POINTER TO CString.CString, stdin, stdout, stderr: Stream.Handle] RETURNS [outcome: INTEGER ¬ normalOutcome] = { ENABLE UNWIND => ClearRunning[h]; gf: PrincOps.GlobalFrameHandle = GFForHandle[h]; outcome ¬ CRuntime.Start[ GFForHandle[h], argc, argv, stdin, stdout, stderr ! UNWIND => CRuntime.CleanUp[]]; CRuntime.CleanUp[]; ClearRunning[h]; }; Restart: PUBLIC PROCEDURE [ h: Handle, argc: CARDINAL, argv: LONG POINTER TO CString.CString, stdin, stdout, stderr: Stream.Handle] RETURNS [outcome: INTEGER ¬ normalOutcome] = { ENABLE UNWIND => ClearRunning[h]; outcome ¬ CRuntime.Restart[ GFForHandle[h], argc, argv, stdin, stdout, stderr ! UNWIND => CRuntime.CleanUp[]]; CRuntime.CleanUp[]; ClearRunning[h]; }; StartOrRestart: PUBLIC PROCEDURE [ file: MFile.Handle, argc: CARDINAL, argv: LONG POINTER TO CString.CString, stdin, stdout, stderr: Stream.Handle] RETURNS [outcome: INTEGER] = { ssh: Handle; restart: BOOLEAN; [ssh, restart] ¬ GetHandle[file]; IF restart THEN RETURN[Restart[ssh, argc, argv, stdin, stdout, stderr]] ELSE { [] ¬ Load[ssh, file]; RETURN[Start[ssh, argc, argv, stdin, stdout, stderr]]; }; }; GFForHandle: PROCEDURE [ssh: Handle] RETURNS [gf: PrincOps.GlobalFrameHandle] = { p: PROGRAM = LOOPHOLE[ssh.lh, MLoaderImpl.Handle].program; gf ¬ SpecialRuntime.GlobalFrameFromProgram[p]; }; EnumerateHandles: PUBLIC ENTRY PROCEDURE [ file: MFile.Handle, proc: StartState.EnumerateProc] = { ff: File.File = SpecialMFile.GetCapaWithAccess[file]; lti: LTIndex = LTHash[ff]; ssh: Handle ¬ loadTable[lti]; WHILE ssh # NIL DO IF ssh.file = ff THEN IF proc[ssh, ssh.lh] THEN EXIT; ssh ¬ ssh.link; ENDLOOP; }; GetLoadHandle: PUBLIC ENTRY PROCEDURE [h: Handle] RETURNS [MLoader.Handle] = { ENABLE UNWIND => NULL; RETURN[h.lh]; }; SetLoadHandle: PUBLIC ENTRY PROCEDURE [h: Handle, lh: MLoader.Handle] = { ENABLE UNWIND => NULL; h.lh ¬ lh; }; ClearRunning: ENTRY PROCEDURE [h: Handle] = { ENABLE UNWIND => NULL; h.running ¬ FALSE; }; loadTable ¬ CRuntime.z.NEW[LoadTable ¬ ALL[NIL]]; }.