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: BOOL ← FALSE;
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.