Declarations
LockRef: TYPE = REF LockRecord;
LockRecord:
TYPE = MONITORED
RECORD [
waitingForWrite: INTEGER ← 0, -- number of processes waiting for write access to this document
count, maxCount: [0..255] ← 0, -- number of times have entered this lock
process: PROCESS ← NIL, -- the unique process which has write access to this document
whoLast, whoFirst: Rope.ROPE, -- provided by the lockers
unlocked: CONDITION -- raised when the lock is freed
];
Access: TYPE = { read, write };
Procedures
Lock:
PROC [doc: TextNode.Ref, who: Rope.
ROPE, access: Access ← write]
RETURNS [LockRef];
Can only lock a document if
(1) it is unlocked, or
(2) current process has a write lock on it already
If neither holds, then waits until it can lock it.
Note that cannot convert a read lock into a write lock. (Implementation limitation.)
Many processes can have read locks; only one can have a write lock.
When a write lock is released, all viewers for the document have their tdd.dirty bit set true.
LockBoth:
PROC [doc1, doc2: TextNode.Ref, who: Rope.
ROPE, access1, access2: Access ← write]
RETURNS [lock1, lock2: LockRef];
Like two calls on Lock, but orders the calls according to LockOrder.
LockOrder:
PROC [doc1, doc2: TextNode.Ref]
RETURNS [
BOOL] =
INLINE {
RETURN [LOOPHOLE[doc1, INT] <= LOOPHOLE[doc2, INT]] };
Returns true if ok to lock doc1 before doc2.
Unlock:
PROC [doc: TextNode.Ref];
Reduces the lock count for the document.
LockDocAndTdd:
PROC [tdd: TEditDocument.TEditDocumentData,
who: Rope.ROPE, access: Access ← write, interrupt, defer: BOOL ← FALSE] RETURNS [LockRef];
access is for locking the document; interrupt and defer are for locking the tdd
if defer and don't get the tdd lock, then returns nil.
UnlockDocAndTdd: PROC [tdd: TEditDocument.TEditDocumentData];
WaitingForWrite:
PROC [lock: LockRef]
RETURNS [
BOOL] =
INLINE
{ RETURN [lock.waitingForWrite > 0] };
Returns true iff some process is waiting to get a write lock for the document.