linux notification chains

linux内核由各个不同的子系统构成,比如网络子系统、存储管理子系统等,当然这种设计是为了使内核便于组织,有点类似于 ISO/OSI参考模型。各个子系统相对独立,但它们之间又存在联系。本问将谈谈内核中,各个子系统之间为了实现信息共享而提供的一种机制 ──notification chain。
从字面解释,它是条链表,而且它要完成通知这项工作。如何通知?靠的是在通知链中的回调例程(callback routine);通知什么?通知某个子系统中某个事件的发生;发送通知的是谁?当然是事件发生的子系统;通知何人?对该事件关注的其它子系统。下面就对 这些问题做进一步展开。

 

一、 因为它是链表,固然节点元素少不了。节点的数据结构如下(在 include/linux/notifier.h中定义):

 2008-12-10-184607_417x103_scrot.png

notifier_call例程,当某个事件发生时它被调用,所完成的工作由关注该事件的子系统负责;
struct notifier_block *next,当然用意很明了了,链表的下一节点指针;
int priority,该节点的优先级,因为链表是按优先级来排序,故当某个事件发生时,也是按优先级顺序来执行所有关注该事件的例程。不过该值一般都为默认值0,因此执行也就根据节点加入链表的先后顺序了。

二、 内核通过notifier_block中提供的统一接口函数 notifier_call来实现对该事件的所应该做出的动作。
参数 struct notifier_block *,指向通知链,这样被通知者便知道是什么事件发出的通知;unsigned long 明确定义了事件的类型,如:NETDEV_REGISTER则表示有新的网络设备注册了;void * 被定义为该类型的指针,用途一般都比较广泛(可以认为是自由量,个人是这么认为的),所以得根据不同的环境来定位如何使用该指针,比如网卡注册事件,则该 指针便可以指向net_device数据结构。看来一个回掉例程就把:如何通知、通知什么、谁发送的通知都给解决了。

三、 通知何人、何人去通知(什么人提供通知这一服务)通知链并不是链表持有子系统主动提供的服务,换句话说,你要我通知你一些事情,你得事先跟我讲要通知你什 么事情、怎么才能够正确的通知到你。为此每个子系统可能会定义一条或若干条通知链,通常以:xxx_chain、xxx_notifier_chain、 xxx_notifier_list为命名方式。举个例子,在网络子系统中通知链是这么定义的:inetaddr_chain、netdev_chain 等,当然它们只是一个名字而已,不过从编码规范的角度,这些规则应该是必须遵守的,要不然哪来如此强大的系统!

在通知链使用之前我们得先在内核里注册它,告诉内核你的存在,这样才会被关注,别人才能够找到你。
在解释如何注册一条通知链代码之前,了解另外一个数据结构──链表头节点。

2008-12-10-184625_387x107_scrot.png
(注:通知链表头还有另外三种,它们分别提供不同的保证数据修改完整性的机制,具体见:include/linux/notifier.h)
注册一条通知链:
代码比较容易懂,一部分用于处理操作的完整性问题,比如读写信号量,另外一部分(notifier_chain_register),就是对单向链表做查找和插入操作。

 2008-12-10-184657_469x625_scrot.png

做完上面的工作后,一条通知链就被创建了,也就是实现了通知事件服务的提供者,接下来如果有其它人对该服务感兴趣的话,那么他就得先订阅该服务,这 样以后,只要该事件一发生,订阅该服务的人就会收到他们所订阅的信息。订阅应该是一件较为容易的事,通过notifier_chain_register 就能够简单的做到,但在你做这事之前还有一件更重要的事要你亲自去完成,那便是你收到消息后应该如何做出反应(也就是notifier_call函数的实 现,及其对notifier_block中成员的初始化)。

最后,只要某个事件一发生,订阅该事件的其它子系统就能够收到该事件,并且做出相应的处理(按照优先权顺序,遍历整个通知链链表,指向每个节点中的回调例程)。

总结:通知链是在内核空间中为共享各子系统中的信息而提供的一种机制,因为它一般在系统启动,或者模块加载/卸载的时候初始化/添加的,所以在设计它之前,想必内核开发者已经充分考虑了它的性能指标。

你可能感兴趣的:(linux,notification)