作用: 内核子系统是相互独立的; 某个子系统可能对其他子系统产生的事件感兴趣;为了满足此需求, 也即让某个子系统在发生某个事件时通知其他子系统, linux提供了通知链机制; 它只能在内核子系统间使用, 不能在内核和用户空间进行时间的通知; 和系统调用signal的思想差不多;
源码:
include/linux/notifier.h //头文件;
kernel/notifier.c
关键结构体:
//include/linux/notifier.h
typedef int (*notifier_fn_t)(struct notifier_block *nb,
unsigned long action, void *data);
struct notifier_block {
notifier_fn_t notifier_call; //收到通知后, 要执行的函数;
struct notifier_block __rcu *next; //链表;
int priority;
};
struct blocking_notifier_head {
struct rw_semaphore rwsem;
struct notifier_block __rcu *head;
};
链表头;
创建通知链:
手动定义’struct notifier_block’里面的回调函数, 没有显示定义的辅助函数;
添加到通知链上来:
blocking_notifier_chain_register(struct blocking_notifier_head *nh, struct notifier_block *n)
notifier_chain_register(&nh->head, n)
notifier_chain_register(struct notifier_block **nl, struct notifier_block *n)
while ((*nl) != NULL) {
if (n->priority > (*nl)->priority)
break;
nl = &((*nl)->next);
}
n->next = *nl;
rcu_assign_pointer(*nl, n) //include/linux/rcupdate.h
这里用到了rcu, rcu_assign_pointer(p, v)函数的作用, 简单的理解就是: p = v;
遍历通知链, 并回调上面的注册函数:
notifier_call_chain(struct notifier_block **nl, unsigned long val, void *v,
int nr_to_call, int *nr_calls) //kernel/notifer.c
struct notifier_block *nb, *next_nb;
nb = rcu_dereference_raw(*nl)
while (nb && nr_to_call)
next_nb = rcu_dereference_raw(nb->next)
nb->notifier_call(nb, val, v)
nb = next_nb
参数val 和 v, 是传递给回调函数的;
执行blocking通知链表:
blocking_notifier_call_chain(struct blocking_notifier_head *nh, unsigned long val, void *v) //kernel/notifer.c
__blocking_notifier_call_chain(nh, val, v, -1, NULL)
notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls)
fb_notifier_call_chain(unsigned long val, void *v) //drivers/video/fb_notify.c
blocking_notifier_call_chain(&fb_notifier_list, val, v)
测试例子
//notify_server_test.c
#include <linux/module.h>
#include <linux/notifier.h>
//定义通知链表头:
BLOCKING_NOTIFIER_HEAD(notifier_server_list);
EXPORT_SYMBOL(notifier_server_list);
static int __init notify_server_test_init(void)
{
printk("--->%s\n", __func__);
//执行通知链:
blocking_notifier_call_chain(¬ifier_server_list, 15, "it is me");
return 0;
}
static void __exit notify_server_test_exit(void)
{
printk("--->%s\n", __func__);
}
module_init(notify_server_test_init);
module_exit(notify_server_test_exit);
MODULE_DESCRIPTION("notify server test");
MODULE_LICENSE("GPL");
notify_client_test.c
#include <linux/module.h>
#include <linux/notifier.h>
extern struct blocking_notifier_head notifier_server_list;
int notify_client_fn (struct notifier_block *nb, unsigned long action, void *data)
{
printk("--->%s, action: %lu, data: %s\n", __func__, action, data);
return 0;
}
static struct notifier_block ntu = {
.notifier_call = notify_client_fn,
};
static int __init notify_client_test_init(void)
{
printk("--->%s\n", __func__);
//注册通知链:
blocking_notifier_chain_register(¬ifier_server_list, &ntu);
return 0;
}
static void __exit notify_client_test_exit(void)
{
printk("--->%s\n", __func__);
}
module_init(notify_client_test_init);
module_exit(notify_client_test_exit);
MODULE_DESCRIPTION("notify client test");
MODULE_LICENSE("GPL");
先运行client, 再运行server:
[ 2.977283] —>notify_client_test_init
[ 2.977290] —>notify_server_test_init
[ 2.977298] —>notify_client_fn, action: 15, data: it is me
发现调用了回调函数, 且参数也传递过去了;