MODULE Modules;
IMPORT SYSTEM, Trace, Machine, Heaps;
CONST
Ok* = 0;
AddressSize = SYSTEM.SIZEOF (SYSTEM.ADDRESS);
MaxTags* = 16;
Tag0Ofs* = -AddressSize * 2;
Mth0Ofs* = Tag0Ofs - AddressSize*MaxTags;
Ptr0Ofs* = AddressSize;
MaxObjFormats = 5;
ProtTypeBit* = Heaps.ProtTypeBit;
None* = 0; PowerDown* = 1; Reboot* = 2;
ClearCode = TRUE;
InitTableLen = 1024;
InitPtrTableLen = 2048;
DefaultContext* = "A2";
TYPE
Name* = ARRAY 32 OF CHAR;
Command* = RECORD
name*: Name;
argTdAdr*, retTdAdr* : SYSTEM.ADDRESS;
entryAdr* : SYSTEM.ADDRESS;
END;
ExportDesc* = RECORD
fp*: SYSTEM.ADDRESS;
adr*: SYSTEM.ADDRESS;
exports*: LONGINT;
dsc*: ExportArray
END;
ExportArray* = POINTER TO ARRAY OF ExportDesc;
Bytes* = POINTER TO ARRAY OF CHAR;
TerminationHandler* = PROCEDURE;
TypeDesc* = POINTER TO RECORD
descSize: LONGINT;
sentinel: LONGINT;
tag*: SYSTEM.ADDRESS;
flags*: SET;
mod*: Module;
name*: Name;
END;
ExceptionTableEntry* = RECORD
pcFrom*: SYSTEM.ADDRESS;
pcTo*: SYSTEM.ADDRESS;
pcHandler*: SYSTEM.ADDRESS;
END;
ExceptionTable* = POINTER TO ARRAY OF ExceptionTableEntry;
ProcTableEntry* = RECORD
pcFrom*, pcLimit*, pcStatementBegin*, pcStatementEnd*: SYSTEM.ADDRESS;
noPtr*: LONGINT;
END;
ProcTable* = POINTER TO ARRAY OF ProcTableEntry;
PtrTable* = POINTER TO ARRAY OF SYSTEM.ADDRESS;
ProcOffsetEntry* = RECORD
data*: ProcTableEntry;
startIndex*: LONGINT;
END;
ProcOffsetTable* = POINTER TO ARRAY OF ProcOffsetEntry;
Module* = OBJECT (Heaps.RootObject)
VAR
next*: Module;
name*: Name;
init, published: BOOLEAN;
refcnt*: LONGINT;
sb*: SYSTEM.ADDRESS;
entry*: POINTER TO ARRAY OF SYSTEM.ADDRESS;
command*: POINTER TO ARRAY OF Command;
ptrAdr*: POINTER TO ARRAY OF SYSTEM.ADDRESS;
typeInfo*: POINTER TO ARRAY OF TypeDesc;
module*: POINTER TO ARRAY OF Module;
procTable*: ProcTable;
ptrTable*: PtrTable;
data*, code*, staticTypeDescs* , refs*: Bytes;
export*: ExportDesc;
term*: TerminationHandler;
exTable*: ExceptionTable;
noProcs*: LONGINT;
firstProc*: SYSTEM.ADDRESS;
maxPtrs*: LONGINT;
crc*: LONGINT;
PROCEDURE FindRoots;
VAR i: LONGINT; ptr: ANY; moduleName: Name; protRecBlockAdr: SYSTEM.ADDRESS; protRecBlock: Heaps.ProtRecBlock;
BEGIN
IF published THEN
moduleName := name;
FOR i := 0 TO LEN(ptrAdr) - 1 DO
SYSTEM.GET (ptrAdr[i], ptr);
IF ptr # NIL THEN Heaps.Mark(ptr) END
END;
SYSTEM.GET(SYSTEM.VAL(SYSTEM.ADDRESS,SELF)+Heaps.HeapBlockOffset, protRecBlockAdr);
protRecBlock := SYSTEM.VAL(Heaps.ProtRecBlock, protRecBlockAdr);
Heaps.Mark(protRecBlock.awaitingLock.head);
Heaps.Mark(protRecBlock.awaitingCond.head);
Heaps.Mark(protRecBlock.lockedBy);
Heaps.Mark(protRecBlock.lock);
Heaps.AddRootObject(next);
END;
END FindRoots;
END Module;
LoaderProc* = PROCEDURE (name, fileName: ARRAY OF CHAR; VAR res: LONGINT;
VAR msg: ARRAY OF CHAR): Module;
VAR
extension-: ARRAY MaxObjFormats, 8 OF CHAR;
loader: ARRAY MaxObjFormats OF LoaderProc;
numLoaders: LONGINT;
kernelProc*: ARRAY 11 OF SYSTEM.ADDRESS;
freeRoot*: Module;
root-: Module;
initBlock: ANY;
procOffsets-: ProcOffsetTable;
numProcs: LONGINT;
ptrOffsets-: PtrTable;
numPtrs: LONGINT;
shutdown*: LONGINT;
trace: BOOLEAN;
ptrOffsetsLock: BOOLEAN;
PROCEDURE AddLoader*(CONST ext: ARRAY OF CHAR; proc: LoaderProc);
BEGIN
Machine.Acquire(Machine.Modules);
ASSERT(numLoaders < MaxObjFormats);
loader[numLoaders] := proc;
COPY(ext, extension[numLoaders]);
ASSERT(ext = extension[numLoaders]);
INC(numLoaders);
Machine.Release(Machine.Modules)
END AddLoader;
PROCEDURE RemoveLoader*(CONST ext: ARRAY OF CHAR; proc: LoaderProc);
VAR i, j: LONGINT;
BEGIN
Machine.Acquire(Machine.Modules);
i := 0;
WHILE (i # numLoaders) & ((loader[i] # proc) OR (extension[i] # ext)) DO INC(i) END;
IF i # numLoaders THEN
FOR j := i TO numLoaders - 2 DO
loader[j] := loader[j + 1]; extension[j] := extension[j + 1];
END;
loader[numLoaders - 1] := NIL; extension[numLoaders - 1] := "";
DEC(numLoaders)
END;
Machine.Release(Machine.Modules)
END RemoveLoader;
PROCEDURE Append*(CONST from: ARRAY OF CHAR; VAR to: ARRAY OF CHAR);
VAR i, j, m: LONGINT;
BEGIN
j := 0; WHILE to[j] # 0X DO INC(j) END;
m := LEN(to)-1;
i := 0; WHILE (from[i] # 0X) & (j # m) DO to[j] := from[i]; INC(i); INC(j) END;
to[j] := 0X
END Append;
PROCEDURE Publish*(VAR m: Module; VAR new: BOOLEAN);
VAR n: Module; i: LONGINT;
BEGIN
ASSERT((m.code # NIL) & (LEN(m.code^) > 0));
Machine.Acquire(Machine.Modules);
n := root; WHILE (n # NIL) & (n.name # m.name) DO n := n.next END;
IF n # NIL THEN
m := n; new := FALSE;
Machine.Release(Machine.Modules);
ELSE
m.published := TRUE;
m.next := root; root := m;
m.refcnt := 0;
FOR i := 0 TO LEN(m.module)-1 DO INC(m.module[i].refcnt) END;
new := TRUE;
REPEAT UNTIL ~ptrOffsetsLock;
ptrOffsetsLock := TRUE;
Machine.Release(Machine.Modules);
InsertProcOffsets(m.procTable, m.ptrTable, m.maxPtrs);
m.procTable := NIL; m.ptrTable := NIL;
END;
END Publish;
PROCEDURE PublishThis*(m: Module): BOOLEAN;
VAR new: BOOLEAN;
BEGIN
Publish(m,new);
RETURN new
END PublishThis;
PROCEDURE SetInitialized*(m: Module);
BEGIN
m.init := TRUE;
END SetInitialized;
PROCEDURE ModuleByName*(CONST name: ARRAY OF CHAR): Module;
VAR m: Module;
BEGIN
Machine.Acquire(Machine.Modules);
m := root; WHILE (m # NIL) & (m.name # name) DO m := m.next END;
Machine.Release(Machine.Modules);
RETURN m
END ModuleByName;
PROCEDURE GetFileName(CONST name, extension: ARRAY OF CHAR; VAR fileName: ARRAY OF CHAR);
VAR i, j: LONGINT;
BEGIN
i := 0; WHILE name[i] # 0X DO fileName[i] := name[i]; INC(i) END;
j := 0; WHILE extension[j] # 0X DO fileName[i] := extension[j]; INC(i); INC(j) END;
fileName[i] := 0X
END GetFileName;
PROCEDURE ThisModule*(CONST name: ARRAY OF CHAR; VAR res: LONGINT; VAR msg: ARRAY OF CHAR): Module;
TYPE Body = PROCEDURE;
VAR m, p: Module; fileName: ARRAY 64 OF CHAR; body: Body; new: BOOLEAN; i: LONGINT;
BEGIN
res := Ok; msg[0] := 0X; m := ModuleByName(name);
IF m = NIL THEN
IF trace THEN
Machine.Acquire (Machine.TraceOutput);
Trace.String(">"); Trace.StringLn (name);
Machine.Release (Machine.TraceOutput);
END;
i := 0;
REPEAT
GetFileName(name, extension[i], fileName);
m := loader[i](name, fileName, res, msg);
INC(i)
UNTIL (i = numLoaders) OR (m # NIL);
IF trace THEN
Machine.Acquire (Machine.TraceOutput);
Trace.String("?"); Trace.StringLn (name);
Machine.Release (Machine.TraceOutput);
END;
p := m;
IF (m # NIL) & ~m.published THEN
Publish(m, new);
IF new THEN
body := SYSTEM.VAL (Body, SYSTEM.ADR(m.code[0]));
body; res := Ok; msg[0] := 0X;
m.init := TRUE
ELSE
END
END;
IF trace THEN
Machine.Acquire (Machine.TraceOutput);
IF m = NIL THEN
Trace.String("could not load "); Trace.StringLn(name)
ELSIF ~m.published THEN
Trace.String("not published "); Trace.StringLn(name)
ELSE
Trace.String("<"); Trace.StringLn (name);
END;
Machine.Release (Machine.TraceOutput);
END;
END;
RETURN m
END ThisModule;
PROCEDURE ThisModuleByAdr0*(pc: SYSTEM.ADDRESS): Module;
VAR m: Module; cbase, dbase: SYSTEM.ADDRESS; i: LONGINT; found: BOOLEAN;
BEGIN
i := 0; found := FALSE;
REPEAT
CASE i OF
0: m := root
|1: m := freeRoot
END;
WHILE (m # NIL) & ~found DO
cbase := SYSTEM.ADR(m.code[0]); dbase := SYSTEM.ADR(m.data[0]);
IF (cbase <= pc) & (pc <= cbase + LEN(m.code^)) THEN
found := TRUE
ELSIF (dbase <= pc) & (pc <= dbase + LEN(m.data^)) THEN
found := TRUE
ELSE
m := m.next
END
END;
INC(i)
UNTIL found OR (i = 2);
RETURN m
END ThisModuleByAdr0;
PROCEDURE ThisModuleByAdr*(pc: SYSTEM.ADDRESS): Module;
VAR m: Module;
BEGIN
Machine.Acquire(Machine.Modules);
m := ThisModuleByAdr0(pc);
Machine.Release(Machine.Modules);
RETURN m
END ThisModuleByAdr;
PROCEDURE GetProcedure*(CONST moduleName, procedureName : ARRAY OF CHAR; argTdAdr, retTdAdr : SYSTEM.ADDRESS; VAR entryAdr : SYSTEM.ADDRESS);
VAR module : Module; ignoreMsg : ARRAY 32 OF CHAR; i, res : LONGINT;
BEGIN
module := ThisModule(moduleName, res, ignoreMsg);
IF (res = Ok) THEN
IF ~module.init THEN
i := 1000000;
REPEAT DEC(i) UNTIL (i = 0) OR module.init
END;
ASSERT(module.init);
Machine.Acquire(Machine.Modules);
i := 0; entryAdr := Heaps.NilVal;
WHILE (entryAdr = Heaps.NilVal) & (i # LEN(module.command^)) DO
IF (module.command[i].name = procedureName) & (module.command[i].argTdAdr = argTdAdr) & (module.command[i].retTdAdr = retTdAdr) THEN
entryAdr := module.command[i].entryAdr;
END;
INC(i)
END;
Machine.Release(Machine.Modules);
END;
END GetProcedure;
PROCEDURE ThisType*(m: Module; CONST name: ARRAY OF CHAR): TypeDesc;
VAR i: LONGINT; type: TypeDesc;
BEGIN
Machine.Acquire(Machine.Modules);
i := 0;
WHILE (i < LEN(m.typeInfo)) & (m.typeInfo[i].name # name) DO INC(i) END;
IF i = LEN(m.typeInfo) THEN
type := NIL
ELSE
type := m.typeInfo[i]
END;
Machine.Release(Machine.Modules);
RETURN type
END ThisType;
PROCEDURE ThisTypeByAdr*(adr: SYSTEM.ADDRESS; VAR m: Module; VAR t: TypeDesc);
BEGIN
IF adr # 0 THEN
Machine.Acquire(Machine.Modules);
SYSTEM.GET (adr + Heaps.TypeDescOffset, adr);
t := SYSTEM.VAL(TypeDesc, adr);
m := t.mod;
Machine.Release(Machine.Modules)
ELSE
m := NIL; t := NIL
END
END ThisTypeByAdr;
PROCEDURE NewObj*(t : TypeDesc; isRealtime: BOOLEAN) : ANY;
VAR x : ANY;
BEGIN
Heaps.NewRec(x, SYSTEM.VAL (SYSTEM.ADDRESS, t.tag), isRealtime);
RETURN x;
END NewObj;
PROCEDURE TypeOf*(obj : ANY): TypeDesc;
VAR
m : Module;
t : TypeDesc;
adr : SYSTEM.ADDRESS;
BEGIN
SYSTEM.GET(SYSTEM.VAL(SYSTEM.ADDRESS, obj) + Heaps.TypeDescOffset, adr);
ThisTypeByAdr(adr, m, t);
RETURN t;
END TypeOf;
PROCEDURE FindPos(key: SYSTEM.ADDRESS; VAR pos: LONGINT): BOOLEAN;
VAR l, r, x: LONGINT; isHit: BOOLEAN;
BEGIN
l := 0; r := numProcs - 1;
REPEAT
x := (l + r) DIV 2;
IF key < procOffsets[x].data.pcFrom THEN r := x - 1 ELSE l := x + 1 END;
isHit := ((procOffsets[x].data.pcFrom <= key) & (key < procOffsets[x].data.pcLimit));
UNTIL isHit OR (l > r);
IF isHit THEN
pos := x;
RETURN TRUE
ELSE
RETURN FALSE
END
END FindPos;
PROCEDURE FindProc*(pc: SYSTEM.ADDRESS; VAR data: ProcTableEntry; VAR index: LONGINT; VAR success: BOOLEAN);
VAR x: LONGINT;
BEGIN
success := FindPos(pc, x);
IF success THEN
data := procOffsets[x].data;
index := procOffsets[x].startIndex
END
END FindProc;
PROCEDURE FindInsertionPos(VAR entry: ProcTableEntry; VAR pos: LONGINT): BOOLEAN;
VAR l, r, x: LONGINT; success, isHit: BOOLEAN;
BEGIN
pos := -1;
success := FALSE;
IF numProcs = 0 THEN
pos := 0; success := TRUE
ELSE
l := 0; r := numProcs - 1;
REPEAT
x := (l + r) DIV 2;
IF entry.pcLimit < procOffsets[x].data.pcFrom THEN r := x - 1 ELSE l := x + 1 END;
isHit := ((x = 0) OR (procOffsets[x - 1].data.pcLimit <= entry.pcFrom)) & (entry.pcLimit <= procOffsets[x].data.pcFrom);
UNTIL isHit OR (l > r);
IF isHit THEN
pos := x; success := TRUE
ELSE
IF (x = numProcs - 1) & (procOffsets[x].data.pcLimit <= entry.pcFrom) THEN
pos := x + 1; success := TRUE
END
END
END;
RETURN success
END FindInsertionPos;
PROCEDURE NumTotalPtrs(procTable: ProcTable): LONGINT;
VAR i, num: LONGINT;
BEGIN
num := 0;
FOR i := 0 TO LEN(procTable) - 1 DO
num := num + procTable[i].noPtr
END;
RETURN num
END NumTotalPtrs;
PROCEDURE InsertProcOffsets(procTable: ProcTable; ptrTable: PtrTable; maxPtr: LONGINT);
VAR success: BOOLEAN; i, j, pos, poslast, newLen, num: LONGINT; newProcOffsets: ProcOffsetTable; newPtrOffsets: PtrTable;
BEGIN
IF LEN(procTable) > 0 THEN
IF numProcs + LEN(procTable) > LEN(procOffsets) THEN
newLen := LEN(procOffsets) + InitTableLen;
WHILE numProcs + LEN(procTable) > newLen DO newLen := newLen + InitTableLen END;
NEW(newProcOffsets, newLen);
FOR i := 0 TO numProcs - 1 DO
newProcOffsets[i] := procOffsets[i]
END;
procOffsets := newProcOffsets
END;
num := NumTotalPtrs(procTable);
IF numPtrs + num > LEN(ptrOffsets) THEN
newLen := LEN(ptrOffsets) + InitPtrTableLen;
WHILE numPtrs + num > newLen DO newLen := newLen + InitPtrTableLen END;
NEW(newPtrOffsets, newLen);
FOR i := 0 TO numPtrs - 1 DO
newPtrOffsets[i] := ptrOffsets[i]
END;
ptrOffsets := newPtrOffsets
END;
success := FindInsertionPos(procTable[0], pos); success := success & FindInsertionPos(procTable[LEN(procTable) - 1], poslast);
IF (~success) OR (pos # poslast) THEN Machine.Release(Machine.Modules); HALT(2001) END;
FOR i := numProcs - 1 TO pos BY -1 DO procOffsets[i + LEN(procTable)] := procOffsets[i] END;
FOR i := 0 TO LEN(procTable) - 1 DO
procOffsets[pos + i].data := procTable[i];
procOffsets[pos + i].startIndex := numPtrs;
FOR j := 0 TO procTable[i].noPtr - 1 DO
ptrOffsets[numPtrs + j] := ptrTable[i * maxPtr + j]
END;
numPtrs := numPtrs + procTable[i].noPtr;
END;
numProcs := numProcs + LEN(procTable);
END;
ptrOffsetsLock := FALSE;
END InsertProcOffsets;
PROCEDURE DeleteProcOffsets(firstProcPC: SYSTEM.ADDRESS; noProcsInMod: LONGINT);
VAR pos, i, noPtrsInMod, oldIndex: LONGINT; success: BOOLEAN;
BEGIN
IF noProcsInMod > 0 THEN
success := FindPos(firstProcPC, pos);
IF success THEN
noPtrsInMod := 0;
FOR i := pos TO pos + noProcsInMod - 1 DO
noPtrsInMod := noPtrsInMod + procOffsets[i].data.noPtr
END;
oldIndex := procOffsets[pos].startIndex;
FOR i := procOffsets[pos].startIndex + noPtrsInMod TO numPtrs - 1 DO
ptrOffsets[i - noPtrsInMod] := ptrOffsets[i]
END;
numPtrs := numPtrs - noPtrsInMod;
FOR i := pos + noProcsInMod TO numProcs - 1 DO
procOffsets[i - noProcsInMod] := procOffsets[i]
END;
numProcs := numProcs - noProcsInMod;
FOR i := 0 TO numProcs - 1 DO
IF procOffsets[i].startIndex > oldIndex THEN
procOffsets[i].startIndex := procOffsets[i].startIndex - noPtrsInMod
END
END;
ELSE
Trace.String("corrupt global procOffsets table"); Trace.Ln;
HALT(2000)
END
END
END DeleteProcOffsets;
PROCEDURE InstallTermHandler*(h: TerminationHandler);
VAR m: Module;
BEGIN
m := ThisModuleByAdr(SYSTEM.VAL (SYSTEM.ADDRESS, h));
IF m # NIL THEN
m.term := h
END
END InstallTermHandler;
PROCEDURE FreeModule*(CONST name: ARRAY OF CHAR; VAR res: LONGINT; VAR msg: ARRAY OF CHAR);
VAR p, m: Module; term: TerminationHandler; i: LONGINT;
BEGIN
m := ModuleByName(name);
IF (m # NIL) & (m.refcnt = 0) THEN
IF m.term # NIL THEN
term := m.term; m.term := NIL; term
END;
Heaps.CleanupModuleFinalizers(SYSTEM.ADR(m.code[0]), LEN(m.code), m.name)
END;
res := Ok; msg[0] := 0X;
Machine.Acquire(Machine.Modules);
p := NIL; m := root;
WHILE (m # NIL) & (m.name # name) DO p := m; m := m.next END;
IF m # NIL THEN
IF m.refcnt = 0 THEN
FOR i := 0 TO LEN(m.module)-1 DO DEC(m.module[i].refcnt) END;
m.init := FALSE;
Append("?", m.name);
IF p = NIL THEN root := root.next ELSE p.next := m.next END;
m.next := freeRoot; freeRoot := m;
FOR i := 0 TO LEN(m.ptrAdr)-1 DO SYSTEM.PUT (m.ptrAdr[i], NIL) END;
IF ClearCode THEN
FOR i := 0 TO LEN(m.code)-1 DO m.code[i] := 0CCX END
END;
m.published := FALSE;
m.entry := NIL; m.command := NIL; m.ptrAdr := NIL;
m.export.dsc := NIL; m.exTable := NIL;
DeleteProcOffsets(m.firstProc, m.noProcs);
ELSE
res := 1901;
COPY(name, msg); Append(" reference count not zero", msg)
END
ELSE
res := 1902;
COPY(name, msg); Append(" not found", msg)
END;
Machine.Release(Machine.Modules)
END FreeModule;
PROCEDURE Terminate(term: TerminationHandler);
BEGIN
term
FINALLY
END Terminate;
PROCEDURE Shutdown*(code: LONGINT);
VAR m: Module; term: TerminationHandler;
BEGIN
IF code # None THEN
LOOP
Machine.Acquire(Machine.Modules);
m := root; WHILE (m # NIL) & (m.term = NIL) DO m := m.next END;
IF m # NIL THEN term := m.term; m.term := NIL END;
Machine.Release(Machine.Modules);
IF m = NIL THEN EXIT END;
IF trace THEN
Machine.Acquire (Machine.TraceOutput);
Trace.String("TermHandler "); Trace.StringLn (m.name);
Machine.Release (Machine.TraceOutput);
END;
Terminate(term)
END;
m := root;
WHILE m # NIL DO
Heaps.CleanupModuleFinalizers(SYSTEM.ADR(m.code[0]), LEN(m.code), m.name);
m := m.next
END;
IF trace THEN
Machine.Acquire (Machine.TraceOutput);
Trace.StringLn ("Modules.Shutdown finished");
Machine.Release (Machine.TraceOutput);
END;
Machine.Shutdown(code = Reboot)
END
END Shutdown;
PROCEDURE IsExceptionHandled*(VAR pc, fp: SYSTEM.ADDRESS; deep: BOOLEAN): BOOLEAN;
VAR
handler: SYSTEM.ADDRESS;
BEGIN
IF deep THEN
handler := GetExceptionHandler(pc);
IF handler # -1 THEN
RETURN TRUE
ELSE
WHILE (fp # 0) & (handler = -1) DO
SYSTEM.GET (fp + 4, pc);
pc := pc - 1;
handler := GetExceptionHandler(pc);
SYSTEM.GET (fp, fp)
END;
IF handler = -1 THEN RETURN FALSE ELSE pc := handler; RETURN TRUE END
END
ELSE
RETURN GetExceptionHandler(pc) # -1
END
END IsExceptionHandled;
PROCEDURE GetExceptionHandler*(pc: SYSTEM.ADDRESS): SYSTEM.ADDRESS;
VAR
m: Module;
PROCEDURE BinSearch(exTable: ExceptionTable; key: SYSTEM.ADDRESS): SYSTEM.ADDRESS;
VAR
x, l, r: LONGINT;
BEGIN
l := 0; r:=LEN(exTable) - 1;
REPEAT
x := (l + r) DIV 2;
IF key < exTable[x].pcFrom THEN r := x - 1 ELSE l := x + 1 END;
UNTIL ((key >= exTable[x].pcFrom) & (key < exTable[x].pcTo) ) OR (l > r);
IF (key >= exTable[x].pcFrom) & (key < exTable[x].pcTo) THEN
RETURN exTable[x].pcHandler;
ELSE
RETURN -1;
END
END BinSearch;
BEGIN
m := ThisModuleByAdr(pc);
IF (m # NIL) & (m.exTable # NIL) & (LEN(m.exTable) > 0) THEN
RETURN BinSearch(m.exTable, pc);
END;
RETURN -1;
END GetExceptionHandler;
PROCEDURE Initialized*(m: Module): BOOLEAN;
BEGIN
RETURN m.init;
END Initialized;
PROCEDURE Init;
VAR
s: ARRAY 4 OF CHAR;
BEGIN
ptrOffsetsLock := FALSE;
shutdown := None;
numLoaders := 0;
freeRoot := NIL;
Machine.GetConfig("TraceModules", s);
trace := (s[0] = "1")
END Init;
BEGIN
Init
END Modules.
(*
19.03.1998 pjm Started
06.10.1998 pjm FreeModule
Note:
o ThisCommand race: process A calls ThisModule, the module is published, but before its body has finished executing, process B calls ThisCommand, causing the assert (m.init) to fail. Process B should perhaps wait in this case until the body has executed, or ThisCommand should return NIL (but that will just move the race to the user).
*)