-- Copyright (C) 1986 by Xerox Corporation. All rights reserved.
-- CRuntimeC.mesa
-- NFS 27-May-86 11:35:37
DIRECTORY
BcdDefs USING [CTIndex, MTIndex, NameRecord],
BcdOps USING [BcdBase, NameString],
BcdOpsExtras USING [CTBaseFromBcd, MTBaseFromBcd, NameStringFromBcd],
CRuntime USING [ProgramExited, z],
CRuntimeInternal USING [
ConfigHandle, GlobalFrameHandle, lock, MainArgsNeeded, SetConfig],
CString USING [CString, CStringToLongString],
Environment USING [bytesPerPage],
Format USING [LongDecimal, LongOctal, StringProc],
Heap USING [Delete, Flush, GetAttributes],
LoadState USING [LockBcdInfo, UnlockBcdInfo],
MFile USING [
Acquire, Error, GetAccess, GetFullName, Handle, maxNameLength, Release,
SetAccess],
MLoader USING [Error, Handle, Load, Start, VersionMismatch],
MLoaderImpl USING [Handle],
MStream USING [Error, GetFile, GetLength, Handle, IsIt, Log, SetLogReadLength],
PrincOps USING [GlobalFrameHandle],
SpecialRuntime USING [GlobalFrameFromProgram],
SpecialCRuntime USING [],
Stream USING [Delete, Handle, PutChar, SendNow],
String USING [AppendSubString, FreeString, SubStringDescriptor];
CRuntimeC: MONITOR LOCKS CRuntimeInternal.lock
IMPORTS
BcdOpsExtras, CRuntime, CRuntimeInternal, CString, Format, Heap, LoadState,
MFile, MLoader, MStream, SpecialRuntime, Stream, String
EXPORTS CRuntime, CRuntimeInternal, SpecialCRuntime
SHARES MLoaderImpl =
{
OPEN CRuntime;
normalOutcome: INTEGER = 0;
maxLogPages: LONG CARDINAL = 200; -- Maximum length of log file.
heapDelete: BOOLEAN ← TRUE; -- if false, heaps are flushed instead of deleted.
logging: BOOLEAN ← FALSE; -- flags if cleanup being logged.
StartProgram: PUBLIC PROCEDURE [
fileName: CString.CString, argc: CARDINAL,
argv: LONG POINTER TO CString.CString, stdin, stdout, stderr: Stream.Handle]
RETURNS [outcome: INTEGER ← normalOutcome] = {
file: LONG STRING ← CString.CStringToLongString[fileName, z];
{
ENABLE MFile.Error => {outcome ← -1; CONTINUE; };
fh: MFile.Handle;
lh: MLoader.Handle;
fh ← MFile.Acquire[name: file, access: readOnly, release: []];
{
ENABLE {
MLoader.Error, MLoader.VersionMismatch => {outcome ← -1; CONTINUE; };
CRuntime.ProgramExited => {outcome ← status; CONTINUE; };
CRuntimeInternal.MainArgsNeeded => RESUME [argc, argv];
};
lh ← MLoader.Load[fh];
CRuntimeInternal.SetConfig[GFForLH[lh], stdin, stdout, stderr];
MLoader.Start[lh];
};
MFile.Release[fh];
};
z.FREE[@file];
};
GFForLH: PROCEDURE [lh: MLoader.Handle] RETURNS [PrincOps.GlobalFrameHandle] =
INLINE {
RETURN[
SpecialRuntime.GlobalFrameFromProgram[
LOOPHOLE[lh, MLoaderImpl.Handle].program]];
};
LogCleanUp: PUBLIC INTERNAL PROCEDURE [cH: CRuntimeInternal.ConfigHandle]
RETURNS [cleanUpNeeded: BOOLEAN ← TRUE] = {
<<This proc. must be called even if not logging, to prevent attempting
to clean up twice. >>
ENABLE MStream.Error => CONTINUE;
bcd: BcdOps.BcdBase;
bcdName: String.SubStringDescriptor;
names: BcdOps.NameString;
bcdNameRecord: BcdDefs.NameRecord;
s: LONG STRING;
openFiles: BOOLEAN = (cH.openStreams # NIL) OR MStream.IsIt[cH.stdin]
OR MStream.IsIt[cH.stdout] OR MStream.IsIt[cH.stderr];
IF cH.heap = NIL AND ~openFiles THEN RETURN[FALSE];
IF ~logging OR log = NIL THEN RETURN;
bcd ← LoadState.LockBcdInfo[].bcdInfo[cH.config].base;
IF MStream.GetLength[log] > maxLogPages * Environment.bytesPerPage THEN {
Stream.Delete[log]; log ← NIL; GetLog[]; WriteLog["Restarted log"L]; };
names ← BcdOpsExtras.NameStringFromBcd[bcd];
bcdNameRecord ←
IF bcd.nConfigs # 0 THEN BcdOpsExtras.CTBaseFromBcd[bcd][
BcdDefs.CTIndex.FIRST].name
ELSE BcdOpsExtras.MTBaseFromBcd[bcd][BcdDefs.MTIndex.FIRST].name;
bcdName ← [
base: LOOPHOLE[names], offset: bcdNameRecord,
length: names.size[bcdNameRecord]];
s ← z.NEW[StringBody [bcdName.length]];
String.AppendSubString[to: s, from: @bcdName];
LoadState.UnlockBcdInfo[];
WriteLog["\N===================================\NCleaning up after "L];
WriteLog[s];
String.FreeString[z, s];
};
DeleteAndLogHeap: PUBLIC INTERNAL PROCEDURE [z: UNCOUNTED ZONE] = {
WriteLog[IF heapDelete THEN "\NDeleting heap "L ELSE "\NFlushing heap "L];
Format.LongOctal[WriteLog, LOOPHOLE[z]];
WriteLog[" (size: "L];
Format.LongDecimal[WriteLog, Heap.GetAttributes[z].heapPages];
WriteLog[" pages)..."L];
IF heapDelete THEN Heap.Delete[z: z, checkEmpty: FALSE] ELSE Heap.Flush[z];
WriteLog["done"L];
};
DeleteAndLogStream: PUBLIC INTERNAL PROCEDURE [sH: Stream.Handle] = {
IF MStream.IsIt[sH] THEN { -- write in log only if closing an MStream
ENABLE
MStream.Error, MFile.Error => {
WriteLog["\N*** Error closing file"L]; CONTINUE; };
fileName: LONG STRING ← [MFile.maxNameLength];
file: MFile.Handle = MStream.GetFile[sH];
WriteLog["\NClosing "L];
MFile.GetFullName[file, fileName];
WriteLog[fileName];
WriteLog["..."L];
IF MFile.GetAccess[file] = log THEN {
-- change access to writeOnly so that notify procs. are called.
MStream.SetLogReadLength[sH, MStream.GetLength[sH]];
MFile.SetAccess[file, writeOnly ! MFile.Error => CONTINUE];
};
Stream.Delete[sH];
WriteLog["done"L];
}
ELSE Stream.Delete[sH];
};
WriteLog: Format.StringProc = {
ENABLE MStream.Error => CONTINUE;
IF ~logging OR log = NIL THEN RETURN;
FOR i: CARDINAL IN [0..s.length) DO Stream.PutChar[log, s.text[i]]; ENDLOOP;
Stream.SendNow[log];
MStream.SetLogReadLength[log, MStream.GetLength[log]];
};
SetHeapDelete: PUBLIC ENTRY PROCEDURE [deleteHeap: BOOLEAN]
RETURNS [oldDeleteHeap: BOOLEAN] = {
oldDeleteHeap ← heapDelete;
heapDelete ← deleteHeap;
};
GetHeapDelete: PUBLIC ENTRY PROCEDURE RETURNS [deleteHeap: BOOLEAN] = {
deleteHeap ← heapDelete; };
SetLogging: PUBLIC ENTRY PROCEDURE [
newLogging: BOOLEAN] RETURNS[oldLogging: BOOLEAN] = {
oldLogging ← logging;
logging ← newLogging;
IF newLogging AND log = NIL THEN GetLog[];
};
GetLogging: PUBLIC ENTRY PROCEDURE RETURNS[isLogging: BOOLEAN] = {
isLogging ← logging;};
GetLog: PROCEDURE = {
log ← MStream.Log["CRuntime.log"L, [] ! MStream.Error => CONTINUE]; };
log: PUBLIC MStream.Handle ← NIL;
}.