Linux内核的通知链机制

原创 2012年03月31日 13:30:26

    内核源码:linux-2.6.38.8.tar.bz2

 

    在Linux内核中,通知链是一种非常好的异步通信机制,它的实现也非常简单,就是通过某个单循环链表来实现。

    1、通知链实例都使用notifier_block结构体来表示 

/* linux-2.6.38.8/include/linux/notifier.h */
struct notifier_block {
	int (*notifier_call)(struct notifier_block *, unsigned long, void *);//处理函数
	struct notifier_block __rcu *next; //用于构建单循环链表
	int priority; //为本链表中的通知链实例设定优先级,高优先级的处理函数将优先被执行
};

    2、在当前的Linux内核中有四种类型的通知链链表表头(增加了某种锁机制而已) 

/* linux-2.6.38.8/include/linux/notifier.h */
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;
};

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

    静态地创建链表表头(所谓静态地创建就是定义一个相应的结构体变量,而动态地创建是使用指向结构体变量的指针),srcu_notifier_head类型的表头不支持静态地创建。 

/* linux-2.6.38.8/include/linux/notifier.h */
#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 }

    3、注册和注销(实际上就是向相应的链表中插入或删除通知链实例) 

/* linux-2.6.38.8/include/linux/notifier.h */
extern int atomic_notifier_chain_register(struct atomic_notifier_head *nh,
		struct notifier_block *nb);
extern int blocking_notifier_chain_register(struct blocking_notifier_head *nh,
		struct notifier_block *nb);
extern int raw_notifier_chain_register(struct raw_notifier_head *nh,
		struct notifier_block *nb);
extern int srcu_notifier_chain_register(struct srcu_notifier_head *nh,
		struct notifier_block *nb);

extern int blocking_notifier_chain_cond_register(
		struct blocking_notifier_head *nh,
		struct notifier_block *nb);

extern int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh,
		struct notifier_block *nb);
extern int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh,
		struct notifier_block *nb);
extern int raw_notifier_chain_unregister(struct raw_notifier_head *nh,
		struct notifier_block *nb);
extern int srcu_notifier_chain_unregister(struct srcu_notifier_head *nh,
		struct notifier_block *nb);

    它们最后都会调用notifier_chain_register、notifier_chain_cond_register(只被blocking_notifier_chain_cond_register函数所使用)或notifier_chain_unregister函数。 

/* linux-2.6.38.8/kernel/notifier.c */
static int notifier_chain_register(struct notifier_block **nl,
		struct notifier_block *n)
{
	while ((*nl) != NULL) { //检查链表是否不为空。
		if (n->priority > (*nl)->priority) //检查将要插入的通知链实例的priority是否大于找到的链表元素的priority值,priority值最大的被插入到表头后面
			break;
		nl = &((*nl)->next); //指向链表的下一个元素
	}
	n->next = *nl;
	rcu_assign_pointer(*nl, n); //*nl指向n
	return 0;
}

static int notifier_chain_cond_register(struct notifier_block **nl,
		struct notifier_block *n)
{
	while ((*nl) != NULL) {
		if ((*nl) == n)  //检查被插入的通知链实例是否已经存在,避免重复插入
			return 0;
		if (n->priority > (*nl)->priority)
			break;
		nl = &((*nl)->next);
	}
	n->next = *nl;
	rcu_assign_pointer(*nl, n);
	return 0;
}

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;
}

/* linux-2.6.38.8/include/linux/rcupdate.h */
#define rcu_assign_pointer(p, v) \
	__rcu_assign_pointer((p), (v), __rcu)

#define __rcu_assign_pointer(p, v, space) \
	({ \
		if (!__builtin_constant_p(v) || \
		    ((v) != NULL)) \
			smp_wmb(); \
		(p) = (typeof(*v) __force space *)(v); \
	})

    4、触发相应的处理函数 (即使用链表中的通知链实例)

