当前位置:首页>Linux>linux 内核通知链函数解读

linux 内核通知链函数解读

  • 2026-10-14 09:03:02
linux 内核通知链函数解读
大家好,我是王鸽,今天这篇文章主要是讲内核通知链函数的解读。其实阅读内核代码的时候,发现Linux内核有很多通用的函数,比如屏这块的控制。

还有之前的insmod加载方式,kernel\module.c

从以上例子知道,核心函数是

staticint __kprobes notifier_call_chain(struct notifier_block **nl,  unsignedlong val, void *v, int nr_to_call,int *nr_calls)
其他的模块接口不过是对它换个名字封装一下而已。

参数说明

参数

类型

说明

nl

struct notifier_block **

指向通知链头部的指针(链表头)

val

unsigned long

事件类型标识符(如 NETDEV_UP、CPU_DOWN_PREPARE 等)

v

void *

传递给回调函数的上下文数据(通常为事件相关的数据结构指针)

返回值

返回值

说明

NOTIFY_DONE

所有回调处理完毕,未中断链式调用

NOTIFY_STOP

某个回调要求停止链式调用(例如返回 NOTIFY_STOP_MASK 掩码后的值)

NOTIFY_BAD

某个回调返回错误,链式调用被终止

在 Linux 内核中,notifier_call_chain()是一个用于触发通知链(Notifier Chain)的核心函数。它属于内核的事件通知机制,允许不同子系统注册回调函数,在特定事件(如系统关机、CPU 热插拔、内存压力等)发生时被调用。

一.核心机制

1. 通知链(Notifier Chain)

通知链是 Linux 内核中一种订阅-发布模式的实现:

发布者(Notifier Caller):通过notifier_call_chain()触发事件。

订阅者(Notifier Block):通过notifier_chain_register()注册回调函数到链中。

2. 数据结构

struct notifier_block {     int (*notifier_call)(struct notifier_block *, unsigned long, void *);  struct notifier_block *next;     int priority; // 回调优先级(数值越小优先级越高) };

notifier_call:指向回调函数的指针。

next:链表指针,指向下一个节点。

priority:优先级,值越小优先级越高(或越大,取决于实现)。

二. 通知链类型

根据使用场景和同步机制,通知链分为四类:

原子通知链(Atomic Notifier Chains):

使用自旋锁保护链表,回调函数在原子上下文(如中断)中执行,不可休眠。
定义:struct atomic_notifier_head。

可阻塞通知链(Blocking Notifier Chains):

使用互斥锁,回调函数在进程上下文中执行,允许休眠。
定义:struct blocking_notifier_head。

原始通知链(Raw Notifier Chains):

无锁保护,调用者需自行处理并发。
定义:struct raw_notifier_head。

SRCU 通知链(SRCU Notifier Chains):

使用 Sleepable RCU 机制,适用于回调函数可能长时间阻塞的场景。
定义:struct srcu_notifier_head。

三. 关键操作

注册与注销

注册:将 notifier_block 插入链表中,按优先级排序。

intnotifier_chain_register(struct notifier_block **nl, struct notifier_block *n);
注销:从链表中移除指定notifier_block。
intnotifier_chain_unregister(struct notifier_block **nl, struct notifier_block *n);

事件通知

触发通知:遍历链表,依次调用回调函数。

intnotifier_call_chain(struct notifier_block **nl, unsignedlong val, void *v);

val:事件类型(如NETDEV_REGISTER)。

v:事件相关数据(如网络设备指针)。

回调函数返回值

回调函数返回以下状态码,影响后续处理:

NOTIFY_DONE:事件未处理,继续传递。

NOTIFY_OK:事件已处理,继续传递。

NOTIFY_STOP:事件处理完成,停止传递。

NOTIFY_BAD:事件错误,停止传递。

同步机制

原子通知链:通过自旋锁(spinlock_t)保护链表操作,确保原子性。

可阻塞通知链:使用互斥锁(struct mutex),允许休眠。

SRCU 通知链:利用 SRCU 的读-复制-更新机制,延迟释放资源以避免竞争。

典型应用场景

网络设备事件:如网卡注册(NETDEV_REGISTER)、状态变更(NETDEV_UP)。

// 注册网络设备通知链 static struct notifier_block netdev_notifier = {    .notifier_call = netdev_event,        .priority = 0, }; register_netdevice_notifier(&netdev_notifier);

典型应用例子

设备热插拔:通知驱动某个设备被插入或拔出。

网络状态变化:如网卡注册 (NETDEV_REGISTER)、IP地址变更。

电源管理:系统休眠/唤醒事件通知。

文件系统事件:如挂载/卸载文件系统。

内核中的具体实现

网络子系统:netdevice_notifier_chain 用于网络设备事件。

CPU热插拔:cpu_chain 通知 CPU 状态变化。

时钟事件:tick_notifier_list 处理时钟中断事件。

实现示例

注册一个 CPU 热插拔事件回调的例子

性能与注意事项

回调函数应短小:避免在原子上下文中长时间运行。

避免嵌套锁:防止死锁,尤其在可阻塞链中。

优先级(Priority)

通过priority字段控制回调的执行顺序。高优先级(数值小)的回调先执行。

返回值处理

返回NOTIFY_STOP会终止链式调用(例如内核的die_chain在遇到panic()时终止)。返回NOTIFY_BAD表示严重错误(如内存分配失败)。

并发与锁

注册/注销操作需在安全上下文中进行(如模块初始化/退出时)。回调函数需考虑重入性和锁竞争(如避免阻塞操作)。

内核通知链类型

原子通知链(Atomic Notifier Chain):回调在原子上下文执行(不可睡眠)。

阻塞通知链(Blocking Notifier Chain):回调在进程上下文执行(可睡眠)。

原始通知链(Raw Notifier Chain):无锁保护,需自行处理并发。

通过上述机制,Linux内核实现了高效、灵活的事件通知系统,确保各模块在松散耦合的前提下协同工作。

最新文章

随机文章