DIRECTORY AMEvents USING [Debugged, Debugging], Process USING [GetCurrent, InitializeCondition, MsecToTicks, Pause], Runtime USING [CallDebugger], UserTerminal USING [BlinkDisplay], ViewerClasses USING [Column, Lock, Viewer], ViewerLocks, ViewerOps USING [EnumerateChildren, EnumerateViewers, EnumProc]; ViewerLocksImpl: MONITOR IMPORTS AMEvents, Process, Runtime, UserTerminal, ViewerOps EXPORTS ViewerLocks = BEGIN OPEN ViewerClasses, ViewerOps; lockFree: CONDITION; -- new viewer or column has been released treeLockSynch: CONDITION; -- synchronise read & write requests pending a tree request treeRequest: BOOL _ FALSE; -- viewer tree lock pending request state ColumnInfo: TYPE = RECORD [ lock: Lock, wedgeCount: CARDINAL ]; columns: ARRAY Column OF ColumnInfo ; Error: PROC = INLINE {Runtime.CallDebugger["ViewerLocks bug"]}; InOrder: PROC[v1, v2: Viewer] RETURNS [BOOLEAN] = INLINE { -- highest to lowest RETURN[LOOPHOLE[v1, LONG CARDINAL] >= LOOPHOLE[v2, LONG CARDINAL]]}; CallUnderWriteLock: PUBLIC SAFE PROC [proc: PROC, viewer: Viewer] = TRUSTED BEGIN ENABLE { AMEvents.Debugging => MarkColumnWedged[ViewerColumn[viewer]]; AMEvents.Debugged => MarkColumnUnWedged[ViewerColumn[viewer]]}; AcquireWriteLock[viewer]; proc[]; ReleaseWriteLock[viewer]; END; CallUnderWriteLocks: PUBLIC SAFE PROC [proc: PROC, v0, v1, v2: Viewer _ NIL] = TRUSTED BEGIN ENABLE { AMEvents.Debugging => { IF v0 # NIL THEN MarkColumnWedged[ViewerColumn[v0]]; IF v1 # NIL THEN MarkColumnWedged[ViewerColumn[v1]]; IF v2 # NIL THEN MarkColumnWedged[ViewerColumn[v2]]}; AMEvents.Debugged => { IF v0 # NIL THEN MarkColumnUnWedged[ViewerColumn[v0]]; IF v1 # NIL THEN MarkColumnUnWedged[ViewerColumn[v1]]; IF v2 # NIL THEN MarkColumnUnWedged[ViewerColumn[v2]]}}; AcquireWriteLocks[v0, v1, v2]; proc[]; ReleaseWriteLocks[v0, v1, v2]; END; CallUnderReadLock: PUBLIC SAFE PROC [proc: PROC, viewer: Viewer] = TRUSTED BEGIN ENABLE { AMEvents.Debugging => MarkColumnWedged[ViewerColumn[viewer]]; AMEvents.Debugged => MarkColumnUnWedged[ViewerColumn[viewer]]}; AcquireReadLock[viewer]; proc[]; ReleaseReadLock[viewer]; END; CallUnderReadLocks: PUBLIC SAFE PROC [proc: PROC, v0, v1, v2: Viewer _ NIL] = TRUSTED BEGIN ENABLE { AMEvents.Debugging => { IF v0 # NIL THEN MarkColumnWedged[ViewerColumn[v0]]; IF v1 # NIL THEN MarkColumnWedged[ViewerColumn[v1]]; IF v2 # NIL THEN MarkColumnWedged[ViewerColumn[v2]]}; AMEvents.Debugged => { IF v0 # NIL THEN MarkColumnUnWedged[ViewerColumn[v0]]; IF v1 # NIL THEN MarkColumnUnWedged[ViewerColumn[v1]]; IF v2 # NIL THEN MarkColumnUnWedged[ViewerColumn[v2]]}; }; AcquireReadLocks[v0, v1, v2]; proc[]; ReleaseReadLocks[v0, v1, v2]; END; CallUnderColumnLock: PUBLIC SAFE PROC [proc: PROC, column: Column] = TRUSTED BEGIN ENABLE { AMEvents.Debugging => MarkColumnWedged[column]; AMEvents.Debugged => MarkColumnUnWedged[column]}; Wait: ENTRY PROC = INLINE {ENABLE UNWIND => NULL; WAIT lockFree}; AcquireColumnWriteLock[column ! Wedged => {Wait; RETRY}]; proc[]; ReleaseColumnWriteLock[column]; END; CallUnderColumnLocks: PUBLIC SAFE PROC [proc: PROC, c0, c1: Column] = TRUSTED BEGIN ENABLE { AMEvents.Debugging => {MarkColumnWedged[c0]; MarkColumnWedged[c1]}; AMEvents.Debugged => {MarkColumnUnWedged[c0]; MarkColumnUnWedged[c1]}}; Wait: ENTRY PROC = INLINE {ENABLE UNWIND => NULL; WAIT lockFree}; IF c0 > c1 THEN {c: Column _ c0; c0 _ c1; c1 _ c}; AcquireColumnWriteLock[c0 ! Wedged => {Wait; RETRY}]; AcquireColumnWriteLock[c1 ! Wedged => {Wait; RETRY}]; proc[]; ReleaseColumnWriteLock[c1]; ReleaseColumnWriteLock[c0]; END; CallUnderViewerTreeLock: PUBLIC SAFE PROC [proc: PROC] = TRUSTED BEGIN LockViewerTree[]; proc[]; ReleaseViewerTree[]; END; ViewerColumn: PROC [viewer: Viewer] RETURNS [column: Column] = INLINE {RETURN[IF viewer.iconic THEN static ELSE viewer.column]}; AcquireWriteLock: PUBLIC ENTRY SAFE PROC [viewer: Viewer] = TRUSTED { ENABLE UNWIND => NULL; IF ~WriteLock[viewer] THEN RETURN WITH ERROR Wedged[ViewerColumn[viewer]]}; WriteLock: INTERNAL PROC [viewer: Viewer] RETURNS[success: BOOL _ TRUE] = INLINE BEGIN OPEN viewer; process: PROCESS ~ Process.GetCurrent[]; IF treeRequest THEN WAIT treeLockSynch; -- pause IF ~ReadLockColumn[viewer] THEN RETURN[FALSE]; UNTIL (lock.count=0 OR lock.process=process) DO WAIT lockFree; ENDLOOP; lock _ [process, lock.count+1]; END; ReleaseWriteLock: PUBLIC ENTRY SAFE PROC [viewer: Viewer] = TRUSTED BEGIN OPEN viewer; ENABLE UNWIND => NULL; ReleaseReadLockColumn[ViewerColumn[viewer]]; IF lock.count = 0 THEN Error[]; IF (lock.count _ lock.count-1) = 0 THEN {lock.process _ NIL; BROADCAST lockFree}; END; AcquireWriteLocks: PUBLIC ENTRY SAFE PROC [v0, v1, v2: Viewer _ NIL] = TRUSTED BEGIN ENABLE UNWIND => NULL; v: Viewer; IF ~InOrder[v0, v1] THEN {v _ v0; v0 _ v1; v1 _ v}; IF ~InOrder[v1, v2] THEN {v _ v1; v1 _ v2; v2 _ v}; IF ~InOrder[v0, v1] THEN {v _ v0; v0 _ v1; v1 _ v}; IF v0#NIL THEN IF ~WriteLock[v0] THEN RETURN WITH ERROR Wedged[ViewerColumn[v0]]; IF v1#NIL THEN IF ~WriteLock[v1] THEN { ReleaseWriteLock[v0]; RETURN WITH ERROR Wedged[ViewerColumn[v1]]}; IF v2#NIL THEN IF ~WriteLock[v2] THEN { ReleaseWriteLocks[v0, v1]; RETURN WITH ERROR Wedged[ViewerColumn[v2]]}; END; ReleaseWriteLocks: PUBLIC SAFE PROC [v0, v1, v2: Viewer _ NIL] = TRUSTED BEGIN IF v0#NIL THEN ReleaseWriteLock[v0]; IF v1#NIL THEN ReleaseWriteLock[v1]; IF v2#NIL THEN ReleaseWriteLock[v2]; END; AcquireReadLock: PUBLIC ENTRY SAFE PROC [viewer: Viewer] = TRUSTED { ENABLE UNWIND => NULL; IF ~ReadLock[viewer] THEN RETURN WITH ERROR Wedged[ViewerColumn[viewer]]}; ReadLock: INTERNAL PROC [viewer: Viewer] RETURNS[success: BOOL _ TRUE] = INLINE BEGIN OPEN viewer; process: PROCESS ~ Process.GetCurrent[]; IF treeRequest THEN WAIT treeLockSynch; -- pause IF ~ReadLockColumn[viewer] THEN RETURN[FALSE]; UNTIL (lock.process=NIL OR lock.process=process) DO WAIT lockFree; ENDLOOP; lock.count _ lock.count+1; END; ReleaseReadLock: PUBLIC ENTRY SAFE PROC [viewer: Viewer] = TRUSTED BEGIN ENABLE UNWIND => NULL; ReleaseReadLockColumn[ViewerColumn[viewer]]; IF viewer.lock.count = 0 THEN Error[]; IF (viewer.lock.count _ viewer.lock.count-1) = 0 THEN BROADCAST lockFree; END; AcquireReadLocks: PUBLIC ENTRY SAFE PROC [v0, v1, v2: Viewer _ NIL] = TRUSTED BEGIN ENABLE UNWIND => NULL; v: Viewer; IF ~InOrder[v0, v1] THEN {v _ v0; v0 _ v1; v1 _ v}; IF ~InOrder[v1, v2] THEN {v _ v1; v1 _ v2; v2 _ v}; IF ~InOrder[v0, v1] THEN {v _ v0; v0 _ v1; v1 _ v}; IF v0#NIL THEN IF ~ReadLock[v0] THEN RETURN WITH ERROR Wedged[ViewerColumn[v0]]; IF v1#NIL THEN IF ~ReadLock[v1] THEN { ReleaseReadLock[v0]; RETURN WITH ERROR Wedged[ViewerColumn[v1]]}; IF v2#NIL THEN IF ~ReadLock[v2] THEN { ReleaseReadLocks[v0, v1]; RETURN WITH ERROR Wedged[ViewerColumn[v2]]}; END; ReleaseReadLocks: PUBLIC SAFE PROC [v0, v1, v2: Viewer _ NIL] = TRUSTED BEGIN IF v0#NIL THEN ReleaseReadLock[v0]; IF v1#NIL THEN ReleaseReadLock[v1]; IF v2#NIL THEN ReleaseReadLock[v2]; END; AcquireColumnWriteLock: PUBLIC ENTRY SAFE PROC [column: Column] = TRUSTED BEGIN ENABLE UNWIND => NULL; IF ~ColumnLock[column] THEN RETURN WITH ERROR Wedged[column]; END; ColumnLock: INTERNAL PROC [column: Column] RETURNS[success: BOOL _ TRUE] = BEGIN process: PROCESS ~ Process.GetCurrent[]; IF columns[column].wedgeCount>0 THEN RETURN[FALSE]; UNTIL (columns[column].lock.count=0 OR columns[column].lock.process=process) DO WAIT lockFree; ENDLOOP; columns[column].lock _ [process, columns[column].lock.count+1]; END; ReleaseColumnWriteLock: PUBLIC ENTRY SAFE PROC [column: Column] = TRUSTED {ENABLE UNWIND => NULL; ReleaseColumnLock[column]}; ReleaseColumnLock: INTERNAL PROC [column: Column] = INLINE { IF columns[column].lock.count = 0 THEN Error[]; IF (columns[column].lock.count _ columns[column].lock.count-1) = 0 THEN {columns[column].lock.process _ NIL; BROADCAST lockFree}}; ReadLockColumn: INTERNAL PROC [viewer: Viewer] RETURNS[success: BOOL _ TRUE] = INLINE BEGIN column: Column _ ViewerColumn[viewer]; process: PROCESS ~ Process.GetCurrent[]; IF columns[column].wedgeCount>0 THEN RETURN[FALSE]; UNTIL (columns[column].lock.process=NIL OR columns[column].lock.process=process) DO WAIT lockFree; column _ ViewerColumn[viewer]; IF columns[column].wedgeCount>0 THEN RETURN[FALSE]; ENDLOOP; columns[column].lock.count _ columns[column].lock.count+1; END; ReleaseReadLockColumn: INTERNAL PROC [column: Column] = INLINE BEGIN IF columns[column].lock.count = 0 THEN Error[]; IF (columns[column].lock.count _ columns[column].lock.count-1) = 0 THEN {columns[column].lock.process _ NIL; BROADCAST lockFree}; END; Wedged: PUBLIC SAFE ERROR [wedged: Column] = CODE; ColumnWedged: PUBLIC ENTRY SAFE PROC [column: Column] RETURNS[wedged, write: BOOLEAN] = TRUSTED {RETURN[columns[column].wedgeCount # 0, columns[column].lock.process # NIL]}; MarkColumnWedged: PUBLIC ENTRY SAFE PROC [column: Column] = TRUSTED BEGIN ENABLE UNWIND => NULL; IF columns[column].wedgeCount = 0 THEN THROUGH [0..3) DO UserTerminal.BlinkDisplay[]; Process.Pause[Process.MsecToTicks[100]]; ENDLOOP; columns[column].wedgeCount _ columns[column].wedgeCount+1; END; MarkColumnUnWedged: PUBLIC ENTRY SAFE PROC [column: Column] = TRUSTED BEGIN ENABLE UNWIND => NULL; IF (columns[column].wedgeCount _ columns[column].wedgeCount-1) = 0 THEN BROADCAST lockFree; END; LockViewerTree: PUBLIC ENTRY SAFE PROC = TRUSTED BEGIN ENABLE UNWIND => NULL; treeRequest _ TRUE; -- synchronise further read and write lock requests FOR column: Column IN Column DO IF ~ColumnLock[column] THEN { FOR c: Column IN [FIRST[Column]..column) DO ReleaseColumnLock[c]; ENDLOOP; treeRequest _ FALSE; RETURN WITH ERROR Wedged[column]}; ENDLOOP; treeRequest _ FALSE; END; ReleaseViewerTree: PUBLIC ENTRY SAFE PROC = TRUSTED BEGIN ENABLE UNWIND => NULL; FOR column: Column IN Column DO ReleaseColumnLock[column]; ENDLOOP; END; ClearAllLocks: ENTRY PROC = BEGIN ClearLock: ViewerOps.EnumProc = CHECKED { IF v.parent = NIL THEN ViewerOps.EnumerateChildren[v, ClearLock]; v.lock _ [NIL, 0]}; FOR c: Column IN Column DO columns[c] _ [[NIL, 0], 0]; ENDLOOP; ViewerOps.EnumerateViewers[ClearLock]; BROADCAST lockFree; END; Process.InitializeCondition[@treeLockSynch, Process.MsecToTicks[50]]; END. ’ViewerLocksImpl.mesa; Written by S. McGregor Edited by McGregor on July 21, 1983 2:58 pm Last Edited by: Maxwell, February 7, 1983 12:50 pm Viewers must be sorted so that they are locked from highest to lowest, by column. no sort required viewers must be sorted so that they are locked from highest to lowest no sort required Same as AcquireColumnWriteLock except does ERROR since internal proc Κλ– "cedar" style˜IcodešΟc,™,Kš+™+J™2K˜šΟk ˜ Kšœ žœ˜%Kšœžœ7˜DKšœžœ˜Kšœ žœ˜"Kšœžœ˜+Kšœ ˜ Kšœ žœ2˜A—K˜šœž˜Kšžœ4˜;Kšžœžœžœ˜:—K˜Kšœ ž œ)˜?K˜Kšœž œ;˜UKšœ žœžœ)˜DK˜šœ žœžœ˜Kšœ ˜ Kšœ ž˜Kšœ˜—K˜Kšœ žœžœ ˜%K˜KšΟnœžœžœ+˜?K˜š Ÿœžœžœžœžœ˜OKšžœžœžœžœž œžœžœ˜D—K˜š Ÿœž œžœžœžœž˜Qšžœžœ˜ Kšœ=˜=Kšœ?˜?—Kšœ˜Kšœ˜Kšœ˜Kšžœ˜K˜—š Ÿœž œžœžœžœ˜NKšžœž˜ šžœ˜ šœ˜Kšžœžœžœ$˜4Kšžœžœžœ$˜4Kšžœžœžœ%˜5—šœ˜Kšžœžœžœ&˜6Kšžœžœžœ&˜6Kšžœžœžœ(˜8——Kšœ˜Kšœ˜Kšœ˜Kšžœ˜K˜—š Ÿœž œžœžœžœž˜Pšžœžœ˜ Kšœ=˜=Kšœ?˜?—Kšœ˜Kšœ˜Kšœ˜Kšžœ˜K˜—š Ÿœž œžœžœžœ˜MKšžœž˜ šžœžœ˜ šœ˜Kšžœžœžœ$˜4Kšžœžœžœ$˜4Kšžœžœžœ%˜5—šœ˜Kšžœžœžœ&˜6Kšžœžœžœ&˜6Kšžœžœžœ'˜7Kšœ˜——Kšœ˜Kšœ˜Kšœ˜Kšžœ˜K˜—š Ÿœž œžœžœžœž˜Ršžœžœ˜ Kšœ/˜/Kšœ1˜1—Kš Ÿœžœžœžœžœ ˜AKšœ1žœ˜9Kšœ˜Kšœ˜Kšžœ˜K˜—š Ÿœž œžœžœžœž˜Sšžœžœ˜ KšœC˜CKšœG˜G—Kš Ÿœžœžœžœžœ ˜AKšžœ žœ#˜2Kšœ-žœ˜5Kšœ-žœ˜5Kšœ˜Kšœ˜Kšœ˜Kšžœ˜K˜—š Ÿœž œžœžœžœž˜FKšœ˜Kšœ˜Kšœ˜Kšžœ˜—K˜šŸ œžœžœž˜EKš œžœžœžœžœ˜:—K˜š Ÿœžœžœžœžœžœ˜EKšž˜Kš žœžœžœžœžœ˜KK˜—š Ÿ œžœžœžœ žœžœ˜JKšžœžœžœ˜Kšœ žœ˜(Kšžœ žœžœ˜0Kšžœžœžœžœ˜.Kš žœžœžœžœ žœ˜GKšœ˜Kšžœ˜K˜—šŸœžœžœžœžœžœžœžœ˜VKšžœ˜Kšœ,˜,Kšžœžœ ˜Kšžœ!žœžœž œ ˜QKšžœ˜K˜—šŸœžœžœžœžœžœžœž˜TKšQ™QKšžœ˜Kšœ ˜ Kšžœžœ˜3Kšžœžœ˜3Kšžœžœ˜3š žœžœžœžœžœ˜&Kšžœžœžœ˜+—š žœžœžœžœžœ˜'Kšœžœžœžœ˜B—š žœžœžœžœžœ˜'Kšœžœžœžœ˜G—Kšžœ˜K˜—š Ÿœž œžœžœžœž˜NKš™Kšžœžœžœ˜$Kšžœžœžœ˜$Kšžœžœžœ˜$Kšžœ˜—K˜š Ÿœžœžœžœžœžœ˜DKšžœžœžœ˜Kš žœžœžœžœžœ˜JK˜—š Ÿœžœžœžœ žœžœ˜IKšžœžœžœ˜Kšœ žœ˜(Kšžœ žœžœ˜0Kšžœžœžœžœ˜.Kš žœžœžœžœžœ žœ˜KKšœ˜Kšžœ˜K˜—š Ÿœžœžœžœžœžœž˜HKšžœ˜Kšœ,˜,Kšžœžœ ˜&Kšžœ/žœž œ ˜IKšžœ˜K˜—šŸœžœžœžœžœžœžœž˜SKšE™EKšžœ˜Kšœ ˜ Kšžœžœ˜3Kšžœžœ˜3Kšžœžœ˜3š žœžœžœžœžœ˜%Kšžœžœžœ˜+—š žœžœžœžœžœ˜&Kšœžœžœžœ˜A—š žœžœžœžœžœ˜&Kšœžœžœžœ˜F—Kšžœ˜K˜—š Ÿœž œžœžœžœž˜MKš™Kšžœžœžœ˜#Kšžœžœžœ˜#Kšžœžœžœ˜#Kšžœ˜—K˜š Ÿœžœžœžœžœžœž˜OKšžœ˜Kš žœžœžœžœžœ˜=Kšžœ˜K˜—š Ÿ œžœžœžœ žœžœž˜PKšœœ&žœ™DKšœ žœ˜(Kšžœžœžœžœ˜3šžœžœ'ž˜OKšžœ ˜Kšžœ˜—Kšœ?˜?Kšžœ˜K˜—š Ÿœžœžœžœžœ˜AKšžœžœ˜;K˜—šŸœžœžœžœ˜