-- Copyright (C) 1986 by Xerox Corporation. All rights reserved.
-- CRuntimeA.mesa
-- NFS 5-Mar-86 17:37:14
-- MEW 14-Apr-86 13:25:52
DIRECTORY
BcdOps USING [BcdBase],
AtomVariants USING [ATRecord],
BucketAlloc USING [BucketInfo, Initialize],
CAbort USING [],
CBasics USING [ArraySpaceHandle, CommonRecPtr],
CRuntime USING [abortOutcome, FilePtr],
CRuntimeInternal USING [
ArraySpace, ConfigEntry, ConfigHandle, DeleteAndLogHeap, DeleteAndLogStream,
GFEntry, GFIndex, GFList, GFTable, gfTableSize, lock, LogCleanUp, ProcessEntry,
ProcessIndex, ProcessList, ProcessTable, processTableSize, SHEntry, SHIndex,
SHList, SHTable, shTableSize, StreamEntry, StreamList],
Environment USING [PageCount, Word, wordsPerPage],
File USING [Create, Delete, Error, File, GetSize],
FileTypes USING [tUntypedFile],
Frame USING [GetReturnFrame, ReadGlobalLink],
Heap USING [Create, Delete, Flush, MakeNode],
Inline USING [LongCOPY, LowHalf],
LoadState USING [
GetModuleInfo, LockBcdInfo, LPBcdInfoTable,
ModuleInfoSequenceHandle, ModuleInfosOfBcd,
ModuleInfoRange, UnlockBcdInfo],
LoadStateFormat USING [ModuleInfo],
PrincOps USING [GlobalFrameHandle],
Process USING [GetCurrent],
Space USING [Kill, MakeReadOnly, Map, SwapUnitSize, Unmap],
SpecialCRuntime USING [],
Stream USING [Handle],
Table USING [Base],
Volume USING [InsufficientSpace, systemID];
CRuntimeA: MONITOR LOCKS CRuntimeInternal.lock
IMPORTS
BucketAlloc, CRuntimeInternal, File, Heap, Inline, Frame, LoadState, Process,
Space, Volume
EXPORTS CAbort, CBasics, CRuntime, CRuntimeInternal, SpecialCRuntime =
{
OPEN CRuntime, CRuntimeInternal;
GlobalFrameHandle: TYPE = PrincOps.GlobalFrameHandle;
ConfigEntry: PUBLIC TYPE = CRuntimeInternal.ConfigEntry;
ConfigHandle: TYPE = LONG POINTER TO ConfigEntry;
CEList: PUBLIC ConfigHandle ← NIL;
z: PUBLIC UNCOUNTED ZONE;
arrayZone: PUBLIC UNCOUNTED ZONE;
lock: PUBLIC MONITORLOCK;
gfTable: PUBLIC LONG POINTER TO GFTable;
shTable: PUBLIC LONG POINTER TO SHTable;
processTable: PUBLIC LONG POINTER TO ProcessTable;
ArraySpace: PUBLIC TYPE = CRuntimeInternal.ArraySpace;
GFHash: PROCEDURE [gf: GlobalFrameHandle] RETURNS [GFIndex] = INLINE {
RETURN[(LOOPHOLE[gf, CARDINAL] / 4) MOD gfTableSize]; };
ModuleNotRegistered: SIGNAL [gfh: GlobalFrameHandle] = CODE;
ProcessNotRegistered: PUBLIC ERROR = CODE;
TooMuchGlobalArraySpace: PUBLIC ERROR = CODE;
arraySpaceThreshold: PUBLIC Environment.PageCount ← 5;
heapSize: PUBLIC Environment.PageCount ← 10;
checkUnusedSpace: BOOLEAN ← FALSE;
dataSwapUnitSize: CARDINAL ← 4;
codeSwapUnitSize: CARDINAL ← 2;
GetBcdInfo: PUBLIC PROC RETURNS [numArgs: CARDINAL,
arraySize: LONG CARDINAL,
commonInfo: CBasics.CommonRecPtr] = {
bcdInfo: LoadState.LPBcdInfoTable;
frame: PrincOps.GlobalFrameHandle;
modinfo: LoadStateFormat.ModuleInfo;
atb: LONG POINTER TO cInfo AtomVariants.ATRecord;
bcd: BcdOps.BcdBase;
[, bcdInfo] ← LoadState.LockBcdInfo[];
frame ← Frame.ReadGlobalLink[Frame.GetReturnFrame[]];
modinfo ← LoadState.GetModuleInfo[frame];
bcd ← bcdInfo[modinfo.index].base;
LoadState.UnlockBcdInfo[];
IF bcd.atLimit = LOOPHOLE[0] THEN
RETURN[0,0,NIL];
atb ← ATBaseFromBcd[bcd];
numArgs ← atb.numMainArgs;
arraySize ← atb.arraySpaceSize[0];
IF bcd.atLimit = LOOPHOLE[SIZE[AtomVariants.ATRecord]
+ SIZE[LONG CARDINAL]] THEN
RETURN[numArgs, arraySize, NIL];
commonInfo ← atb + SIZE[AtomVariants.ATRecord] + SIZE[LONG CARDINAL];
RETURN[numArgs, arraySize, commonInfo]};
-- ATBaseFromBcd: analogous to BcdOpsExtras.MTBaseFromBcd
ATBaseFromBcd: PROC [bcd: BcdOps.BcdBase] RETURNS [Table.Base] = INLINE {
RETURN[LOOPHOLE[bcd + bcd.atOffset]]};
-- GetCommons called from the driver module, performs the allocation of common space and initializes pointers in the global frame of the driver module to point to the various commons.
GetCommons: PUBLIC PROCEDURE [comm: CBasics.CommonRecPtr,
comSpace: CBasics.ArraySpaceHandle ] = {
ptrptr: POINTER TO LONG POINTER ← NIL;
driversGF: PrincOps.GlobalFrameHandle = Frame.ReadGlobalLink[
Frame.GetReturnFrame[]];
ptrptr ← LOOPHOLE[driversGF + comm.commPtrOffset];
FOR i: CARDINAL IN [0..comm.twiceNumCommons / 2) DO
ptrptr↑ ← NextArray[comSpace, comm.items[i]];
ptrptr ← ptrptr + SIZE[LONG POINTER];
ENDLOOP}; -- GetCommons
-- GetTotalSize computes the total ammount of space required for all the commons which are declared in this config.
GetCommonSize: PUBLIC PROCEDURE [comm: CBasics.CommonRecPtr]
RETURNS [totSize: LONG CARDINAL ← 0] = {
FOR i: CARDINAL IN [0..comm.twiceNumCommons / 2) DO
totSize ← totSize + comm.items[i]; ENDLOOP;
RETURN[totSize]}; -- GetTotalSize
ConfigHandleForGF: INTERNAL PROCEDURE [gf: GlobalFrameHandle]
RETURNS [ConfigHandle] = {
hashValue: GFIndex = GFHash[gf];
searcher: GFList ← gfTable[hashValue];
IF searcher = NIL THEN SIGNAL ModuleNotRegistered[gf];
UNTIL searcher.gf = gf DO
searcher ← searcher.link;
IF searcher = NIL THEN SIGNAL ModuleNotRegistered[gf];
ENDLOOP;
RETURN[searcher.config];
};
RegisterConfig: PUBLIC ENTRY PROCEDURE [wordsNeeded: LONG CARDINAL] = {
ENABLE UNWIND => NULL;
gf: GlobalFrameHandle = Frame.ReadGlobalLink[Frame.GetReturnFrame[]];
ch: ConfigHandle ← AssociateProcessWithGF[gf];
IF ch.data = NIL THEN ch.data ← MakeArraySpace[wordsNeeded];
IF ch.data # NIL THEN {
ch.data.nextArray ← ch.data.space + ch.data.firstArrayOffset;
ZeroFill[ch.data.nextArray, ch.data.words];
};
};
RegisterFrame: PUBLIC ENTRY PROCEDURE [wordsNeeded: LONG CARDINAL]
RETURNS [CBasics.ArraySpaceHandle] = {
ENABLE UNWIND => NULL;
gf: GlobalFrameHandle = Frame.ReadGlobalLink[Frame.GetReturnFrame[]];
gfi: GFIndex;
ge: GFList;
ch: ConfigHandle ← AssociateProcessWithGF[gf];
gfi ← GFHash[gf];
ge ← gfTable[gfi];
WHILE ge # NIL DO
IF ge.gf = gf THEN {
IF ge.data # NIL THEN {
ge.data.nextArray ← ge.data.space + ge.data.firstArrayOffset;
ZeroFill[ge.data.nextArray, ge.data.words];
};
RETURN[IF ch.data = NIL THEN ge.data ELSE ch.data];
};
ge ← ge.link;
ENDLOOP;
gfTable[gfi] ← MakeGFEntry[gfi, gf, wordsNeeded, ch.data = NIL];
RETURN[IF ch.data = NIL THEN gfTable[gfi].data ELSE ch.data];
};
MakeGFEntry: INTERNAL PROCEDURE [
gfi: GFIndex, gf: GlobalFrameHandle, wordsNeeded: LONG CARDINAL,
localData: BOOLEAN]
RETURNS [gfl: GFList] = {
ch: ConfigHandle ← NIL;
moduleInfo: LoadStateFormat.ModuleInfo = LoadState.GetModuleInfo[gf];
ch ← ConfigHandleForConfig[moduleInfo.index, gf];
IF ch.data = NIL AND ~localData THEN
ch.data ← MakeArraySpace[wordsNeeded];
IF localData THEN gfl ← z.NEW[
GFEntry ← [gf, ch, gfTable[gfi], MakeArraySpace[wordsNeeded]]]
ELSE gfl ← z.NEW[GFEntry ← [gf, ch, gfTable[gfi], NIL]];
};
MakeArraySpace: PROCEDURE [wordsNeeded: LONG CARDINAL]
RETURNS [ah: LONG POINTER TO ArraySpace] = {
IF wordsNeeded > 0 THEN {
pages: Environment.PageCount ← PagesForWords[wordsNeeded];
IF pages > arraySpaceThreshold THEN {
file: File.File;
ah ← z.NEW[large ArraySpace];
IF checkUnusedSpace THEN {
swapUnits: ARRAY [1..2] OF Space.SwapUnitSize ← [CARDINAL[pages], 1];
ah.firstArrayOffset ← CARDINAL[
(pages * Environment.wordsPerPage) - wordsNeeded];
pages ← pages + 1;
file ← File.Create[
volume: Volume.systemID, initialSize: pages,
type: FileTypes.tUntypedFile !
File.Error, Volume.InsufficientSpace =>
ERROR TooMuchGlobalArraySpace];
ah.space ← Space.Map[
window: [file: file, base: 0, count: pages], life: dead,
swapUnits: [irregular[DESCRIPTOR[swapUnits]]]].pointer;
Space.MakeReadOnly[
interval: [
pointer: ah.space + ((pages - 1) * Environment.wordsPerPage),
count: 1]];
ah.nextArray ← ah.space + ah.firstArrayOffset;
}
ELSE { -- no unused space check
file ← File.Create[
volume: Volume.systemID, initialSize: pages,
type: FileTypes.tUntypedFile !
File.Error, Volume.InsufficientSpace =>
ERROR TooMuchGlobalArraySpace];
ah.space ← ah.nextArray ← Space.Map[
window: [file: file, base: 0, count: pages], life: dead,
swapUnits: [uniform[size: ]]].pointer;
ah.firstArrayOffset ← 0;
};
ah.filePart ← large[file];
}
ELSE {
ah ← z.NEW[small ArraySpace];
ah.space ← ah.nextArray ← Heap.MakeNode[
arrayZone, CARDINAL[wordsNeeded]];
ah.firstArrayOffset ← 0;
ah.filePart ← small[];
};
ah.words ← wordsNeeded;
ZeroFill[ah.nextArray, ah.words];
}
ELSE ah ← NIL};
PagesForWords: PROCEDURE [nWords: LONG CARDINAL]
RETURNS [Environment.PageCount] = INLINE {
RETURN[(nWords + Environment.wordsPerPage - 1) / Environment.wordsPerPage]; };
NextArray: PUBLIC PROCEDURE [
heap: LONG POINTER TO ArraySpace, nWords: LONG CARDINAL]
RETURNS [next: LONG POINTER] = {
next ← heap.nextArray; heap.nextArray ← heap.nextArray + nWords; };
ZeroFill: PROCEDURE [space: LONG POINTER, words: LONG CARDINAL] = {
-- Initializes global array space to all zeroes.
largeSpace: BOOLEAN = words > LONG[CARDINAL.LAST];
words1: CARDINAL = IF largeSpace THEN CARDINAL.LAST ELSE CARDINAL[words];
IF words = 0 THEN RETURN;
LOOPHOLE[space, LONG POINTER TO Environment.Word]↑ ← 0;
Inline.LongCOPY[from: space, nwords: words1 - 1, to: space + 1];
IF largeSpace THEN {
words2: CARDINAL = CARDINAL[words - LONG[CARDINAL.LAST]];
ptr: LONG POINTER = space + CARDINAL.LAST;
LOOPHOLE[ptr, LONG POINTER TO Environment.Word]↑ ← 0;
Inline.LongCOPY[from: ptr, nwords: words2 - 1, to: ptr + 1];
};
};
ConfigHandleForConfig: INTERNAL PROCEDURE [
config: CARDINAL, gf: GlobalFrameHandle] RETURNS [cH: ConfigHandle] = {
searcher: ConfigHandle ← CEList;
[] ← LoadState.LockBcdInfo[];
WHILE searcher # NIL DO
Validate[searcher];
IF searcher.config = config THEN {cH ← searcher; GOTO Unlock; };
searcher ← searcher.link;
ENDLOOP;
CEList ← NewConfigEntry[config, gf, NIL, NIL, NIL];
cH ← CEList;
GOTO Unlock;
EXITS Unlock => LoadState.UnlockBcdInfo[];
};
NewConfigEntry: INTERNAL PROCEDURE [
config: CARDINAL, gf: GlobalFrameHandle, stdin, stdout, stderr: Stream.Handle]
RETURNS [ConfigHandle] = INLINE {
RETURN[
z.NEW[
ConfigEntry ← [
config: config, gf: gf, heap: NIL, openStreams: NIL, stdin: stdin,
stdout: stdout, stderr: stderr, link: CEList, data: NIL]]];
};
SetConfig: PUBLIC ENTRY PROCEDURE [
gf: GlobalFrameHandle, stdin, stdout, stderr: Stream.Handle] = {
ENABLE UNWIND => NULL;
moduleInfo: LoadStateFormat.ModuleInfo = LoadState.GetModuleInfo[gf];
CEList ← NewConfigEntry[moduleInfo.index, gf, stdin, stdout, stderr];
EnterStreamGloballyInternal[stdin];
EnterStreamGloballyInternal[stdout];
EnterStreamGloballyInternal[stderr];
};
ResetConfig: PUBLIC ENTRY PROCEDURE [
gf: GlobalFrameHandle, stdin, stdout, stderr: Stream.Handle] = {
ENABLE UNWIND => NULL;
cH: ConfigHandle;
moduleInfo: LoadStateFormat.ModuleInfo = LoadState.GetModuleInfo[gf];
cH ← ConfigHandleForConfig[moduleInfo.index, gf];
IF cH.openStreams # NIL THEN FreeOpenStreamList[cH];
IF cH.heap # NIL THEN Heap.Flush[cH.heap];
cH.stdin ← stdin;
cH.stdout ← stdout;
cH.stderr ← stderr;
EnterStreamGloballyInternal[stdin];
EnterStreamGloballyInternal[stdout];
EnterStreamGloballyInternal[stderr];
cH.openStreams ← NIL;
};
RegisterProcess: PUBLIC ENTRY PROCEDURE = {
ENABLE UNWIND => NULL;
[] ← AssociateProcessWithGF[Frame.ReadGlobalLink[Frame.GetReturnFrame[]]];
};
AssociateProcessWithGF: INTERNAL PROCEDURE [gf: GlobalFrameHandle]
RETURNS [cH: ConfigHandle] = {
cH ← ConfigHandleForConfig[LoadState.GetModuleInfo[gf].index, gf];
AssociateProcessWithConfig[cH];
};
AssociateProcessWithConfig: INTERNAL PROCEDURE [cH: ConfigHandle] = {
p: PROCESS = Process.GetCurrent[];
pti: ProcessIndex = PHash[p];
pl: ProcessList ← processTable[pti];
<<Check if process already there, and reuse the process entry if it is.>>
WHILE pl # NIL DO
IF pl.p = p THEN {pl.config ← cH; RETURN; }; pl ← pl.link; ENDLOOP;
pl ← z.NEW[ProcessEntry ← [p: p, config: cH, link: processTable[pti]]];
processTable[pti] ← pl;
};
ConfigHandleForProcess: INTERNAL PROCEDURE RETURNS [ConfigHandle] = {
p: PROCESS = Process.GetCurrent[];
pl: ProcessList ← processTable[PHash[p]];
WHILE pl # NIL DO IF pl.p = p THEN RETURN[pl.config]; pl ← pl.link; ENDLOOP;
ERROR ProcessNotRegistered;
};
GetConfigHandle: PUBLIC ENTRY PROCEDURE RETURNS [ConfigHandle] = {
RETURN[ConfigHandleForProcess[]]; };
SetConfigHandle: PUBLIC ENTRY PROCEDURE [cH: ConfigHandle] = {
AssociateProcessWithConfig[cH]; };
PHash: PROCEDURE [p: PROCESS] RETURNS [ProcessIndex] = {
RETURN[LOOPHOLE[p, CARDINAL] MOD processTableSize]; };
FreeOpenStreamList: INTERNAL PROCEDURE [cH: ConfigHandle] = {
s1, s2: StreamList;
s1 ← cH.openStreams;
WHILE s1 # NIL DO s2 ← s1.link; z.FREE[@s1]; s1 ← s2; ENDLOOP;
};
RemoveConfig: PUBLIC ENTRY PROC [gf: GlobalFrameHandle] = {
ENABLE UNWIND => NULL;
cH: ConfigHandle;
moduleSeq: LoadState.ModuleInfoSequenceHandle;
searcher, follower: ConfigHandle;
cH ← ConfigHandleForGF[gf ! ModuleNotRegistered => GOTO NotRegisterd];
IF cH.heap # NIL THEN Heap.Delete[z: cH.heap, checkEmpty: FALSE];
[] ← LoadState.LockBcdInfo[];
Validate[cH];
moduleSeq ← LoadState.ModuleInfosOfBcd[cH.config, z];
-- Remove each gf from gfTable and unmap global array space.
FOR i: LoadState.ModuleInfoRange IN [0..moduleSeq.length) DO
RemoveGF[moduleSeq[i].gf]; ENDLOOP;
-- Remove cH from list of config entries.
searcher ← CEList;
follower ← NIL;
UNTIL searcher = cH DO follower ← searcher; searcher ← searcher.link; ENDLOOP;
IF follower = NIL THEN CEList ← searcher.link
ELSE follower.link ← searcher.link;
IF searcher.data # NIL THEN { -- if space was mapped
WITH a: searcher.data↑ SELECT FROM
large => {[] ← Space.Unmap[pointer: a.space]; File.Delete[a.file]; };
small => arrayZone.FREE[@a.space];
ENDCASE;
z.FREE[@searcher.data];
};
z.FREE[@searcher];
z.FREE[@moduleSeq];
LoadState.UnlockBcdInfo[];
EXITS NotRegisterd => NULL;
};
RemoveGF: INTERNAL PROCEDURE [gf: GlobalFrameHandle] = {
gfi: GFIndex = GFHash[gf];
searcher, follower: GFList;
searcher ← gfTable[gfi];
follower ← NIL;
UNTIL searcher = NIL OR searcher.gf = gf DO
follower ← searcher; searcher ← searcher.link; ENDLOOP;
IF searcher = NIL THEN RETURN;
IF searcher.data # NIL THEN { -- if space was mapped
WITH a: searcher.data↑ SELECT FROM
large => {[] ← Space.Unmap[pointer: a.space]; File.Delete[a.file]; };
small => arrayZone.FREE[@a.space];
ENDCASE;
z.FREE[@searcher.data];
};
IF follower = NIL THEN gfTable[gfi] ← searcher.link
ELSE follower.link ← searcher.link;
z.FREE[@searcher];
};
Validate: PROCEDURE [cH: ConfigHandle] = {
cH.config ← LoadState.GetModuleInfo[cH.gf].index; };
GetHeap: PUBLIC ENTRY PROCEDURE RETURNS [UNCOUNTED ZONE] = {
ENABLE UNWIND => NULL; RETURN[ConfigHandleForProcess[]↑.heap]; };
SetHeap: PUBLIC ENTRY PROCEDURE [h: UNCOUNTED ZONE] = {
ENABLE UNWIND => NULL; ConfigHandleForProcess[]↑.heap ← h; };
SHHash: PROCEDURE [sh: Stream.Handle] RETURNS [SHIndex] = INLINE {
RETURN[(LOOPHOLE[Inline.LowHalf[sh], CARDINAL] / 4) MOD shTableSize]; };
EnterStream: PUBLIC ENTRY PROCEDURE [sH: Stream.Handle] RETURNS [FilePtr] = {
ENABLE UNWIND => NULL;
cH: ConfigHandle = ConfigHandleForProcess[];
newStream: StreamList = z.NEW[StreamEntry ← [sH, cH.openStreams]];
cH.openStreams ← newStream;
EnterStreamGloballyInternal[sH];
RETURN[@newStream.sH];
};
EnterStreamGlobally: PUBLIC ENTRY PROC [sH: Stream.Handle] = {
ENABLE UNWIND => NULL; EnterStreamGloballyInternal[sH]; };
EnterStreamGloballyInternal: INTERNAL PROCEDURE [sH: Stream.Handle] = {
shi: SHIndex = SHHash[sH];
shl: SHList;
shl ← shTable[shi];
WHILE shl # NIL DO
IF shl.sh = sH THEN {shl.refCount ← shl.refCount.SUCC; RETURN; };
shl ← shl.link;
ENDLOOP;
shTable[shi] ← z.NEW[SHEntry ← [sh: sH, refCount: 1, link: shTable[shi]]];
};
RemoveStream: PUBLIC ENTRY PROCEDURE [sH: Stream.Handle]
RETURNS [canDeleteStream: BOOLEAN] = {
ENABLE UNWIND => NULL;
cH: ConfigHandle;
-- OK if sH not in list . Might not have been opened with fopen.
searcher: StreamList;
IF sH = NIL THEN RETURN [FALSE];
cH ← ConfigHandleForProcess[];
searcher ← cH.openStreams;
UNTIL searcher = NIL OR searcher.sH = sH DO searcher ← searcher.link; ENDLOOP;
IF searcher # NIL THEN searcher.sH ← NIL;
-- check if sH is a standard stream
SELECT sH FROM
cH.stdin => cH.stdin ← NIL;
cH.stdout => cH.stdout ← NIL;
cH.stderr => cH.stderr ← NIL;
ENDCASE;
canDeleteStream ← RemoveStreamGlobally[sH]; --called even if not in list
};
RemoveStreamGlobally: INTERNAL PROCEDURE [sH: Stream.Handle]
RETURNS [canDeleteStream: BOOLEAN] = {
-- decrements ref. count and removes entry if ref. count becomes 0.
searcher, follower: SHList;
shi: SHIndex ← SHHash[sH];
searcher ← shTable[shi];
follower ← NIL;
UNTIL searcher = NIL OR searcher.sh = sH DO
follower ← searcher; searcher ← searcher.link; ENDLOOP;
IF searcher = NIL THEN RETURN[TRUE];
searcher.refCount ← searcher.refCount.PRED;
IF searcher.refCount = 0 THEN {
canDeleteStream ← TRUE;
IF follower = NIL THEN shTable[shi] ← searcher.link
ELSE follower.link ← searcher.link;
z.FREE[@searcher];
}
ELSE canDeleteStream ← FALSE;
};
CanDelete: PUBLIC ENTRY PROC [sh: Stream.Handle] RETURNS [BOOLEAN] = {
-- Returns true if sh not in global stream table.
ENABLE UNWIND => NULL;
shi: SHIndex = SHHash[sh];
shl: SHList;
shl ← shTable[shi];
WHILE shl # NIL DO IF shl.sh = sh THEN RETURN[FALSE]; shl ← shl.link; ENDLOOP;
RETURN[TRUE];
};
ProgramExited: PUBLIC ERROR [status: INTEGER] = CODE;
exit: PUBLIC PROCEDURE [status: INTEGER] RETURNS [INTEGER ← 0] = {
CleanUp[]; ERROR ProgramExited[status]; };
abort: PUBLIC PROCEDURE RETURNS [INTEGER ← 0] = {
CleanUp[]; ERROR ProgramExited[abortOutcome]; };
CleanUp: PUBLIC ENTRY PROCEDURE = {
-- Deletes heap and closes open streams.
ENABLE UNWIND => NULL; CleanUpConfig[ConfigHandleForProcess[]]; };
CleanUpConfig: INTERNAL PROCEDURE [cH: ConfigHandle] = {
sl: StreamList;
IF ~LogCleanUp[cH].cleanUpNeeded THEN RETURN;
-- delete heap
IF cH.heap # NIL THEN {DeleteAndLogHeap[z: cH.heap]; cH.heap ← NIL; };
-- close standard streams
IF cH.stdin # NIL AND RemoveStreamGlobally[cH.stdin].canDeleteStream THEN
DeleteAndLogStream[cH.stdin];
IF cH.stdout # NIL AND RemoveStreamGlobally[cH.stdout].canDeleteStream THEN
DeleteAndLogStream[cH.stdout];
IF cH.stderr # NIL AND RemoveStreamGlobally[cH.stderr].canDeleteStream THEN
DeleteAndLogStream[cH.stderr];
-- close other open files
sl ← cH.openStreams;
WHILE sl # NIL DO
nextsl: StreamList ← sl.link;
IF sl.sH # cH.stdin AND sl.sH # cH.stdout AND sl.sH # cH.stderr
AND sl.sH # NIL THEN {
IF RemoveStreamGlobally[sl.sH].canDeleteStream THEN
DeleteAndLogStream[sl.sH];
};
z.FREE[@sl];
sl ← nextsl;
ENDLOOP;
cH.openStreams ← NIL;
cH.stdin ← cH.stdout ← cH.stderr ← NIL;
IF cH.data # NIL THEN WITH ah: cH.data SELECT FROM
large =>
Space.Kill[
interval: [pointer: cH.data.space, count: File.GetSize[ah.file]]];
ENDCASE;
};
GetStdin: PUBLIC ENTRY PROCEDURE RETURNS [FilePtr] = {
ENABLE UNWIND => NULL; RETURN[@(ConfigHandleForProcess[].stdin)]; };
GetStdout: PUBLIC ENTRY PROCEDURE RETURNS [FilePtr] = {
ENABLE UNWIND => NULL; RETURN[@(ConfigHandleForProcess[].stdout)]; };
GetStderr: PUBLIC ENTRY PROCEDURE RETURNS [FilePtr] = {
ENABLE UNWIND => NULL; RETURN[@(ConfigHandleForProcess[].stderr)]; };
SetStdin: PUBLIC ENTRY PROCEDURE [fp: FilePtr] = {
ENABLE UNWIND => NULL;
cH: ConfigHandle = ConfigHandleForProcess[];
cH.stdin ← IF fp = NIL THEN NIL ELSE fp↑;
};
SetStdout: PUBLIC ENTRY PROCEDURE [fp: FilePtr] = {
ENABLE UNWIND => NULL;
cH: ConfigHandle = ConfigHandleForProcess[];
cH.stdout ← IF fp = NIL THEN NIL ELSE fp↑;
};
SetStderr: PUBLIC ENTRY PROCEDURE [fp: FilePtr] = {
ENABLE UNWIND => NULL;
cH: ConfigHandle = ConfigHandleForProcess[];
cH.stderr ← IF fp = NIL THEN NIL ELSE fp↑;
};
SetUnusedSpaceCheck: PUBLIC ENTRY PROCEDURE [checkSpace: BOOLEAN]
RETURNS [oldCheckSpace: BOOLEAN] = {
oldCheckSpace ← checkUnusedSpace; checkUnusedSpace ← checkSpace; };
GetUnusedSpaceCheck: PUBLIC ENTRY PROCEDURE RETURNS [checkSpace: BOOLEAN] = {
checkSpace ← checkUnusedSpace; };
SetDataSwapUnitSize:PUBLIC ENTRY PROCEDURE[size:CARDINAL]
RETURNS [oldSize:CARDINAL] = {
oldSize ← dataSwapUnitSize;
dataSwapUnitSize ← size;
};
SetCodeSwapUnitSize:PUBLIC ENTRY PROCEDURE[size:CARDINAL]
RETURNS [oldSize:CARDINAL] = {
oldSize ← codeSwapUnitSize;
codeSwapUnitSize ← size;
};
GetDataSwapUnitSize:PUBLIC ENTRY PROCEDURE RETURNS [size:CARDINAL] = {
size ← dataSwapUnitSize;
};
GetCodeSwapUnitSize:PUBLIC ENTRY PROCEDURE RETURNS [size:CARDINAL] = {
size ← codeSwapUnitSize;
};
Init: PROCEDURE = {
buckets: ARRAY [0..8) OF BucketAlloc.BucketInfo ← [
[6, 4, 2], [10, 4, 2], [12, 4, 1], [15, 4, 2], -- SIZE[CIOLib.ClientDataObject]
[20, 3, 0], [25, 2, 0], [32, 2, 0], [45, 2, 2] -- SIZE[CFormatIO$StringStreamObject]
];
z ← Heap.Create[
initial: 15, increment: 10,
largeNodeThreshold:
Environment.wordsPerPage * CARDINAL[arraySpaceThreshold]];
arrayZone ← Heap.Create[
initial: 25, increment: 50,
largeNodeThreshold:
Environment.wordsPerPage * CARDINAL[arraySpaceThreshold]];
gfTable ← z.NEW[GFTable];
shTable ← z.NEW[SHTable];
processTable ← z.NEW[ProcessTable];
BucketAlloc.Initialize[z, DESCRIPTOR[buckets]];
};
Init[];
}.