您的位置:首页 > 运维架构 > Linux

linux通知链相关

2013-10-30 15:54 357 查看
一.头文件

[cpp]
view plaincopyprint?

#include <linux/notifier.h>

二.结构体

[cpp]
view plaincopyprint?

//通知块
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;
};

三.通知链头初始化

调用定义好的宏初始化通知链表头

[cpp]
view plaincopyprint?

#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_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)

定义通知链表头结构体,然后初始化赋值

SRCU通知链不支持静态调用

四.注册注销通知块

1.注册通知块

[cpp]
view plaincopyprint?

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

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

[cpp]
view plaincopyprint?

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.注销通知块

[cpp]
view plaincopyprint?

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)

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)

最终调用

[cpp]
view plaincopyprint?

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

五.通知通知链

[cpp]
view plaincopyprint?

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)

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)

最终会调用

[cpp]
view plaincopyprint?

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); //调用通知块的notifier_call函数


if (nr_calls)
(*nr_calls)++;

if ((ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK)
break;
nb = next_nb; //指向下一通知块

nr_to_call--;
}
return ret;
}

六.运用

发送通知者:定义通知块及回调函数,注册通知块

接收通知者:,通知通知链

在drivers/usb/core/usb.c中

定义了通识块及其回调函数

static struct notifier_block usb_bus_nb = {

.notifier_call = usb_bus_notify,

};

在drivers/usb/core/usb.c中usb_init函数中

注册了总线通知链

retval = bus_register_notifier(&usb_bus_type, &usb_bus_nb);

总线通知链中注册了阻塞通知链

int bus_register_notifier(struct bus_type *bus, struct notifier_block *nb)

{

return blocking_notifier_chain_register(&bus->p->bus_notifier, nb);

}

通知者

1.有设备添加

device_register

device_add



if (dev->bus)

blocking_notifier_call_chain(&dev->bus->p->bus_notifier,BUS_NOTIFY_ADD_DEVICE, dev);

2.有设备移除

device_unregister

device_del



if (dev->bus)

blocking_notifier_call_chain(&dev->bus->p->bus_notifier,BUS_NOTIFY_DEL_DEVICE, dev);

通知链回调函数

[cpp]
view plaincopyprint?

static int usb_bus_notify(struct notifier_block *nb, unsigned long action,void *data)
{
struct device *dev = data;
//回调函数根据传递进来的参数获得设备文件及行为标识,对设备添加和移除做分别处理

switch (action) {
case BUS_NOTIFY_ADD_DEVICE:
if (dev->type == &usb_device_type)
(void) usb_create_sysfs_dev_files(to_usb_device(dev));
else if (dev->type == &usb_if_device_type)
(void) usb_create_sysfs_intf_files(to_usb_interface(dev));
break;

case BUS_NOTIFY_DEL_DEVICE:
if (dev->type == &usb_device_type)
usb_remove_sysfs_dev_files(to_usb_device(dev));
else if (dev->type == &usb_if_device_type)
usb_remove_sysfs_intf_files(to_usb_interface(dev));
break;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: