-- EditNotifyImpl.mesa
-- written by Bill Paxton, March 1981
-- last edit by Bill Paxton, October 18, 1982 10:42 am
DIRECTORY
EditNotify,
TextNode;
EditNotifyImpl:
CEDAR MONITOR
IMPORTS TextNode
EXPORTS EditNotify =
BEGIN
OPEN EditNotify;
NotifyList: TYPE = REF NotifyListBody;
NotifyListBody:
TYPE =
RECORD [
next: NotifyList,
action: EditNotifyProc,
changeSet: ChangeSet ];
NotifyArray: TYPE = ARRAY Priority OF NotifyList;
beforeProcs: NotifyArray;
afterProcs: NotifyArray;
-- **** Notification Operations ****
unlocked: CONDITION;
lockCount: INTEGER ← 0;
Lock: ENTRY PROC = { lockCount ← lockCount+1 };
Unlock:
ENTRY
PROC = {
IF (lockCount ← lockCount-1) <= 0 THEN { lockCount ← 0; BROADCAST unlocked }};
AddNotifyProc:
PUBLIC
ENTRY
PROC [
proc: EditNotifyProc,
time: When ← after,
priority: Priority ← normal,
changeSet: ChangeSet ← defaultChangeSet] = {
ENABLE UNWIND => NULL;
WHILE lockCount > 0 DO WAIT unlocked; ENDLOOP;
RemoveNotify[proc, time];
IF time=before
THEN
beforeProcs[priority] ←
TextNode.pZone.NEW[NotifyListBody ← [beforeProcs[priority], proc, changeSet]]
ELSE afterProcs[priority] ←
TextNode.pZone.NEW[NotifyListBody ← [afterProcs[priority], proc, changeSet]]};
RemoveNotifyProc:
PUBLIC
ENTRY
PROC
[proc: EditNotifyProc, time: When ← after] = {
-- remove proc from list of notification procedures
ENABLE UNWIND => NULL;
WHILE lockCount > 0 DO WAIT unlocked; ENDLOOP;
RemoveNotify[proc, time] };
RemoveNotify:
PROC
[proc: EditNotifyProc, time: When ← after] = {
FOR p:Priority
IN Priority
DO
prev: NotifyList ← NIL;
list: NotifyList ←
IF time=before
THEN beforeProcs[p]
ELSE afterProcs[p];
IF list=NIL THEN LOOP;
UNTIL list=
NIL
DO
IF list.action = proc THEN EXIT;
prev ← list; list ← list.next;
REPEAT FINISHED => LOOP; -- proc not found on this list
ENDLOOP;
IF prev#NIL THEN prev.next ← list.next
ELSE IF time=before THEN beforeProcs[p] ← list.next
ELSE afterProcs[p] ← list.next;
ENDLOOP };
Notify:
PUBLIC
PROC [change:
REF
READONLY Change, time: When] = {
-- call notification procedures
ENABLE UNWIND => Unlock[];
kind: ChangeType;
IF change=NIL THEN RETURN;
kind ← change.kind;
Lock[];
FOR p:Priority
IN Priority
DO
FOR lst:NotifyList ← GetList[p,time], lst.next
UNTIL lst=
NIL
DO
IF lst.changeSet[kind] THEN lst.action[change];
ENDLOOP;
ENDLOOP;
GetList:
PROC [p:Priority, time:When]
RETURNS [NotifyList] =
INLINE
{ RETURN [IF time=before THEN beforeProcs[p] ELSE afterProcs[p]] };
Start:
PUBLIC
PROC = {
};
END.