日期:2014-05-16 浏览次数:20929 次
一.头文件
#include <linux/notifier.h>
二.结构体
//通知块
struct notifier_block {
int (*notifier_call)(struct notifier_block *, unsigned long, void *); //回调函数
struct notifier_block __rcu *next; //指向通知链表的下一项
int priority; //优先级
};
//原子通知链 运行在中断上下文,不允许阻塞
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_block __rcu *head;
};
//SRCU通知链 阻塞通知链的变体
struct srcu_notifier_head {
struct mutex mutex;
struct srcu_struct srcu;
struct notifier_block __rcu *head;
};
三.通知链头初始化
调用定义好的宏初始化通知链表头
#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)
定义通知链表头结构体,然后初始化赋值
#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 }
SRCU通知链不支持静态调用
四.注册注销通知块
1.注册通知块
int atomic_notifier_chain_register(struct atomic_notifier_head *nh,struct notifier_block *nb); int blocking_notifier_chain_register(struct blocking_notifier_head *nh,struct notifier_block *nb); int raw_notifier_chain_register(struct raw_notifier_head *nh,struct notifier_block *nb); int srcu_notifier_chain_register(struct srcu_notifier_head *nh,struct notifier_block *nb); int blocking_notifier_chain_cond_register(struct blocking_notifier_head *nh,struct notifier_block *nb);
最终调用notifier_chain_register
static int notifier_chain_register(struct notifier_block **nl,struct notifier_block *n)
{
while ((*nl) != NULL) { //若链表项非空
if (n->priority > (*nl)->priority)
break;
nl = &((*nl)->next); //则nl指向其下一链表项
}
n->next = *nl; //将通知链表项添加进通知链表
rcu_assign_pointer(*nl, n);
return 0;
}
2.注销通知块
int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh,struct notifier_block *n) int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh,struct notifier_block *n) int raw_notifier_chain_unregister(struct raw_notifier_head *nh,struct notifier_block *n) int srcu_notifier_chain_unregister(struct srcu_notifier_head *nh,struct notifier_block *n)
最终调用
static int notifier_chain_unregister(struct notifier_block **nl,struct notifier_block *n)
{
while ((*nl) != NULL) {
if ((*nl) == n) {
rcu_assign_pointer(*nl, n->next);
return 0;
}
nl = &((*nl)->next); //从通知链表中移除通知块
}
return -ENOENT;
}
五.通知通知链
int __kprobes 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)
最终会调用
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