DIRECTORY
FS USING [Lock],
FSBackdoor USING [Version],
FSLock USING [ActiveFile, LookupLock, RemoveLock],
Rope USING [ROPE];
Procedures exported to FSLock
LockRecord:
PUBLIC
PROC [volumePrefix, nameBody: Rope.
ROPE, version: FSBackdoor.Version]
RETURNS [a: FSLock.ActiveFile, ok:
BOOLEAN] =
BEGIN
InnerLockRecord:
ENTRY
PROC [a: FSLock.ActiveFile]
RETURNS [{gotIt, wait, dead}] =
BEGIN
IF a.nameBody = NIL THEN RETURN [dead];
IF a.recordLock THEN RETURN [wait];
a.recordLock ← TRUE;
RETURN [gotIt];
END;
DO
a ← FSLock.LookupLock[volumePrefix, nameBody, version];
SELECT InnerLockRecord[a]
FROM
gotIt => ok ← TRUE;
wait => ok ← FALSE;
dead => LOOP;
ENDCASE => ERROR;
EXIT;
ENDLOOP;
END;
checkAgain: CONDITION;
LockAttachedToRecord:
PUBLIC
PROC [a: FSLock.ActiveFile] =
BEGIN
InnerLockAttachedToRecord:
PUBLIC
ENTRY
PROC [a: FSLock.ActiveFile] =
BEGIN
WHILE a.recordLock DO WAIT checkAgain ENDLOOP;
IF a.nameBody = NIL THEN ERROR;
a.recordLock ← TRUE;
END;
IF NOT a.recordLock THEN ERROR;
InnerLockAttachedToRecord[a.attachedTo];
END;
WaitForRecord:
PUBLIC
ENTRY
PROC [a: FSLock.ActiveFile] =
{ WHILE a.nameBody # NIL AND a.recordLock DO WAIT checkAgain ENDLOOP };
ReleaseRecord:
PUBLIC
PROC [a: FSLock.ActiveFile] =
BEGIN
InnerReleaseRecord:
ENTRY
PROC [a: FSLock.ActiveFile] =
BEGIN
IF a.recordLock -- may be no record lock to release
THEN
BEGIN
a.recordLock ← FALSE;
IF a.fileLockCount = 0 THEN FSLock.RemoveLock[a];
BROADCAST checkAgain;
END;
END;
IF a = NIL THEN RETURN; -- release of NIL is a nop!
InnerReleaseRecord[a];
END;
LockFile:
PUBLIC
ENTRY
PROC [a: FSLock.ActiveFile, lock:
FS.Lock]
RETURNS [ok:
BOOLEAN] =
BEGIN
IF NOT a.recordLock THEN ERROR;
IF a.fileLockCount = 0
THEN a.fileLock ← (IF lock = write THEN write ELSE read)
ELSE { IF lock = write OR (lock = read AND a.fileLock = write) THEN RETURN [FALSE] };
a.fileLockCount ← a.fileLockCount + 1;
RETURN [TRUE];
END;
GetAttachment:
PUBLIC
ENTRY
PROC [a: FSLock.ActiveFile]
RETURNS [FSLock.ActiveFile] =
BEGIN
WHILE a.recordLock DO WAIT checkAgain ENDLOOP;
IF a.fileLockCount = 0 THEN ERROR;
RETURN [a.attachedTo];
END;
ReportClose:
PUBLIC
PROC [a: FSLock.ActiveFile] =
BEGIN
ReleaseFile:
ENTRY
PROC [a: FSLock.ActiveFile]
RETURNS [attachedTo: FSLock.ActiveFile] =
BEGIN
WHILE a.recordLock DO WAIT checkAgain ENDLOOP;
IF a.fileLockCount = 0 THEN ERROR;
attachedTo ← a.attachedTo;
a.fileLockCount ← a.fileLockCount - 1;
IF a.fileLockCount = 0
THEN
BEGIN
a.fileLock ← none;
IF NOT a.recordLock
THEN FSLock.RemoveLock[a];
END;
END;
att: FSLock.ActiveFile ← ReleaseFile[a];
IF att # NIL THEN att ← ReleaseFile[att];
IF att # NIL THEN ERROR;
END;