DIRECTORY AMEvents USING [Debugged, Debugging], Interminal USING [terminal], Process USING [GetCurrent, InitializeCondition, MsecToTicks, Pause], DebuggerSwap USING [CallDebugger], Terminal USING [BlinkBWDisplay], ViewerClasses USING [Column, Lock, Viewer], ViewerLocks USING [], ViewerOps USING [EnumerateChildren, EnumerateViewers, EnumProc]; ViewerLocksImpl: MONITOR IMPORTS AMEvents, Interminal, Process, DebuggerSwap, Terminal, 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 {DebuggerSwap.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 Interminal.terminal.BlinkBWDisplay[]; 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 Copyright c 1982, 1983, 1984 Xerox Corporation. All rights reserved. Edited by McGregor on October 27, 1982 10:27 am Last Edited by: Maxwell, February 7, 1983 12:50 pm Last Edited by: Paul Rovner, June 15, 1983 5:46 pm Doug Wyatt, September 4, 1984 4:17:35 pm PDT 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˜šœ™Jšœ Οmœ:™EJšœ/™/J™2J™2J™,J™—šΟk ˜ Jšœ žœ˜%Jšœ žœ ˜Jšœžœ7˜DJšœ žœ˜"Jšœ žœ˜ Jšœžœ˜+Jšœ žœ˜Jšœ žœ2˜A—J˜šœž˜JšžœA˜HJšžœžœžœ˜:—J˜Jšœ ž œΟc)˜?J˜Jšœž œŸ;˜UJšœ žœžœŸ)˜DJ˜šœ žœžœ˜Jšœ ˜ Jšœ ž˜Jšœ˜—J˜Jšœ žœžœ ˜%J˜JšΟnœžœžœ0˜DJ˜š  œžœžœžœžœŸ˜OJšžœžœžœžœž œžœžœ˜D—J˜š  œž œžœžœžœž˜Qšžœžœ˜ Jšœ=˜=Jšœ?˜?—Jšœ˜Jšœ˜Jšœ˜Jšžœ˜J˜—š  œž œžœžœžœ˜NJšžœž˜ šžœ˜ šœ˜Jšžœžœžœ$˜4Jšžœžœžœ$˜4Jšžœžœžœ%˜5—šœ˜Jšžœžœžœ&˜6Jšžœžœžœ&˜6Jšžœžœžœ(˜8——Jšœ˜Jšœ˜Jšœ˜Jšžœ˜J˜—š  œž œžœžœžœž˜Pšžœžœ˜ Jšœ=˜=Jšœ?˜?—Jšœ˜Jšœ˜Jšœ˜Jšžœ˜J˜—š  œž œžœžœžœ˜MJšžœž˜ šžœžœ˜ šœ˜Jšžœžœžœ$˜4Jšžœžœžœ$˜4Jšžœžœžœ%˜5—šœ˜Jšžœžœžœ&˜6Jšžœžœžœ&˜6Jšžœžœžœ'˜7Jšœ˜——Jšœ˜Jšœ˜Jšœ˜Jšžœ˜J˜—š  œž œžœžœžœž˜Ršžœžœ˜ Jšœ/˜/Jšœ1˜1—Jš  œžœžœžœžœ ˜AJšœ1žœ˜9Jšœ˜Jšœ˜Jšžœ˜J˜—š  œž œžœžœžœž˜Sšžœžœ˜ JšœC˜CJšœG˜G—Jš  œžœžœžœžœ ˜AJšžœ žœ#˜2Jšœ-žœ˜5Jšœ-žœ˜5Jšœ˜Jšœ˜Jšœ˜Jšžœ˜J˜—š  œž œžœžœžœž˜FJšœ˜Jšœ˜Jšœ˜Jšžœ˜—J˜š  œžœžœž˜EJš œžœžœžœžœ˜:—J˜š  œžœžœžœžœžœ˜EJšž˜Jš žœžœžœžœžœ˜KJ˜—š   œžœžœžœ žœžœ˜JJšžœžœžœ˜Jšœ žœ˜(Jšžœ žœžœŸ˜0Jšžœžœžœžœ˜.Jš žœžœžœžœ žœ˜GJšœ˜Jšžœ˜J˜—š œžœžœžœžœžœžœžœ˜VJšžœ˜Jšœ,˜,Jšžœžœ ˜Jšžœ!žœžœž œ ˜QJšžœ˜J˜—š œžœžœžœžœžœžœž˜TJšŸQ™QJšžœ˜Jšœ ˜ Jšžœžœ˜3Jšžœžœ˜3Jšžœžœ˜3š žœžœžœžœžœ˜&Jšžœžœžœ˜+—š žœžœžœžœžœ˜'Jšœžœžœžœ˜B—š žœžœžœžœžœ˜'Jšœžœžœžœ˜G—Jšžœ˜J˜—š  œž œžœžœžœž˜NJšŸ™Jšžœžœžœ˜$Jšžœžœžœ˜$Jšžœžœžœ˜$Jšžœ˜—J˜š  œžœžœžœžœžœ˜DJšžœžœžœ˜Jš žœžœžœžœžœ˜JJ˜—š  œžœžœžœ žœžœ˜IJšžœžœžœ˜Jšœ žœ˜(Jšžœ žœžœŸ˜0Jšžœžœžœžœ˜.Jš žœžœžœžœžœ žœ˜KJšœ˜Jšžœ˜J˜—š  œžœžœžœžœžœž˜HJšžœ˜Jšœ,˜,Jšžœžœ ˜&Jšžœ/žœž œ ˜IJšžœ˜J˜—š œžœžœžœžœžœžœž˜SJšŸE™EJšžœ˜Jšœ ˜ Jšžœžœ˜3Jšžœžœ˜3Jšžœžœ˜3š žœžœžœžœžœ˜%Jšžœžœžœ˜+—š žœžœžœžœžœ˜&Jšœžœžœžœ˜A—š žœžœžœžœžœ˜&Jšœžœžœžœ˜F—Jšžœ˜J˜—š  œž œžœžœžœž˜MJšŸ™Jšžœžœžœ˜#Jšžœžœžœ˜#Jšžœžœžœ˜#Jšžœ˜—J˜š  œžœžœžœžœžœž˜OJšžœ˜Jš žœžœžœžœžœ˜=Jšžœ˜J˜—š   œžœžœžœ žœžœž˜PJšœŸœ&žœ™DJšœ žœ˜(Jšžœžœžœžœ˜3šžœžœ'ž˜OJšžœ ˜Jšžœ˜—Jšœ?˜?Jšžœ˜J˜—š  œžœžœžœžœ˜AJšžœžœ˜;J˜—š œžœžœžœ˜