日期:2014-05-16  浏览次数:20708 次

linux通知链相关

一.头文件

#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