Cedar Nucleus (Files): global table of open files (to cause sharing of handles)
FileTableImpl.mesa
Andrew Birrell June 27, 1983 4:42 pm
Last Edited by: Levin, May 20, 1983 5:19 pm
Last Edited by: Schroeder, June 10, 1983 5:20 pm
DIRECTORY
File USING[ FileID, Volume ],
FileInternal USING[ FreeHeaderVM, Handle, Object],
PrincOps USING[ LongNumber ],
SafeStorage USING[ ClearFinalizedFlag, EstablishFinalization, FinalizationQueue, FQEmpty, FQNext, NewFQ ];
FileTableImpl: CEDAR MONITOR
IMPORTS FileInternal, SafeStorage
EXPORTS FileInternal
SHARES File =
BEGIN
HashValue: TYPE = [0..256);
Table: TYPE = ARRAY HashValue OF FileInternal.Handle;
table: REF Table = NEW[Table ← ALL[NIL]];
Hash: PROC[id: File.FileID] RETURNS[HashValue] =
The LOOPHOLE below is "respectable", since all we want is a decent hash function (?).
{ l: PrincOps.LongNumber = [li[LOOPHOLE[id]]]; RETURN[l.ll] };
Lookup: PUBLIC ENTRY PROC[volume: File.Volume, id: File.FileID] RETURNS [file: FileInternal.Handle] =
BEGIN
ENABLE UNWIND => NULL;
h: HashValue = Hash[id];
prev: FileInternal.Handle ← NIL;
file ← table[h];
DO
IF file = NIL
THEN BEGIN
file ← InternalCreate[];
file.volume ← volume;
file.fp.id ← id;
IF prev = NIL THEN table[h] ← file ELSE prev.rest ← file;
SafeStorage.ClearFinalizedFlag[file];
EXIT
END;
IF file.fp.id = id AND file.volume = volume THEN { file.reissued ← TRUE; EXIT };
prev ← file; file ← file.rest;
ENDLOOP;
END;
ConfusedHash: ERROR = CODE;
Insert: PUBLIC ENTRY PROC[new: FileInternal.Handle] =
BEGIN
ENABLE UNWIND => NULL;
h: HashValue = Hash[new.fp.id];
prev: FileInternal.Handle ← NIL;
file: FileInternal.Handle ← table[h];
DO
IF file = NIL
THEN BEGIN
IF prev = NIL THEN table[h] ← new ELSE prev.rest ← new;
SafeStorage.ClearFinalizedFlag[new];
EXIT
END;
IF file.fp.id = new.fp.id AND file.volume = new.volume THEN ERROR ConfusedHash[];
prev ← file; file ← file.rest;
ENDLOOP;
END;
Remove: INTERNAL PROC[old: FileInternal.Handle] =
BEGIN
ENABLE UNWIND => NULL;
h: HashValue = Hash[old.fp.id];
prev: FileInternal.Handle ← NIL;
file: FileInternal.Handle ← table[h];
DO
IF file = NIL THEN EXIT;
IF file = old
THEN BEGIN
IF prev = NIL THEN table[h] ← file.rest ELSE prev.rest ← file.rest;
EXIT
END;
prev ← file; file ← file.rest;
ENDLOOP;
END;
AllocForCreate: PUBLIC ENTRY PROC RETURNS[FileInternal.Handle] =
{ RETURN[ InternalCreate[ ! UNWIND => NULL] ] };
InternalCreate: INTERNAL PROC RETURNS[FileInternal.Handle] =
BEGIN
UNTIL SafeStorage.FQEmpty[MyQueue]
DO file: FileInternal.Handle = NARROW[SafeStorage.FQNext[MyQueue]];
IF file.reissued
THEN { file.reissued ← FALSE; SafeStorage.ClearFinalizedFlag[file] }
ELSE BEGIN
Remove[file];
FileInternal.FreeHeaderVM[file];
END;
ENDLOOP;
RETURN[NEW[FileInternal.Object ← []]]
END;
DuplicateHashTableEntry: ERROR = CODE;
MyQueue: SafeStorage.FinalizationQueue = SafeStorage.NewFQ[];
SafeStorage.EstablishFinalization[type: CODE[FileInternal.Object], npr: 1, fq: MyQueue];
END.