DIRECTORY MonitoredQueue USING [AddToSet], NodeProps USING [GetProp, NullCopy, NullRead, NullWrite, PutProp, Register], Process USING [GetCurrent], Rope USING [ROPE], TEditDocument USING [GetViewerForRoot, SpinAndLock, TEditDocumentData, Unlock], TEditLocks USING [Access, LockRecord, LockRef], TEditRefresh USING [dirtyDocs], TextNode USING [Ref], ViewerClasses USING [Lock, Viewer], ViewerLocks USING [LockOrder], ViewerPrivate USING [AcquireWriteLock, ReleaseWriteLock]; TEditLocksImpl: CEDAR MONITOR LOCKS lock USING lock: LockRef IMPORTS NodeProps, Process, MonitoredQueue, TEditDocument, TEditRefresh, ViewerLocks, ViewerPrivate EXPORTS TEditLocks = BEGIN OPEN TEditLocks, TEditDocument; ROPE: TYPE = Rope.ROPE; Viewer: TYPE = ViewerClasses.Viewer; locksBothCount: INT _ 0; dubious: INT _ 0; lockRootViewer: BOOL _ TRUE; lockSplitViewer: BOOL _ TRUE; LockBoth: PUBLIC PROC [doc1, doc2: TextNode.Ref, who: Rope.ROPE, access1, access2: Access _ write] RETURNS [lock1, lock2: LockRef] = { locksBothCount _ locksBothCount + 1; IF (doc1=doc2 AND access1=write) OR (doc1 # doc2 AND LockOrder[doc1, doc2]) THEN { lock1 _ Lock[doc1, who, access1]; lock2 _ Lock[doc2, who, access2]; } ELSE { lock2 _ Lock[doc2, who, access2]; lock1 _ Lock[doc1, who, access1]; }; }; Lock: PUBLIC PROC [doc: TextNode.Ref, who: Rope.ROPE, access: Access _ write] RETURNS [lock: LockRef] = { IF doc=NIL THEN ERROR; DO v: Viewer _ TEditDocument.GetViewerForRoot[doc]; root: Viewer _ GetRoot[v]; localViewer: Viewer _ NIL; IF (lock _ GetLock[doc])=NIL THEN RETURN; IF root # NIL THEN { IF lockRootViewer AND root.link = NIL THEN localViewer _ root; IF lockSplitViewer AND root.link # NIL THEN localViewer _ root; IF localViewer # NIL THEN ViewerPrivate.AcquireWriteLock[localViewer]; }; IF root = GetRoot[v] THEN { IF TEditDocument.GetViewerForRoot[doc] = v THEN { LockIt[lock, who, access, doc]; IF TEditDocument.GetViewerForRoot[doc] = v THEN { NodeProps.PutProp[doc, $LockedViewer, localViewer]; EXIT; }; NodeProps.PutProp[doc, $LockedViewer, NIL]; UnlockIt[lock, doc]; }; }; IF localViewer # NIL THEN ViewerPrivate.ReleaseWriteLock[localViewer]; ENDLOOP; }; LockIt: ENTRY PROC [lock: LockRef, who: Rope.ROPE, access: Access, doc: TextNode.Ref] = { ENABLE UNWIND => NULL; myProcess: PROCESS; TRUSTED {myProcess _ LOOPHOLE[Process.GetCurrent[]]}; IF access=read THEN { IF lock.process # myProcess THEN WHILE lock.process # NIL DO WAIT lock.unlocked; ENDLOOP } ELSE { IF lock.process # myProcess THEN { IF lock.count > 0 THEN { lock.waitingForWrite _ lock.waitingForWrite+1; WHILE lock.count > 0 DO WAIT lock.unlocked; ENDLOOP; lock.waitingForWrite _ lock.waitingForWrite-1 }; lock.process _ myProcess }}; IF lock.count=0 THEN lock.whoFirst _ who ELSE lock.whoLast _ who; lock.count _ lock.count+1; lock.maxCount _ MAX[lock.maxCount, lock.count]; }; LockOrder: PUBLIC PROC [doc1, doc2: TextNode.Ref] RETURNS [BOOL] = { v1: Viewer _ IF doc1 = NIL THEN NIL ELSE TEditDocument.GetViewerForRoot[doc1]; v2: Viewer _ IF doc2 = NIL THEN NIL ELSE TEditDocument.GetViewerForRoot[doc2]; IF v1 # v2 THEN RETURN [ViewerLocks.LockOrder[v1, v2]]; RETURN [LOOPHOLE[doc1, INT] <= LOOPHOLE[doc2, INT]] }; Unlock: PUBLIC PROC [doc: TextNode.Ref] = { lock: LockRef; IF doc=NIL THEN ERROR; IF (lock _ GetLock[doc])=NIL THEN RETURN; UnlockIt[lock, doc]; }; UnlockIt: ENTRY PROC [lock: LockRef, doc: TextNode.Ref] = { ENABLE UNWIND => NULL; v: Viewer _ NARROW[NodeProps.GetProp[doc, $LockedViewer]]; IF lock=NIL THEN RETURN; IF lock.count <= 0 THEN ERROR; TRUSTED {IF lock.process # NIL AND lock.process # Process.GetCurrent[] THEN ERROR}; SELECT TRUE FROM (lock.count _ lock.count-1) > 0 => {}; ENDCASE => { SELECT TRUE FROM lock.process # NIL => { viewer: ViewerClasses.Viewer _ TEditDocument.GetViewerForRoot[doc]; IF viewer # v THEN dubious _ dubious + 1; IF viewer # NIL THEN { FOR v: ViewerClasses.Viewer _ viewer, v.link UNTIL v = NIL DO WITH v.data SELECT FROM tdd: TEditDocument.TEditDocumentData => tdd.dirty _ TRUE; ENDCASE; IF v.link = viewer THEN EXIT; ENDLOOP; MonitoredQueue.AddToSet[doc, TEditRefresh.dirtyDocs]; }; lock.process _ NIL; }; ENDCASE; NodeProps.PutProp[doc, $LockedViewer, NIL]; lock.whoFirst _ lock.whoLast _ NIL; lock.maxCount _ 0; BROADCAST lock.unlocked; }; IF v # NIL THEN ViewerPrivate.ReleaseWriteLock[v]; }; LockDocAndTdd: PUBLIC PROC [tdd: TEditDocument.TEditDocumentData, who: Rope.ROPE, access: Access _ write, interrupt, defer: BOOL _ FALSE] RETURNS [lock: LockRef] = { IF ~TEditDocument.SpinAndLock[tdd, "LockDocAndTdd1", interrupt, defer] THEN RETURN [NIL]; DO doc: TextNode.Ref _ tdd.text; TEditDocument.Unlock[tdd]; -- must unlock tdd before try to lock the document. IF doc=NIL THEN RETURN [NIL]; lock _ Lock[doc, who, access]; IF ~TEditDocument.SpinAndLock[tdd, "LockDocAndTdd2", interrupt, defer] THEN { UnlockIt[lock, doc]; RETURN [NIL] }; IF tdd.text = doc THEN RETURN; -- all went well UnlockIt[lock, doc]; -- document changed during the time we had tdd unlocked ENDLOOP; }; UnlockDocAndTdd: PUBLIC PROC [tdd: TEditDocument.TEditDocumentData] = { IF tdd.text#NIL THEN Unlock[tdd.text]; TEditDocument.Unlock[tdd]; }; WaitingForWrite: PUBLIC PROC [lock: LockRef] RETURNS [BOOL] = { RETURN [lock.waitingForWrite > 0]; }; GetRoot: PROC [viewer: Viewer] RETURNS [root: Viewer] = { root _ viewer; IF root # NIL THEN DO next: Viewer _ root.parent; IF next = NIL THEN EXIT; root _ next; ENDLOOP; }; GetLock: PROC [root: TextNode.Ref] RETURNS [lock: LockRef] ~ INLINE --gfi saver-- { RETURN [LockedGetLock[privateLock, root]] }; privateLock: LockRef ~ NEW[LockRecord]; -- used only to lock GetLock lastRoot: TextNode.Ref _ NIL; lastLock: LockRef _ NIL; LockedGetLock: ENTRY PROC [lock: LockRef, root: TextNode.Ref] RETURNS [LockRef] ~ { ENABLE UNWIND => NULL; IF root = NIL THEN RETURN [NIL]; IF root = lastRoot THEN RETURN [lastLock]; lastRoot _ root; lastLock _ NARROW[NodeProps.GetProp[root, $DocumentLock]]; IF lastLock # NIL THEN RETURN [lastLock]; lastLock _ NEW[LockRecord]; NodeProps.PutProp[root, $DocumentLock, lastLock]; RETURN [lastLock] }; NodeProps.Register[$DocumentLock, NodeProps.NullRead, NodeProps.NullWrite, NodeProps.NullCopy]; END. 2TEditLocksImpl.mesa Copyright Σ 1985, 1987 by Xerox Corporation. All rights reserved. Michael Plass, October 16, 1987 5:00:29 pm PDT Russ Atkinson (RRA) June 18, 1985 4:01:34 pm PDT Governs the locking of the root viewer for non-split viewers Governs the locking of the root viewer for split viewers Like two calls on Lock, but orders the calls according to LockOrder. RRA: this is not used, I think! Be prepared for v = NIL At this point we have a lock on the correct viewer (if asked to do so) The viewer is still the right one, so try to lock the document itself Success! So note the current association for unlocking. Rats! The viewer changed while we were trying for the lock, so let's undo everything. At this point we have a viewer lock, but on the wrong viewer! wait for write lock to clear want write access I don't have a write lock on it already doc is locked wait for all locks to clear had write lock must lock before read tdd.text Returns true iff some process is waiting to get a write lock for the document. Don't copy document lock or big trouble. Κ D˜codešœ™KšœB™BK™.K™0—K˜šΟk ˜ Kšœœ ˜ Kšœ œ=˜LKšœœ˜Kšœœœ˜Kšœœ<˜OKšœ œ˜/Kšœ œ ˜Kšœ œ˜Kšœœ˜#Kšœ œ ˜Kšœœ&˜9K˜—KšΠlnœ œœœ˜Kšœœ œœ˜?Kšœœœ-˜FK˜—šœœ˜KšœF™Fšœ)œ˜1KšœE™EK˜šœ)œ˜1Kšœ8™8Kšœ3˜3Kšœ˜Kšœ˜—KšœU™UKšœ&œ˜+Kšœ˜K˜—K˜—Kšœ=™=Kšœœœ-˜FKšœ˜—˜K˜——šŸœœœœ(˜YKšœœœ˜Kšœ œ˜Kšœœ˜5šœ ˜šœ˜šœ˜ šœœ˜Kšœ™Kšœ˜Kš˜——Kšœ˜—šœ˜Kšœ™šœœ˜"Kšœ'™'šœœ˜Kšœ ™ K˜.šœ˜Kšœ™Kšœ˜Kšœ˜—K˜0—Kšœ˜—Kšœ˜——Kšœœœ˜AK˜Kšœœ˜/Kšœ˜—K˜š Ÿ œœœœœ˜DKš œ œœœœœ&˜NKš œ œœœœœ&˜NKšœ œœ!˜7Kš œœœœœ˜3K˜K˜—šŸœœœ˜+Kšœ˜Kšœœœœ˜Kšœœœœ˜)K˜K˜—K˜šŸœœœ'˜;Kšœœœ˜Kšœ œ(˜:Kšœœœœ˜Kšœœœ˜Kš œœœœ%œœ˜Sšœœ˜Kšœ&˜&šœ˜ šœœ˜šœœ˜Kšœ™KšœC˜CKšœ œ˜)šœ œœ˜šœ*œœ˜=šœœ˜Kšœ4œ˜9Kšœ˜—Kšœœœ˜Kšœ˜—Kšœ5˜5Kšœ˜—Kšœœ˜Kšœ˜—Kšœ˜—Kšœ&œ˜+Kšœœ˜#K˜Kš œ˜K˜——Kšœœœ#˜2K˜—K˜šŸ œœœ2œ,œœœ˜₯šœE˜KKšœ™Kšœœ˜ —š˜K˜KšœΟc3˜NKš œœœœœ˜Kšœ˜šœEœ˜MKšœœœ˜$—Kšœœœ ˜/Kšœ 7˜LKšœ˜—Kšœ˜—K˜šŸœ œ+˜GKšœ œœ˜&Kšœ˜Kšœ˜—K˜š Ÿœ œœœœ˜?K™NKšœ˜"Kšœ˜—K˜šŸœœœ˜9K˜šœœœ˜K˜Kšœœœœ˜K˜ Kšœ˜—K˜K˜—š Ÿœœœœ  œ˜SKšœ#˜)Kšœ˜K˜—Kšœœ ˜DKšœœ˜šœœ˜K˜—šŸ œœœ%œ˜SKšœœœ˜Kš œœœœœ˜ Kšœœœ ˜*K˜Kšœ œ)˜:Kšœ œœœ ˜)Kšœ œ ˜Kšœ1˜1Kšœ ˜Kšœ˜K˜—šœ_˜_K™(K˜——Kšœ˜—…—%