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_NOTIFIERSif (unlikely(!func_ptr_is_kernel_text(nb->notifier_call))) {WARN(1, "Invalid notifier called!");nb = next_nb;continue;}#endifret = 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);
通知链回调函数
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;}