当前位置:首页>Linux>Linux通知链

Linux通知链

  • 2026-10-11 06:29:58
Linux通知链

Linux驱动入门课程:

https://www.bilibili.com/cheese/play/ss635583370

Linux驱动进阶课程:

https://www.bilibili.com/cheese/play/ss254727759

01

什么是通知链

Linux 中的 Notifier(通知链,Notifier Chain) 是内核中一种非常常见的事件发布/订阅机制。它允许一个模块在某个事件发生时,通知多个对此事件感兴趣的模块,而不需要彼此直接依赖。有点类似于MQTT协议。

02

工作原理

通知链的核心思想是:“等事情发生了,我再通知你”

  • 定义通知链:内核某个子系统定义一个链表头(Chain Head)。

  • 注册(订阅):其他对该事件感兴趣的模块,调用注册函数将自己的回调函数(Callback)挂到这个链表上。

  • 通知(发布):当该子系统触发了特定事件,它会遍历这个链表,依次执行所有注册的回调函数。

03

通知链类型

Linux 内核根据运行环境和锁的需求,提供了四种不同类型的通知链:

点击放大

04

重要结构体

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:主动要求中止后续的通知(不需要继续往下传了)。

05

API函数

//定义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);

06

总结

由于传统的 notifier_block 结构体和底层注册函数比较通用、抽象,如果每个子系统都直接去调用它们,代码会显得非常臃肿且容易出错。为了简化开发、提高代码可读性并隐藏实现细节,内核中几乎所有主流子系统都会基于原生的通知链,封装出一套属于自己子系统的专用接口。

END
往期推荐:

驱动之间如何共享寄存器?Syscon 给出了答案

延迟函数别乱用,Linux 内核开发者必须掌握的延迟“潜规则”

Linux驱动之SPI子系统

一文搞懂SPI总线协议

别再手写寄存器读写了!试试Regmap吧

最新文章

随机文章