Linux内核基础 | 通知链机制( 二 )

Makefile:
obj-m:=Demo.oCURRENT_PATH:=$(shell pwd)LINUX_KERNEL:=$(shell uname -r)LINUX_KERNEL_PATH:=/usr/src/linux-headers-$(LINUX_KERNEL)all: make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modulesclean: make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean将模块插入内核后,将网卡关闭再重启一次,查看日志信息:
dx@ubuntu:~/Linux_Sys_code/Notice/Module3$sudo insmod Demo.ko dx@ubuntu:~/Linux_Sys_code/Notice/Module3$ dmesg[24309.137937] inet[00000000baf272e6] is down[24313.046209] inet[00000000baf272e6] is up2、案例2
通过写两个内核模块,其中一个作为通知者一个作为被通知者
module_1.c:

  • 初始化一个通知链
  • 定义事件的回调函数并向通知链中插入三个通知块(与之前定义的回调函数相对应)
  • 测试通知链:循环遍历通知链的通知块,并同时调用对应的回调函数
#include <linux/init.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/notifier.h>/*模块功能:1、初始化一个通知链2、定义事件的回调函数并向通知链中插入三个通知块(与之前定义的回调函数相对应)3、测试通知链:循环遍历通知链的通知块,并同时调用对应的回调函数*/static RAW_NOTIFIER_HEAD(test_chain_head);EXPORT_SYMBOL_GPL(test_chain_head);//通知块1的执行函数static int A_call(struct notifier_block *nb, unsigned long event, void *v){printk("AAAAAAAAAA---------event_A occur!---------AAAAAAAAAAn");printk("my priority:%dn",nb->priority);return NOTIFY_DONE;} //通知块1:testAstatic struct notifier_block testA = {.notifier_call = A_call,.priority = 7,};//通知块2的执行函数static int B_call(struct notifier_block *nb, unsigned long event, void *v){printk("BBBBBBBBBB---------event_B occur!---------BBBBBBBBBn");printk("my priority:%dn",nb->priority);return NOTIFY_STOP_MASK;} //通知块2:testBstatic struct notifier_block testB = {.notifier_call = B_call,.priority = 9,};//通知块1的执行函数static int C_call(struct notifier_block *nb, unsigned long event, void *v){printk("CCCCCCCCCC---------event_c occur!---------CCCCCCCCCCn");printk("my priority:%dn",nb->priority);return NOTIFY_DONE;}static struct notifier_block testC = {.notifier_call = C_call,.priority = 6,};static int __init my_register(void){printk("----------register notice chain---------n");raw_notifier_chain_register(&test_chain_head,&testA);raw_notifier_chain_register(&test_chain_head,&testB);raw_notifier_chain_register(&test_chain_head,&testC);printk("----------register notice chain done---------n");//遍历已经注册的调用链 struct notifier_block *nb, *next_nb;struct raw_notifier_head *tmp = &test_chain_head;struct notifier_block *head = tmp->head; nb = rcu_dereference_raw(head);printk("----Test registed notice call----n");//循环遍历调用链,测试一下所插入的通知块 while (nb) {int ret = NOTIFY_DONE;int index=0;next_nb = rcu_dereference_raw(nb->next);printk("notice%d fun:%p,priority:%d",++index,nb->notifier_call,nb->priority);ret = nb->notifier_call(nb, 1, NULL);//调用注册的回调函数nb = next_nb; }printk("--------------Module_1 test end-------------n");return 0;}static void __exit my_unregister(void){raw_notifier_chain_unregister(&test_chain_head,&testA);raw_notifier_chain_unregister(&test_chain_head,&testB);raw_notifier_chain_unregister(&test_chain_head,&testC);}module_init(my_register);module_exit(my_unregister);MODULE_AUTHOR("Dong Xu");MODULE_LICENSE("GPL");module_2.c:模拟某事件发生,并调用通知链
#include <linux/init.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/notifier.h>/*模块功能:模拟某事件发生,并调用通知链.*/extern struct raw_notifier_head test_chain_head;//某事件static int event(unsigned long val){int ret = raw_notifier_call_chain(&test_chain_head,val,NULL);return notifier_to_errno(ret);}static int __init my_entry(void){event(666);//模拟某事件发生return 0;}static void __exit my_exit(void){printk("test endn");}module_init(my_entry);module_exit(my_exit);MODULE_AUTHOR("Dong Xu");MODULE_LICENSE("GPL");(module_1与module_2的Makefile可参考上面的Demo1)
运行时先插入module_1再插入module_2结果如下,红框内是module_1中的测试输出日志,绿框内为世界调用通知链时的执行结果日志 。
Linux内核基础 | 通知链机制

文章插图
 
从上面可以看到通知链的执行顺序是按照优先级进行的,那么当调用通知链时是否每个通知块上的回调函数都会执行呢?


推荐阅读