Tango: What happens in the notifd process?
This HowTo describe the Tango's usage of the notifd process and the tool you can use to check its activity
Tango is using the CORBA notification service for its event system. The implementation of the notification service used actually is called omniNotify. In practise, this is a daemon process called notifd. If you want to receive event(s) from Tango device attribute, one notifd process has to run on each crate where the Tango device server(s) is(are) running. The device server sends the event to this notifd process and it is the rule of this daemon to forward this event to all interested clients.
From the notifd point of view, the Device server is the event supplier and the applications are the event consumers. Within the notifd, events are propagated by Event channel. Within this channel, the events are propagated to the applications according to the filters they have created in the channel. With omniNotify, we have a tool called ndadmin which allow a user to monitor the notification service event channels and filters.
Objects created in the notification service (notifd)
Tango creates one event channel (in its startup sequence) for each device server process even if there is no client requesting for event. There is one extra channel for notifd itself. Therefore, the number of event channels in a notifd process is the number of DS running of this crate plus one. Each event channel will have one supplier (the device server) and X consumer (the application waiting for events). The application registers as consumer in the event channel during the DeviceProxy::subscribe_event() method. This method also create the necessary filters associated to the application. Each application need 1 + n filters, n being the number of couple attribute/event type on which it is listening (waiting for the archive event of attribute att1 is not the same thing than waiting for change event of the same attribute). There is one extra filter needed by the Tango heartbeat (a system dedicated to check if the device server is alive).
As an example, on a crate where 6 device servers processes are running, one application listening on change event of one attribute belonging to a device running in device server 2, one application listening on archive event on 3 attributes belonging to a device running in device server 5 and a last application listening on archive and change event of 1 attribute belonging to a device running in device server 5, we will have:
- 7 event channels defined in the notifd (1 + 6)
- Each event channel associated to Tango device server process will have 1 supplier
- The event channel associated with device server process number 2 will have 1 consumer with 2 filters
- The event channel associated with device server process number 5 will have 2 consumers with:
- 4 filters for application 1 (1 + 3)
3 filters for application 2 (1 + 2)
Using the ndadmin tool
You will find the ndadmin tool in the bin directory of the tree where notifd has been built. Start it with the -f option followed by the name of the file where notifd stored the main parameter needed to build a connection with it (The channel factory CORBA IOR). In a typical Tango system, it's "/tmp/rdichan.ior"
>ndadmin -f /tmp/rdichan.iorYou can forget the -f option (and the file name) but you will have an extra line telling you that ndadmin had an exception while it tried to contact the CORBA Naming service (not used in a Tango system)
---------------------------------------------
omniNotify Server Version 2.1
AT&T Laboratories -- Research
---------------------------------------------
Interactive Mode [server]:
We are mainly interested in the parameters linked to Event channels. The command "go chanfact" asks ndadmin to change to the channel factory. The command "children" will display the list of all the event channels built. Each channel has a name like "chanX".
Interactive Mode [server]: go chanfactIn this example (on one of the ESRF machine control system crate), we have 18 event channels because 17 device server processes are running on this crate: 16 classical device servers plus the starter.
omniNotify: new target ==> chanfact
Interactive Mode [server.chanfact]: children
Children of chanfact : chan0, chan1, chan2, chan3, chan4, chan5, chan6, chan7, chan8, chan9, chan10, chan11, chan12, chan13, chan14, chan15, chan16, chan17
(Use 'go <name>' to go to one of the children)
The name of these event channels is chosen by notifd and it is not always easy to find which event channel is used by which device server. Nevertheless, the naming follows more or less the channel creation order and after a crate reboot, most of the time (but not always), chan1 will be used by the Starter and the other channels will be used by device server in the order they are created by the starter (See astor crate control panel and device server run level on that crate).
Checking the device server process side
Each channel has one supplier admin and one consumer admin objects automatically created by the notifd. To check if the device server sends event to the channel, you have to go to the specific channel and then to the supplier admin object (called sadmin0). The command "children" will display the proxy object used by the device server to send the event to the notifd.
Interactive Mode [server.chanfact]: go chan2The supplier admin sadmin0 has only one children (called proxy1) which is the device server process. The command "debug" allows you to check that the heartbeat event is correctly sent (every 10 seconds)
omniNotify: new target ==> chan2
Interactive Mode [server.chanfact.chan2]: children
Children of chan2 : cadmin0, sadmin0
(Use 'go <name>' to go to one of the children)
Interactive Mode [server.chanfact.chan2]: go sadmin0
omniNotify: new target ==> sadmin0
Interactive Mode [server.chanfact.chan2.sadmin0]: children
Children of sadmin0 : proxy1
(Use 'go <name>' to go to one of the children)
Interactive Mode [server.chanfact.chan2.sadmin0]: debugThe interesting part is the last line. It tells you that the device server process is connected. Events is the number of events sent by the device server process to this channel. By typing several time this "debug" command, you should see the Events number increasing.
----------------------------------------------------------------------
Supplier Admin server.chanfact.chan2.sadmin0
----------------------------------------------------------------------
0x9f13420 ID 0
Last Use Thu Jun 19 14:20:46 2008 [+ 673169000 nanosecs] (local time)
----------------------------------------------------------------------
NotifQos settings for server.chanfact.chan2.sadmin0
----------------------------------------------------------------------
EventReliability 0 | ConnectionReliability 0 | Priority 0
StartTimeSupported 0 | StopTimeSupported 0 | OrderPolicy 0
DiscardPolicy 0 | MaxEventsPerConsumer 0 | MaximumBatchSize 8
Timeout(s,n) (0,0)
PacingInterval(s,n) (1,0)
All values are inherited from parent.
1 : 0x9ef74c0 -- PUSH_STR ID 1 Connected #Events 9186
Checking the application side
We now have to go to the consumer admin object called cadmin0. The command "up" allows you to go one level up in the event channel object hierarchy. Again, the command "children" will display all the proxy objects used by the applications connected to this channel.Interactive Mode [server.chanfact.chan2.sadmin0]: up
omniNotify: new target ==> chan2
Interactive Mode [server.chanfact.chan2]: go cadmin0
omniNotify: new target ==> cadmin0
Interactive Mode [server.chanfact.chan2.cadmin0]: children
Children of cadmin0 : proxy32, proxy1, proxy2, proxy13, proxy31
(Use 'go <name>' to go to one of the children)
Interactive Mode [server.chanfact.chan2.cadmin0]:
In this case, we have 5 applications listening for events coming from this channel. The command "info filters" gives interesting results.
Interactive Mode [server.chanfact.chan2.cadmin0]: info filters
----------------------------------------------------------------------
Admin Filters attached to server.chanfact.chan2.cadmin0
----------------------------------------------------------------------
(no attached filters)
----------------------------------------------------------------------
Proxy Filters attached to server.chanfact.chan2.cadmin0.proxy32
----------------------------------------------------------------------
[server.filtfact.filter104] #constraints = 1
Constraint 0 Types EventTypeSeq:{ *::* }
Expression: $event_name == 'heartbeat'
This filter attached to 1 proxies or admins, 0 external callbacks.
[server.filtfact.filter105] #constraints = 1
Constraint 0 Types EventTypeSeq:{ *::* }
Expression: $domain_name == 'tango/admin/l-c06-1/state' and $event_name == 'change'
This filter attached to 1 proxies or admins, 0 external callbacks.
----------------------------------------------------------------------
Proxy Filters attached to server.chanfact.chan2.cadmin0.proxy1
----------------------------------------------------------------------
[server.filtfact.filter10] #constraints = 1
Constraint 0 Types EventTypeSeq:{ *::* }
Expression: $event_name == 'heartbeat'
This filter attached to 1 proxies or admins, 0 external callbacks.
[server.filtfact.filter11] #constraints = 1
Constraint 0 Types EventTypeSeq:{ *::* }
Expression: $domain_name == 'tango/admin/l-c06-1/state' and $event_name == 'change'
This filter attached to 1 proxies or admins, 0 external callbacks.
----------------------------------------------------------------------
Proxy Filters attached to server.chanfact.chan2.cadmin0.proxy2
----------------------------------------------------------------------
[server.filtfact.filter12] #constraints = 1
Constraint 0 Types EventTypeSeq:{ *::* }
Expression: $event_name == 'heartbeat'
This filter attached to 1 proxies or admins, 0 external callbacks.
[server.filtfact.filter13] #constraints = 1
Constraint 0 Types EventTypeSeq:{ *::* }
Expression: $domain_name == 'tango/admin/l-c06-1/state' and $event_name == 'change'
This filter attached to 1 proxies or admins, 0 external callbacks.
----------------------------------------------------------------------
Proxy Filters attached to server.chanfact.chan2.cadmin0.proxy13
----------------------------------------------------------------------
[server.filtfact.filter50] #constraints = 1
Constraint 0 Types EventTypeSeq:{ *::* }
Expression: $event_name == 'heartbeat'
This filter attached to 1 proxies or admins, 0 external callbacks.
[server.filtfact.filter51] #constraints = 1
Constraint 0 Types EventTypeSeq:{ *::* }
Expression: $domain_name == 'tango/admin/l-c06-1/state' and $event_name == 'change'
This filter attached to 1 proxies or admins, 0 external callbacks.
----------------------------------------------------------------------
Proxy Filters attached to server.chanfact.chan2.cadmin0.proxy31
----------------------------------------------------------------------
[server.filtfact.filter102] #constraints = 1
Constraint 0 Types EventTypeSeq:{ *::* }
Expression: $event_name == 'heartbeat'
This filter attached to 1 proxies or admins, 0 external callbacks.
[server.filtfact.filter103] #constraints = 1
Constraint 0 Types EventTypeSeq:{ *::* }
Expression: $domain_name == 'tango/admin/l-c06-1/state' and $event_name == 'change'
This filter attached to 1 proxies or admins, 0 external callbacks.
Interactive Mode [server.chanfact.chan2.cadmin0]:
From the filter expressions, it is now clear that the device server process attached to this channel is the Starter device server and the applications are Astor applications listenning on State change event on the starter device.
The command "debug" could also help
Interactive Mode [server.chanfact.chan2.cadmin0]: debug
----------------------------------------------------------------------
Consumer Admin server.chanfact.chan2.cadmin0
----------------------------------------------------------------------
0x8178c78 ID 0
Last Use Fri Jun 20 11:02:45 2008 [+ 698713000 nanosecs] (local time)
----------------------------------------------------------------------
NotifQos settings for server.chanfact.chan2.cadmin0
----------------------------------------------------------------------
EventReliability 0 | ConnectionReliability 0 | Priority 0
StartTimeSupported 0 | StopTimeSupported 0 | OrderPolicy 0
DiscardPolicy 0 | MaxEventsPerConsumer 0 | MaximumBatchSize 8
Timeout(s,n) (0,0)
PacingInterval(s,n) (1,0)
All values are inherited from parent.
1 : 0x84c69f8 -- PUSH_STR ID 32 Connected QSize 0 #Push 1257
2 : 0x82ccc08 -- PUSH_STR ID 1 Connected QSize 0 #Push 15668
3 : 0x8303e10 -- PUSH_STR ID 2 Connected QSize 0 #Push 15667
4 : 0x85b1700 -- PUSH_STR ID 13 Connected QSize 0 #Push 11842
5 : 0x854d690 -- PUSH_STR ID 31 Connected QSize 0 #Push 1378
Here again, the most interesting lines are the last one. We see that all the applications are still correctly connected to the channel. By typing several times this command, you should see the number of pushed events increasing (at least due to the heartbeat event).
To exit this tool, simply types the "exit" command.