WalnutRegistryImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Donahue, July 9, 1985 1:23:55 pm PDT
Willie-Sue, July 12, 1985 10:01:25 am PDT
Walnut Registry provides notification to outside clients of changes in Walnut databases. Walnut RegistryImpl can be run without running Walnut -- WalnutKernel imports it, rather than the other way around.
Procedures registered with Walnut Registry are placed on the queue, using MBQueue.QueueClientAction, given in the registration when the database changes; clients are guaranteed that the procedures will be queued in the order in which the database changes that caused their invocation occurred.
DIRECTORY
MBQueue,
RefTab,
Rope USING [ROPE],
WalnutRegistry,
WalnutRegistryInternal,
WalnutRegistryPrivate;
WalnutRegistryImpl: CEDAR MONITOR
IMPORTS RefTab, WalnutRegistryInternal
EXPORTS WalnutRegistry, WalnutRegistryPrivate
= BEGIN
RegistrationEntry: TYPE = REF RegistrationRecord;
RegistrationRecord: TYPE = RECORD[queue: MBQueue.Queue, eventProc: EventProcEntry ← NIL, msgProc: MsgProcEntry ← NIL, msgGroupProc: MsgGroupEntry ← NIL, moveProc: MoveProcEntry ← NIL, msgSetProc: MsgSetProcEntry ← NIL];
EventProcEntry: TYPE = REF EventProcRecord;
EventProcRecord: TYPE = RECORD[clientData: REF ANY, proc: WalnutRegistry.EventProc, parent: RegistrationEntry, next, prev: EventProcEntry];
MsgProcEntry: TYPE = REF MsgProcRecord;
MsgProcRecord: TYPE = RECORD[clientData: REF ANY, proc: WalnutRegistry.MsgProc, parent: RegistrationEntry, next, prev: MsgProcEntry];
MoveProcEntry: TYPE = REF MoveProcRecord;
MoveProcRecord: TYPE = RECORD[clientData: REF ANY, proc: WalnutRegistry.MoveProc, parent: RegistrationEntry, next, prev: MoveProcEntry];
MsgGroupEntry: TYPE = REF MsgGroupRecord;
MsgGroupRecord: TYPE = RECORD[clientData: REF ANY, proc: WalnutRegistry.MsgGroupProc, parent: RegistrationEntry, next, prev: MsgGroupEntry];
MsgSetProcEntry: TYPE = REF MsgSetProcRecord;
MsgSetProcRecord: TYPE = RECORD[clientData: REF ANY, proc: WalnutRegistry.MsgSetProc, parent: RegistrationEntry, next, prev: MsgSetProcEntry];
nextRegistration: CARDINAL ← 0;
registrationTable: RefTab.Ref = RefTab.Create[];
the values in the table are the registration entries; the keys are the Registrations returned (they are simply REF CARDINALS)
the registrations are also linked into doubly-linked lists according to the type of procedures
eventProcHead: EventProcEntry;
msgProcHead: MsgProcEntry;
moveProcHead: MoveProcEntry;
msgSetProcHead: MsgSetProcEntry;
msgGroupHead: MsgGroupEntry;
we want to be able to notify new clients of the current state of Walnut
stateIsKnown: BOOLFALSE;
stateIs: WalnutRegistry.Event ← stopped;  -- not reported unless stateIsKnown is TRUE
CurrentWalnutState: PUBLIC ENTRY PROC
RETURNS[walnutState: WalnutRegistry.WalnutState] = {
IF stateIsKnown THEN
{ IF stateIs=stopped THEN RETURN[stopped] ELSE RETURN[active] }
ELSE RETURN[unknown];
};
Register: PUBLIC ENTRY PROC [procSet: WalnutRegistry.ProcSet, queue: MBQueue.Queue] RETURNS[registration: WalnutRegistry.Registration] = {
newEntry: RegistrationEntry = NEW[RegistrationRecord ← [queue: queue]];
registration ← NEW[CARDINAL ← nextRegistration];
nextRegistration ← nextRegistration+1;
[] ← RefTab.Store[registrationTable, registration, newEntry];
stitch it into the appropriate lists
IF procSet.eventProc # NIL THEN {
newEntry.eventProc ← NEW[EventProcRecord ← [clientData: procSet.eventProcData, proc: procSet.eventProc, parent: newEntry]];
newEntry.eventProc.next ← eventProcHead;
newEntry.eventProc.prev ← eventProcHead.prev;
eventProcHead.prev.next ← newEntry.eventProc;
eventProcHead.prev ← newEntry.eventProc;
IF stateIsKnown THEN
WalnutRegistryInternal.QueueEvent[stateIs, queue, procSet.eventProc, procSet.eventProcData];
};
IF procSet.msgProc # NIL THEN {
newEntry.msgProc ← NEW[MsgProcRecord ← [clientData: procSet.msgProcData, proc: procSet.msgProc, parent: newEntry]];
newEntry.msgProc.next ← msgProcHead;
newEntry.msgProc.prev ← msgProcHead.prev;
msgProcHead.prev.next ← newEntry.msgProc;
msgProcHead.prev ← newEntry.msgProc };
IF procSet.moveProc # NIL THEN {
newEntry.moveProc ← NEW[MoveProcRecord ← [clientData: procSet.moveProcData, proc: procSet.moveProc, parent: newEntry]];
newEntry.moveProc.next ← moveProcHead;
newEntry.moveProc.prev ← moveProcHead.prev;
moveProcHead.prev.next ← newEntry.moveProc;
moveProcHead.prev ← newEntry.moveProc };
IF procSet.msgGroupProc # NIL THEN {
newEntry.msgGroupProc ← NEW[MsgGroupRecord ← [clientData: procSet.msgGroupData, proc: procSet.msgGroupProc, parent: newEntry]];
newEntry.msgGroupProc.next ← msgGroupHead;
newEntry.msgGroupProc.prev ← msgGroupHead.prev;
msgGroupHead.prev.next ← newEntry.msgGroupProc;
msgGroupHead.prev ← newEntry.msgGroupProc };
IF procSet.msgSetProc # NIL THEN {
newEntry.msgSetProc ← NEW[MsgSetProcRecord ← [clientData: procSet.msgSetData, proc: procSet.msgSetProc, parent: newEntry]];
newEntry.msgSetProc.next ← msgSetProcHead;
newEntry.msgSetProc.prev ← msgSetProcHead.prev;
msgSetProcHead.prev.next ← newEntry.msgSetProc;
msgSetProcHead.prev ← newEntry.msgSetProc };
};
InvalidRegistration: PUBLIC ERROR = CODE;
UnRegister: PUBLIC ENTRY PROC [registration: WalnutRegistry.Registration] = {
entry: RegistrationEntry = NARROW[RefTab.Fetch[registrationTable, registration].val];
IF entry = NIL THEN ERROR InvalidRegistration;
IF entry.eventProc # NIL THEN {
entry.eventProc.prev.next ← entry.eventProc.next;
entry.eventProc.next.prev ← entry.eventProc.prev;
entry.eventProc.parent ← NIL };
IF entry.msgProc # NIL THEN {
entry.msgProc.prev.next ← entry.msgProc.next;
entry.msgProc.next.prev ← entry.msgProc.prev;
entry.msgProc.parent ← NIL };
IF entry.moveProc # NIL THEN {
entry.moveProc.prev.next ← entry.moveProc.next;
entry.moveProc.next.prev ← entry.moveProc.prev;
entry.moveProc.parent ← NIL };
IF entry.msgGroupProc # NIL THEN {
entry.msgGroupProc.prev.next ← entry.msgGroupProc.next;
entry.msgGroupProc.next.prev ← entry.msgGroupProc.prev;
entry.msgGroupProc.parent ← NIL };
IF entry.msgSetProc # NIL THEN {
entry.msgSetProc.prev.next ← entry.msgSetProc.next;
entry.msgSetProc.next.prev ← entry.msgSetProc.prev;
entry.msgSetProc.parent ← NIL };
[] ← RefTab.Delete[registrationTable, registration] };
GetProcs: PUBLIC ENTRY PROC[registration: WalnutRegistry.Registration] RETURNS[procSet: WalnutRegistry.ProcSet, queue: MBQueue.Queue] = {
entry: RegistrationEntry = NARROW[RefTab.Fetch[registrationTable, registration].val];
IF entry = NIL THEN ERROR InvalidRegistration;
queue ← entry.queue;
IF entry.eventProc # NIL THEN {
procSet.eventProc ← entry.eventProc.proc;
procSet.eventProcData ← entry.eventProc.clientData };
IF entry.msgProc # NIL THEN {
procSet.msgProc ← entry.msgProc.proc;
procSet.msgProcData ← entry.msgProc.clientData};
IF entry.moveProc # NIL THEN {
procSet.moveProc ← entry.moveProc.proc;
procSet.moveProcData ← entry.moveProc.clientData};
IF entry.msgGroupProc # NIL THEN {
procSet.msgGroupProc ← entry.msgGroupProc.proc;
procSet.msgGroupData ← entry.msgGroupProc.clientData};
IF entry.msgSetProc # NIL THEN {
procSet.msgSetProc ← entry.msgSetProc.proc;
procSet.msgSetData ← entry.msgSetProc.clientData}
};
CheckForMsgGroupRegistration: PUBLIC ENTRY PROC RETURNS[yes: BOOL] =
{ RETURN[msgGroupHead.next.proc # NIL] };
NotifyForEvent: PUBLIC ENTRY PROC[event: WalnutRegistry.Event] = TRUSTED {
stateIsKnown ← TRUE;
stateIs ← IF event = mailRead THEN started ELSE event;
FOR e: EventProcEntry ← eventProcHead.next, e.next UNTIL e.proc = NIL DO
WalnutRegistryInternal.QueueEvent[event, e.parent.queue, e.proc, e.clientData];
ENDLOOP };
NotifyForMsgEvent: PUBLIC ENTRY PROC[msgEvent: WalnutRegistry.MsgEvent, msg: Rope.ROPE] = TRUSTED {
FOR e: MsgProcEntry ← msgProcHead.next, e.next UNTIL e.proc = NIL DO
WalnutRegistryInternal.QueueMsgEvent[msgEvent, msg, e.parent.queue, e.proc, e.clientData];
ENDLOOP};
NotifyForMove: PUBLIC ENTRY PROC[msg: Rope.ROPE, to, from: Rope.ROPE] = TRUSTED {
FOR e: MoveProcEntry ← moveProcHead.next, e.next UNTIL e.proc = NIL DO
WalnutRegistryInternal.QueueMoveEvent[msg, to, from, e.parent.queue, e.proc, e.clientData];
ENDLOOP};
NotifyForMsgGroup: PUBLIC ENTRY PROC[event: WalnutRegistry.MsgGroupEvent, group: WalnutRegistry.MsgGroup] = TRUSTED {
msgGroupCopy: REF WalnutRegistry.MsgGroup = NEW[WalnutRegistry.MsgGroup];
msgGroupCopy^ ← group;
FOR e: MsgGroupEntry ← msgGroupHead.next, e.next UNTIL e.proc = NIL DO
WalnutRegistryInternal.QueueMsgGroupEvent[event, msgGroupCopy, e.parent.queue, e.proc, e.clientData];
ENDLOOP};
NotifyForMsgSetEvent: PUBLIC ENTRY PROC[msgSetEvent: WalnutRegistry.MsgSetEvent, msgSet: Rope.ROPE] = TRUSTED {
FOR e: MsgSetProcEntry ← msgSetProcHead.next, e.next UNTIL e.proc = NIL DO
WalnutRegistryInternal.QueueMsgSetEvent[msgSetEvent, msgSet, e.parent.queue, e.proc, e.clientData];
ENDLOOP};
The heads to be non-NIL to make the list manipulation easier and faster
eventProcHead ← NEW[EventProcRecord ← [clientData: NIL, proc: NIL]];
eventProcHead.prev ← eventProcHead.next ← eventProcHead;
msgProcHead ← NEW[MsgProcRecord ← [clientData: NIL, proc: NIL]];
msgProcHead.prev ← msgProcHead.next ← msgProcHead;
moveProcHead ← NEW[MoveProcRecord ← [clientData: NIL, proc: NIL]];
moveProcHead.prev ← moveProcHead.next ← moveProcHead;
msgGroupHead ← NEW[MsgGroupRecord ← [clientData: NIL, proc: NIL]];
msgGroupHead.prev ← msgGroupHead.next ← msgGroupHead;
msgSetProcHead ← NEW[MsgSetProcRecord ← [clientData: NIL, proc: NIL]];
msgSetProcHead.prev ← msgSetProcHead.next ← msgSetProcHead;
END.