-- File: Locker.mesa, Last Edit: HGM December 18, 1980 10:48 PM DIRECTORY Storage USING [CopyString, Free, FreeString, Node], String USING [EquivalentString], Lock USING [Lock, LockObject, ReadWrite]; Locker: MONITOR IMPORTS Storage, String EXPORTS Lock = BEGIN OPEN Lock; first: Lock _ NIL; EnumerateLocks: PUBLIC ENTRY PROCEDURE [proc: PROCEDURE [Lock]] = BEGIN FOR lock: Lock _ first, lock.next UNTIL lock = NIL DO proc[lock]; ENDLOOP; END; GetLockLocation: PUBLIC PROCEDURE RETURNS [POINTER TO Lock] = BEGIN RETURN[@first]; END; wholeDiskBusy: BOOLEAN _ FALSE; lockFree: CONDITION; DiskNotBusy: ERROR = CODE; LockDiskAndWait: PUBLIC ENTRY PROCEDURE [fileName: STRING, why: ReadWrite] = BEGIN ok: BOOLEAN _ why # write; UNTIL ok DO FOR lock: Lock _ first, lock.next UNTIL lock = NIL DO IF String.EquivalentString[lock.name, fileName] THEN BEGIN WAIT lockFree; EXIT; END; REPEAT FINISHED => ok _ TRUE; -- not in list yet, nobody else reading or writing ENDLOOP; ENDLOOP; FOR lock: Lock _ first, lock.next UNTIL lock = NIL DO IF String.EquivalentString[lock.name, fileName] THEN BEGIN lock.useCount _ lock.useCount + 1; UNTIL ~lock.write DO WAIT lockFree; ENDLOOP; IF why = write THEN lock.write _ TRUE; EXIT; END; REPEAT FINISHED => BEGIN new: Lock _ Storage.Node[SIZE[LockObject]]; new^ _ [first, Storage.CopyString[fileName], 1, why = write]; first _ new; END; ENDLOOP; END; LockDisk: PUBLIC ENTRY PROCEDURE [ fileName: STRING, why: ReadWrite, fast: BOOLEAN] RETURNS [ok: BOOLEAN] = BEGIN IF fast AND wholeDiskBusy THEN RETURN[FALSE]; FOR lock: Lock _ first, lock.next UNTIL lock = NIL DO IF String.EquivalentString[lock.name, fileName] THEN BEGIN IF lock.write OR why = write THEN RETURN[FALSE]; lock.useCount _ lock.useCount + 1; EXIT; END; REPEAT FINISHED => BEGIN new: Lock _ Storage.Node[SIZE[LockObject]]; new^ _ [first, Storage.CopyString[fileName], 1, why = write]; first _ new; END; ENDLOOP; IF fast THEN wholeDiskBusy _ TRUE; RETURN[TRUE]; END; UnlockDisk: PUBLIC ENTRY PROCEDURE [fileName: STRING, fast: BOOLEAN] = BEGIN where: POINTER TO Lock _ @first; FOR lock: Lock _ first, lock.next UNTIL lock = NIL DO IF String.EquivalentString[lock.name, fileName] THEN BEGIN lock.useCount _ lock.useCount - 1; lock.write _ FALSE; IF lock.useCount = 0 THEN BEGIN where^ _ lock.next; Storage.FreeString[lock.name]; Storage.Free[lock]; END; EXIT; END; where _ @lock.next; REPEAT FINISHED => ERROR DiskNotBusy; ENDLOOP; IF fast THEN wholeDiskBusy _ FALSE; BROADCAST lockFree; END; END.