当有事件发生时,通知者调用 notifier_call_chain
函数通知事件的到达,这个函数会遍历n1指向的通知链中所有的元素,然后依次调用每一个的回调函数,完成通知动作。
static int __kprobes notifier_call_chain(struct notifier_block
**nl,
unsigned long val, void *v,
int nr_to_call,
int *nr_calls)
{
int ret = NOTIFY_DONE;
struct notifier_block *nb, *next_nb;
nb = rcu_dereference_raw(*nl);
while (nb && nr_to_call) {
next_nb = rcu_dereference_raw(nb->next);
#ifdef CONFIG_DEBUG_NOTIFIERS
if
(unlikely(!func_ptr_is_kernel_text(nb->notifier_call)))
{
WARN(1, "Invalid notifier called!");
nb = next_nb;
continue;
}
#endif
ret = nb->notifier_call(nb, val, v);
if (nr_calls)
(*nr_calls)++;
if ((ret & NOTIFY_STOP_MASK) ==
NOTIFY_STOP_MASK)
break;
nb = next_nb;
nr_to_call--;
}
return ret;
}
在kernel/notifier.c中内核根据通知链的类型分别包装了上面这个函数:
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)
5.通知链四种类型
(5.1)原子通知链的链头:
通知链元素的回调函数(当事件发生时要执行的函数)只能在中断上下文中运行,不允许阻塞。
struct atomic_notifier_head {
spinlock_t lock;
struct notifier_block *head;
};
(5.2)可阻塞通知链:
通知链元素的回调函数在进程上下文中运行,允许阻塞。
struct blocking_notifier_head {
struct rw_semaphore rwsem;
struct notifier_block *head;
};
(5.3)原始通知链:
对通知链元素的回调函数没有任何限制,所有锁和保护机制都由调用者维护。
struct raw_notifier_head {
struct notifier_block *head;
};
(5.4)SRCU 通知链:
可阻塞通知链的变种。
struct srcu_notifier_head {
struct mutex mutex;
struct srcu_struct srcu;
struct notifier_block *head;
};
(6)定义一个通知链的头部结点并初始化:
在include/linux/Notifier.h中
初始化宏定义:
#define ATOMIC_NOTIFIER_INIT(name) {
\
.lock = __SPIN_LOCK_UNLOCKED(name.lock),
\
.head = NULL }
#define BLOCKING_NOTIFIER_INIT(name) {
\
.rwsem = __RWSEM_INITIALIZER((name).rwsem),
\
.head = NULL }
#define RAW_NOTIFIER_INIT(name)
{
\
.head = NULL }
定义通知链:
#define ATOMIC_NOTIFIER_HEAD(name)
\
struct atomic_notifier_head name =
\
ATOMIC_NOTIFIER_INIT(name)
#define BLOCKING_NOTIFIER_HEAD(name)
\
struct blocking_notifier_head name =
\
BLOCKING_NOTIFIER_INIT(name)
#define RAW_NOTIFIER_HEAD(name)
\
struct raw_notifier_head name =
\
RAW_NOTIFIER_INIT(name)
转自:http://blog.csdn.net/xiyu_1986/article/details/6641378