Often one subsystem wants to be notified of something happening in another subsystem. Notifier Chains solve this problem by providing a way for different subsystems to subscribe on asynchronous events from other subsystems.
Examples of such notifications include the following:
- Die notification - sent when a kernel function triggers a trap or a fault.
- Net device notification - sent when a network interface goes up or down.
- Internet address notification - Sent when IP is changed on a network interface.
To be able to receive notification, a user must register its handler function with a specific notifier.
A handler function signature is:
int some_handler(struct notifier_block *self, unsigned long val, void *data)
- val - type of event
- data - pointer to some data structure
For example, for - die event, val equals - 0 if it is an "oops" event, and data points to a structure which contains all CPU registers status.
Some example code:
#include <linux/notifier.h> #include <asm/kdebug.h> #include <linux/netdevice.h> #include <linux/inetdevice.h> /* Net Device notifier definition */ static struct notifier_block my_net_dev_notifier = { .notifier_call = my_net_dev_event_handler, }; /* Net Device notification event handler */ int my_net_dev_event_handler(struct notifier_block *self,
unsigned long val, void *data) { printk("my_net_dev_event: status=%ld, Interface=%s\n", val,
((struct net_device *) data)->name); return 0; } static int __init my_init(void) { // Register Net Device Notifier register_netdevice_notifier(&my_net_dev_notifier); }
You can generate this event by changing a state of a network interface, for example:
$sudo ifconfig eth0 up
You should receive a message:
my_net_dev_event_handler: status=1, Interface=eth0
When status=1, it means NETDEV_UP event.
Some example of a custom of a custom notifier:
#include <linux/notifier.h> #include <asm/kdebug.h> /* User-defined notifier chain implementation */ static BLOCKING_NOTIFIER_HEAD(my_notif_chain); static struct notifier_block my_notifier = { .notifier_call = my_event_handler, }; /* User-defined notification event handler */ int my_event_handler(struct notifier_block *self,
unsigned long val, void *data) { printk("my_event_handler: status=%ld\n", val); return 0; } /* Driver Initialization */ static int __init my_init(void) { // Register a user-defined Notifier blocking_notifier_chain_register(&my_notif_chain,
&my_notifier);
}
You may invoke this new custom event anywhere in the code by calling:
blocking_notifier_call_chain(&my_notif_chain, 1000, NULL);
You should receive a message:
my_event_handler: status=1000
Note:
We have declared our notification chain using - BLOCKING_NOTIFIER_HEAD
and registered our notifier using blocking_notifier_chain_register() function. By doing that, we declared that the notifier will be called from a process and because of that the handler function is allowed to sleep.
Now, if your notifier can be called from interrupt context, declare the notifier chain using ATOMIC_NOTIFIER_HEAD(), and register it via atomic_notifier_chain_register().
Thats all for now... Thanks for reading!
No comments:
Post a Comment