IFSFileImplE.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Levin - 2-Jul-81 10:14:42
Russ Atkinson, March 7, 1985 2:21:40 pm PST
DIRECTORY
IFSFile USING [AccessFailure, CantOpen, Error],
IFSFilePrivate USING [FileHandle, FileObject, FSInstance],
Rope USING [Equal, ROPE];
IFSFileImplE: MONITOR
LOCKS fs.LOCK USING fs: IFSFilePrivate.FSInstance
IMPORTS IFSFile, Rope
EXPORTS IFSFilePrivate = {
OPEN IFSFilePrivate;
ROPE: TYPE = Rope.ROPE;
Miscellaneous
FileListSmashed: ERROR = CODE;
FileNotInList: ERROR = CODE;
IllegalDestroy: ERROR = CODE;
InvalidFile: ERROR = CODE;
Procedures and Signals Exported to IFSFilePrivate
InsertFile: PUBLIC PROC [fs: FSInstance, name: ROPE, openProc: PROC [FileHandle] RETURNS [IFSFile.AccessFailure]] RETURNS [file: FileHandle] = {
NewlyOpened: ENTRY PROC [fs: FSInstance] RETURNS [BOOL] = {
checks to see if the file identified by 'name' has already been entered in the file list. If not, it enters it and indicates that the open operation is underway. If so, it waits for any previous open attempt to be resolved, then reports the outcome.
file ← fs.fileList;
UNTIL file = NIL DO
IF Rope.Equal[file.name, name, FALSE]
THEN {
SELECT file.seal FROM
openSeal => {file.openCount ← file.openCount + 1; RETURN[FALSE]};
underwaySeal => {WAIT fs.changeInOpenState; file ← fs.fileList};
ENDCASE => GO TO bogusList
}
ELSE -- ensure pointer validity
SELECT file.seal FROM
openSeal, underwaySeal => file ← file.link;
ENDCASE => GO TO bogusList;
REPEAT
bogusList => ERROR FileListSmashed;
ENDLOOP;
file ← NEW[FileObject ← FileObject[link: fs.fileList, name: name, fs: fs]];
fs.fileList ← file;
RETURN[TRUE]
};
AnnounceOutcome: ENTRY PROC [fs: FSInstance, outcome: IFSFile.AccessFailure] = {
IF outcome = ok THEN file.seal ← openSeal ELSE RemoveFile[fs, file];
BROADCAST fs.changeInOpenState;
SELECT outcome FROM
ok => RETURN;
io => RETURN WITH ERROR IFSFile.Error[io];
ENDCASE => RETURN WITH ERROR IFSFile.CantOpen[outcome];
};
IF NewlyOpened[fs] THEN AnnounceOutcome[fs, openProc[file]];
};
ReleaseFile: PUBLIC PROC [file: FileHandle, closeProc: PROC [FileHandle]] = {
IF LastReference[file.fs, file] THEN {closeProc[file]; FlushFile[file]};
};
PurgeFile: PUBLIC PROC [file: FileHandle, destroyProc: PROC [FileHandle]] = {
IF LastReference[file.fs, file]
THEN {destroyProc[file]; FlushFile[file]}
ELSE ERROR IllegalDestroy;
};
Internal Procedures
LastReference: ENTRY PROC [fs: FSInstance, file: FileHandle] RETURNS [last: BOOL] = {
IF file.seal ~= openSeal OR file.openCount = 0 THEN ERROR InvalidFile;
IF (last ← file.openCount = 1)
THEN file.seal ← underwaySeal
ELSE file.openCount ← file.openCount - 1;
RETURN[last]
};
FlushFile: PROC [file: FileHandle] = {
DoRemoveFile: ENTRY PROC [fs: FSInstance] =
{RemoveFile[fs, file]; BROADCAST fs.changeInOpenState};
DoRemoveFile[file.fs];
};
RemoveFile: INTERNAL PROC [fs: FSInstance, file: FileHandle] = {
removes the file from the list.
IF file = fs.fileList
THEN fs.fileList ← file.link
ELSE {
IF fs.fileList = NIL THEN GO TO Trouble;
FOR prev: FileHandle ← fs.fileList, prev.link UNTIL prev.link = NIL DO
IF prev.link = file THEN {prev.link ← file.link; EXIT};
REPEAT FINISHED => GO TO Trouble;
ENDLOOP;
EXITS
Trouble => ERROR FileNotInList;
};
file.seal ← closedSeal; -- try to catch dangling references
};
}.