Linux 中的 Notifier(通知链,Notifier Chain) 是内核中一种非常常见的事件发布/订阅机制。它允许一个模块在某个事件发生时,通知多个对此事件感兴趣的模块,而不需要彼此直接依赖。有点类似于MQTT协议。
通知链的核心思想是:“等事情发生了,我再通知你”
定义通知链:内核某个子系统定义一个链表头(Chain Head)。
注册(订阅):其他对该事件感兴趣的模块,调用注册函数将自己的回调函数(Callback)挂到这个链表上。
通知(发布):当该子系统触发了特定事件,它会遍历这个链表,依次执行所有注册的回调函数。
Linux 内核根据运行环境和锁的需求,提供了四种不同类型的通知链:
点击放大
struct notifier_block { //回调函数 //action:发生的事件类型 data:传递的数据指针 int (*notifier_call)(struct notifier_block *nb, unsigned long action, void *data); //指向链表中下一个节点的指针 struct notifier_block __rcu *next; //优先级, 数值越大,越优先被调用。如果都一样,就按注册顺序决定。 int priority;};
回调函数 notifier_call 的返回值非常关键,它决定了通知链接下来如何运行。常见的返回值(定义在 <linux/notifier.h>)包括:
NOTIFY_DONE:对该事件不感兴趣,允许通知链继续往下走。
NOTIFY_OK:事件处理成功,允许通知链继续往下走。
NOTIFY_BAD:发生错误,停止继续通知后续的节点。
NOTIFY_STOP:主动要求中止后续的通知(不需要继续往下传了)。
//定义notifier head#define ATOMIC_NOTIFIER_HEAD(name) \ struct atomic_notifier_head name = \ ATOMIC_NOTIFIER_INIT(name)#define BLOCKING_NOTIFIER_HEAD(name) \ struct blocking_notifier_head name = \ BLOCKING_NOTIFIER_INIT(name)#define RAW_NOTIFIER_HEAD(name) \ struct raw_notifier_head name = \ RAW_NOTIFIER_INIT(name)#define SRCU_NOTIFIER_HEAD(name) \ _SRCU_NOTIFIER_HEAD(name, /* not static */)//添加监听intatomic_notifier_chain_register(struct atomic_notifier_head *nh, struct notifier_block *nb);intblocking_notifier_chain_register(struct blocking_notifier_head *nh, struct notifier_block *nb);intraw_notifier_chain_register(struct raw_notifier_head *nh, struct notifier_block *nb);intsrcu_notifier_chain_register(struct srcu_notifier_head *nh, struct notifier_block *nb);//注销监听intatomic_notifier_chain_unregister(struct atomic_notifier_head *nh, struct notifier_block *nb);intblocking_notifier_chain_unregister(struct blocking_notifier_head *nh, struct notifier_block *nb);intraw_notifier_chain_unregister(struct raw_notifier_head *nh, struct notifier_block *nb);intsrcu_notifier_chain_unregister(struct srcu_notifier_head *nh, struct notifier_block *nb);//发送通知intatomic_notifier_call_chain(struct atomic_notifier_head *nh, unsigned long val, void *v);intblocking_notifier_call_chain(struct blocking_notifier_head *nh, unsigned long val, void *v);intraw_notifier_call_chain(struct raw_notifier_head *nh, unsigned long val, void *v);intsrcu_notifier_call_chain(struct srcu_notifier_head *nh, unsigned long val, void *v);
由于传统的 notifier_block 结构体和底层注册函数比较通用、抽象,如果每个子系统都直接去调用它们,代码会显得非常臃肿且容易出错。为了简化开发、提高代码可读性并隐藏实现细节,内核中几乎所有主流子系统都会基于原生的通知链,封装出一套属于自己子系统的专用接口。