notifier通知链机制

1. 目的

Linux内核中各个子系统相互依赖,当其中某个子系统状态发生改变时,就必须使用一定的机制告知使用其服务的其他子系统,以便其他子系统采取相应的措施。为满足这样的需求,内核实现了事件通知链机制(notificationchain)。

2. 范围

通知链只能用在各个子系统之间,而不能在内核和用户空间进行事件的通知。

3. 代码位置

组成内核的核心系统代码均位于kernel目录下,通知链表位于kernel/notifier.c中,对应的头文件为include/linux/notifier.h。

4. 被通知数据结构

notifier_block是通知链中的主要结构:

struct notifier_block {
    int (*notifier_call)(struct notifier_block *, unsigned long, void *);
    struct notifier_block *next;
    int priority;
};

其中,
a. notifier_call:当相应事件发生时应该调用的函数,由被通知方提供;
b. notifier_block *next:用于链接成链表的指针;
c. priority:回调函数的优先级,一般默认为0;

5. 通知链数据结构

围绕核心数据结构notifier_block,内核定义了四种通知链类型:
a. 原子通知链( Atomic notifier chains ):通知链元素的回调函数(当事件发生时要执行的函数)在中断或原子操作上下文中运行,不允许阻塞。对应的链表头结构:

struct atomic_notifier_head {
    spinlock_t  lock;
    struct  notifier_block *head;
};

b. 可阻塞通知链( Blocking notifier chains ):通知链元素的回调函数在进程上下文中运行,允许阻塞。对应的链表头:

struct  blocking_notifier_head {
    struct  rw_semaphore  rwsem;
    struct  notifier_block   *head;
};

c. 原始通知链( Raw notifierchains ):对通知链元素的回调函数没有任何限制,所有锁和保护机制都由调用者维护。对应的链表头:

struct  raw_notifier_head {
    struct  notifier_block   *head;
};

d. SRCU 通知链( SRCU notifier chains ):可阻塞通知链的一种变体。对应的链表头:

struct  srcu_notifier_head {
    struct  mutex mutex;
    struct  srcu_struct  srcu;
    struct  notifier_block  *head;
};

6. 使用过程

a. 通知方先初始化一个通知链;
b. 被通知方申明一个notifier_block;
c. 被通知方实现notifier_call函数;
d. 被通知方调用特定的事件通知链的注册函数,将notifier_block注册到通知方的通知链中。特定的注册函数包括:

int atomic_notifier_chain_register(struct atomic_notifier_head *nh, struct notifier_block *n)
int blocking_notifier_chain_register(struct blocking_notifier_head *nh, struct notifier_block *n)
int raw_notifier_chain_register(struct raw_notifier_head *nh, struct notifier_block *n)
int srcu_notifier_chain_register(struct srcu_notifier_head *nh, struct notifier_block *n)

e. 当通知方状态变化时,调用对应的notifier_call_chain函数通知其他子系统,对应的notifier_call_chain包括:

int atomic_notifier_call_chain(struct atomic_notifier_head *nh, unsigned long val, void *v)
int blocking_notifier_call_chain(struct blocking_notifier_head *nh, unsigned long val, void *v)
int raw_notifier_call_chain(struct raw_notifier_head *nh, unsigned long val, void *v)
int srcu_notifier_call_chain(struct srcu_notifier_head *nh, unsigned long val, void *v)

f. 被通知方执行notifier_block函数;

7. 关于notifier_block函数的返回值

notifier_block的返回值是NOTIFY_XXX的形式,在include/linux/notifier.h中:

#define NOTIFY_DONE 0x0000 /* 对事件视而不见 */
#define NOTIFY_OK 0x0001 /* 事件正确处理 */
#define NOTIFY_STOP_MASK 0x8000 /*由notifier_call_chain检查,看继续调用回调函数,还是停止,_BAD和_STOP中包含该标志 */
#define NOTIFY_BAD (NOTIFY_STOP_MASK|0x0002) /*事件处理出错,不再继续调用回调函数 */
/*
 *Clean way to return from the notifier and stop further calls.
 */
#define NOTIFY_STOP (NOTIFY_OK|NOTIFY_STOP_MASK) /*  回调出错,不再继续调用该事件回调函数 */

你可能感兴趣的:(Linux驱动开发)