linux里的通知链

作用: 内核子系统是相互独立的; 某个子系统可能对其他子系统产生的事件感兴趣;为了满足此需求, 也即让某个子系统在发生某个事件时通知其他子系统, 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(&notifier_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(&notifier_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
发现调用了回调函数, 且参数也传递过去了;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值