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[]; eventProcHead: EventProcEntry; msgProcHead: MsgProcEntry; moveProcHead: MoveProcEntry; msgSetProcHead: MsgSetProcEntry; msgGroupHead: MsgGroupEntry; 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]; 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}; 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. 2WalnutRegistryImpl.mesa Copyright c 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. 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 we want to be able to notify new clients of the current state of Walnut stitch it into the appropriate lists The heads to be non-NIL to make the list manipulation easier and faster Κ˜šΟb™Jšœ Οmœ1™