-- 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; }.