-- 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] = {
<<Unloads and removes from start state, but doesn't check running
and doesn't remove config from C Runtime.>>
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]];
}.