一、linux通知链介绍
内核的很多子系统(例如:进程调度、内存管理、虚拟文件系统、路由子系统等)之间具有很强的相互依赖性,因此,其中一个子系统侦测到的或者产生的事件,其他子系统可能都有兴趣,为了完成这种交互需求,linux使用了所谓的通知链(notification chain)
通知链表是一个函数链表,链表上的每一个节点都注册了一个函数。当某个事情发生时,链表上所有节点对应的函数就会被执行。所以对于通知链表来说有一个通知方与一个接收方。在通知这个事件时所运行的函数由被通知方决定,实际上也即是被通知方注册了某个函数,在发生某个事件时这些函数就得到执行。其实和系统调用signal的思想差不多。
注意:通知链只在内核子系统之间使用,内核和用户空间之间的通知信息则是依赖其他机制,例如ioctl。
二、linux内核通知链的基本数据结构
通知链列表元素的类型是notifier_block,其定义如下:
struct notifier_block {
int (*notifier_call)(struct notifier_block *, unsigned long, void *);
struct notifier_block __rcu *next;
int priority;
};
Notifier_call是要执行的函数,next用于链接列表的元素,而priority代表的是该函数的优先级,较高优先级的函数会先被执行,但是在实际中,注册时几乎都不理会notifier_block定义中的priority,意味着获取其默认值0,因此,执行的次序仅依赖于注册次序。
通知链有四种类型:
1、 原子通知链( Atomicnotifier chains ):通知链元素的回调函数(当事件发生时要执行的函数)只能在中断上下文中运行,不允许阻塞。对应的链表头结构:
structatomic_notifier_head
{
spinlock_t lock;
struct notifier_block *head;
};
2、 可阻塞通知链(Blocking notifier chains ):通知链元素的回调函数在进程上下文中运行,允许阻塞。对应的链表头:
structblocking_notifier_head
{
struct rw_semaphore rwsem;
struct notifier_block *head;
};
3、 原始通知链( Rawnotifier chains ):对通知链元素的回调函数没有任何限制,所有锁和保护机制都由调用者维护。对应的链表头:
structraw_notifier_head
{
struct notifier_block *head