/* linux-2.6.38.8/include/linux/notifier.h */
extern int atomic_notifier_call_chain(struct atomic_notifier_head *nh,
		unsigned long val, void *v);
extern int __atomic_notifier_call_chain(struct atomic_notifier_head *nh,
	unsigned long val, void *v, int nr_to_call, int *nr_calls);
extern int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
		unsigned long val, void *v);
extern int __blocking_notifier_call_chain(struct blocking_notifier_head *nh,
	unsigned long val, void *v, int nr_to_call, int *nr_calls);
extern int raw_notifier_call_chain(struct raw_notifier_head *nh,
		unsigned long val, void *v);
extern int __raw_notifier_call_chain(struct raw_notifier_head *nh,
	unsigned long val, void *v, int nr_to_call, int *nr_calls);
extern int srcu_notifier_call_chain(struct srcu_notifier_head *nh,
		unsigned long val, void *v);
extern int __srcu_notifier_call_chain(struct srcu_notifier_head *nh,
	unsigned long val, void *v, int nr_to_call, int *nr_calls);

    它们最后都会调用notifier_call_chain函数。 

/* linux-2.6.38.8/kernel/notifier.c */
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) {  //根据需要,会调用链表中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;
}

 

Linux内核基础--事件通知链(notifier chain)

内核通知链 1.1. 概述        Linux内核中各个子系统相互依赖,当其中某个子系统状态发生改变时,就必须使用一定的机制告知使用其服务的其他子系统,以便其他子系统采取相应的措施。为满足这...

notifier_block的使用

/* * 本例用于捕捉panic事件*/#include #include #include static int my_panic_event(struct notifier_block *this...
  • zomeasm
  • zomeasm
  • 2010年12月15日 22:05
  • 1003

linux notifier机制及应用

linux庞大系统中,各个模块是相对独立的,那么模块间通信该如何做呢?当然你也可以使用全局资源,如果这样的话系统缺少独立性,会带来稳定性问题的。如果你说,使用共享内存,进程通信等,那么你曲解我的意思了...

Linux 下的notifier chain 机制的注册和触发讲解

Linux 下的notifier chain 机制的注册和触发讲解  notifier_chain_register 本文以tegra jack 为例。讲解了notifier_cain   1...

Notifier chain 全面分析

原文:http://haohetao.iteye.com/blog/1147833 Notifier是Linux中提供一种在内核子系统中共享事件信息的方法。 基于版本2.6.22,notifi...

Linux内核通知链(Notifier)

引入 在linux内核中,各个子系统之间有很强的相互关系,某些子系统可能对其他子系统产生的事件比较感兴趣。因此内核引入了notifier机制,当然了notifier机制只能用在内核子系统之间,不能用...

一个驱动支持多个设备再usb子系统、input子系统、platform、iic子系统 中的实现

/** 先看平台总线。 */ ![这里写图片描述](http://img.blog.csdn.net/20160201221542781) struct bus_type platform_b...

Android Notification 使用详解之一:基础应用

前言          欢迎大家我分享和推荐好用的代码段~~ 声明          欢迎转载,但请保留文章原始出处:          CSDN:http://www.csdn.net       ...
  • luckkof
  • luckkof
  • 2013年06月03日 15:24
  • 960

linux内核的通知链机制

一、为什么需要通知链:    linux内核的各个子系统之间往往互相关联,一个子系统产生或者侦测到的事件,其它的子系统往往也很感兴趣,因此linux内核采用了通知链机制实现内核的子系统之间的通信需求...

Linux内核通知链机制的原理及实现

一、概念:    大多数内核子系统都是相互独立的,因此某个子系统可能对其它子系统产生的事件感兴趣。为了满足这个需求,也即是让某个子系统在发生某个事件时通知其它的子系统,Linux内核提供了通知链的机制...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Linux内核的通知链机制
举报原因:
原因补充:

(最多只允许输入30个字)