1.内核基础结构和描述-10.内核通知链-《计算机知识》

admin 2025-11-02 22:17:41 系统网络 来源:ZONE.CI 全球网 0 阅读模式
  • 内核通知链的使用
    • 内核通知链的作用
    • 内核相关API介绍
    • DEMO
    • 典型案例
  • 内核通知链的实现细节
  • 在用户层实现一个内核通知链

    参考:内核通知链注:我们对于一个比较好的结构,先学会用,然后尝试自己去实现即可。

    相关类图:notifier.drawio

    内核通知链的使用

    内核通知链的作用

    内核的通知链就是:“订阅者-发布者”模型

    作用:就是注册一个通知链表(基于优先级排序),在某种情况发证的时候,遍历去通知下大家;

    就像考试的时候,在好学生答完卷以后(发生了事件),然后将答案一个个往后传(通知),最后大家都完成了;

    image.png

    实现基于 事件和 优先级, 优先级越高越快(notifier_chain_register 链表添加时遍历优先级,priority 高的插在链表前边)

    内核相关API介绍

    根据上边的情况,其实也就分为三个接口:申请加入被通知队列,申请退出被通知队列;触发一次通知其实就是单向链表的:插入,删除,遍历;

    首先,内核支持三种通知链:atomic使用自旋锁,blocking使用rwsem(可阻塞的锁),RAW原始通知链用户自定义锁头文件include/linux/notifier.h,源文件kernel/notifier.c

    1. #include <linux/notifier.h>
    2. /*********************** 1. 定义通知链头部********************/
    3. // 初始化通知链header
    4. ATOMIC_NOTIFIER_HEAD(name) //定义并初始化一个名为name的原子通知链
    5. BLOCKING_NOTIFIER_HEAD(name) //定义并初始化一个名为name的阻塞通知链
    6. RAW_NOTIFIER_HEAD(name) //定义并初始化一个名为name的原始通知链
    7. // 或者
    8. static struct atomic_notifier_head dock_notifier_list;
    9. ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list);
    10. static struct blocking_notifier_head dock_notifier_list;
    11. ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list);
    12. static struct raw_notifier_head dock_notifier_list;
    13. ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list);
    14. /*********************** 2.定义通知链毁掉函数********************/
    15. nb = kzalloc(sizeof(struct notifier_block), GFP_KERNEL);
    16. if (nb == NULL) {
    17. pr_err("......\n");
    18. return;
    19. }
    20. nb->notifier_call = xxx;
    21. /*********************** 3. 使用通知链********************/
    22. //原子通知链
    23. int atomic_notifier_chain_register(struct atomic_notifier_head *nh, struct notifier_block *nb);
    24. int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh, struct notifier_block *nb);
    25. int atomic_notifier_call_chain(struct atomic_notifier_head *nh, unsigned long val, void *v);
    26. //可阻塞通知链
    27. int blocking_notifier_chain_register(struct blocking_notifier_head *nh, struct notifier_block *nb);
    28. int blocking_notifier_chain_cond_register(struct blocking_notifier_head *nh, struct notifier_block *nb);
    29. int srcu_notifier_chain_register(struct srcu_notifier_head *nh, struct notifier_block *nb);
    30. int blocking_notifier_call_chain(struct blocking_notifier_head *nh,unsigned long val, void *v);
    31. int srcu_notifier_call_chain(struct srcu_notifier_head *nh, unsigned long val, void *v);
    32. int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh, struct notifier_block *nb);
    33. int srcu_notifier_chain_unregister(struct srcu_notifier_head *nh, struct notifier_block *nb);
    34. //原始通知链
    35. int raw_notifier_chain_register(struct raw_notifier_head *nh, struct notifier_block *nb);
    36. int raw_notifier_chain_unregister(struct raw_notifier_head *nh,struct notifier_block *nb);
    37. int raw_notifier_call_chain(struct raw_notifier_head *nh, unsigned long val, void *v);
    38. // 如果在总线中,想通知到自己,就不继续通知后边的人了,怎么办?
    39. 自己在回调函数中返回:
    40. return NOTIFY_STOP;

    DEMO

    内核通知链:中举了一个很典型的例子;测试源码 已整理到gittee

    典型案例

    Linux总线框架就用了notifier机制 代码实现细节:

    bus_register%20%20%20%20//%20每一个总线初始化一个notifier%20head,这里使用阻塞接口%20%20%20%20BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);dma_debug_add_bus%20%20%20%20nb->notifier_call%20=%20dma_debug_device_change;%20//%20总线回调函数%20%20%20%20//%20给总线的notifier%20head添加一个%20通知需求%20%20%20%20bus_register_notifier%20%20%20%20%20%20%20%20blocking_notifier_chain_register(&bus->p->bus_notifier,%20nb);

    内核通知链的实现细节

    notifier_chain_register 是一个单项链表,然后

    1. int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
    2. unsigned long val, void *v)
    3. nh 是自己的通知链头
    4. val 是 自定义的命令,被 回调函数解析;
    5. v 是用户自定义参数
    6. 可参考 driver/base/core.c中device_add接口

    在用户层实现一个内核通知链

    TBD

    01-shell脚本介绍-《shell脚本》 系统网络

    01-shell脚本介绍-《shell脚本》

    一、shell脚本是什么二、为什么要学shell,而不是其他计算机语言三、学习这门课程的优势四、学了能干什么五、学习什么内容六、学习的技巧七、成长路径八、学习环
    评论:0   参与:  20