前言
上篇讲了netlink
机制是用户层和内核层之间通信机制。Linux内核基础 | netlink的使用
本篇讲下Linux内核中常见notifier
机制的使用,notifier
机制是一种用于实现事件通知的机制,允许不同的内核子系统之间进行解耦的通信。
本篇环境
硬件平台:飞凌OK3588开发板
内核源码:5.10.66-rt53
编译环境:Ubuntu 20.04 LTS
编译工具链:aarch64-linux-gnu-
notifier机制引入
大家知道内核子系统都是相互独立的模块,因此如果某个子系统可能对其他子系统产生的事件感兴趣,怎么办。Linux内核为了解决这个问题,Linux内核提供了notifier
(通知链)机制的机制,notifier
只能在内核子系统之间使用,而不能在内核与用户之间进行事件的通知。可以考虑有这么一个场景:对于网卡驱动子系统来说,经常会发生的情况是什么?网卡IP有变化,网卡状态有变化等待。那么如果有其他子系统,比如路由子系统对网卡IP地址有变化,网卡状态有变化等等,它该怎么感知这件事?
很多人第一直觉就是"订阅者-发布者"模型。不过确实是这样的,通知链机制可以算是"订阅者-发布者"的一种,每个子系统都有些这样的机制,比如网卡驱动子系统网卡的事件,或者USB的状态事件或者系统suspend给其他各个子系统进行suspend。这些子系统都会提供一个自己的事件链表,这个链表都是其他函数提供的回调函数。当有事件发生时,子系统就会去遍历其事件链表上已经注册了的所有回调函数,这样就实现了“通知”的目的
内核实现的notifier机制代码位于kernel/kernel/notifier.c
notifier的数据结构
Linux内核提供了四类通知链:原子通知链、可阻塞通知链、原始通知链和SRCU
通知链,它们的主要区别就是在执行通知链上的回调函数时是否有安全保护措施。下面我们分别看一下这四类通知链:
原子通知链
原子通知链的链表头定义如下:
struct atomic_notifier_head {
spinlock_t lock;
struct notifier_block __rcu *head;
};
我们看到原子通知链采用的是自旋锁,通知链元素的回调函数只能在中断/原子上下文中运行,而且不允许阻塞
可阻塞通知链
可阻塞的通知链的链表头定义如下
struct blocking_notifier_head {
struct rw_semaphore rwsem;
struct notifier_block __rcu *head;
};
我们看到可阻塞通知链采用的是用信号量,通知链元素的回调函数只能进程上下文环境中
原始通知链
原始通知链的链表头定义如下:
struct raw_notifier_head {
struct notifier_bloc