notifier_call -----总结

本文详细探讨了Notifier Call的工作原理及其在系统中的应用,包括其在事件通知、状态改变等方面的关键角色。通过实例分析,阐述了如何利用Notifier Call实现高效的消息传递和系统间的协调。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >



1.通知链表简介
    大多数内核子系统都是相互独立的,因此某个子系统可能对其它子系统产生的事件感兴趣。
	为了满足这个需求,也即是让某个子系统在发生某个事件时通知其它的子系统,Linux内核提供了通知链的机制。
	通知链表只能够在内核的子系统之间使用,而不能够在内核与用户空间之间进行事件的通知。
    
	通知链表是一个函数链表,链表上的每一个节点都注册了一个函数。
	当某个事情发生时,链表上所有节点对应的函数就会被执行。
	所以对于通知链表来说有一个通知方与一个接收方。
	在通知这个事件时所运行的函数由被通知方决定,实际上也即是被通知方注册了某个函数,在发生某个事件时这些函数就得到执行。
	其实和系统调用signal的思想差不多。

===============================================================================================
2.通知链表数据结构
    通知链表的节点类型为notifier_block,其定义如下:

struct notifier_block
{
    int (*notifier_call)(struct notifier_block *self, unsigned long, void *);
    struct notifier_block *next;
    int priority;
};

===============================================================================================
3.注册通知链
    在通知链注册时,需要有一个链表头,它指向这个通知链表的第一个元素。
	这样,之后的事件对该链表通知时就会根据这个链表头而找到这个链表中所有的元素。

    注册的函数是:
	int notifier_chain_register(struct notifier_block **nl, struct notifier_block *n)
    也即是将新的节点n加入到nl所指向的链表中去。
   
   卸载的函数是:
	int notifier_chain_unregister(strut notifier_block **nl, struct notifier_block *n)
    也即是将节点n从nl所指向的链表中删除。

===============================================================================================

4.通知链表
    当有事件发生时,就使用notifier_call_chain向某个通知链表发送消息。
	int notifier_call_chain(struct notifier_block **nl, unsigned long val, void *v)
    这个函数是按顺序运行nl指向的链表上的所有节点上注册的函数。简单地说,如下所示:

    struct notifier_block *nb = *n;

    while (nb)
    {
        ret = nb->notifier_call(nb, val, v);
        if (ret & NOTIFY_STOP_MASK)
        {
            return ret;
        }
        nb = nb->next;
    }

===============================================================================================
5.示例
    在这里,写了一个简单的通知链表的代码。

    实际上,整个通知链的编写也就两个过程:
    1.首先是定义自己的通知链的头节点,并将要执行的函数注册到自己的通知链中。
    2.其次则是由另外的子系统来通知这个链,让其上面注册的函数运行。

    我这里将第一个过程分成了两步来写,
	第一步是定义了头节点和一些自定义的注册函数(针对该头节点的),
	第二步则是使用自定义的注册函数注册了一些通知链节点。分别在代码buildchain.c与regchain.c中。
    发送通知信息的代码为notify.c。

代码1 buildchain.c
    它的作用是自定义一个通知链表test_chain,然后再自定义两个函数分别向这个通知链中加入或删除节点,最后再定义一个函数通知这个test_chain链。


#include <asm/uaccess.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/notifier.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/module.h>
MODULE_LICENSE("GPL");

/*
* 定义自己的通知链头结点以及注册和卸载通知链的外包函数
*/

/*
* RAW_NOTIFIER_HEAD是定义一个通知链的头部结点,
* 通过这个头部结点可以找到这个链中的其它所有的notifier_block
*/

static RAW_NOTIFIER_HEAD(test_chain);

/*
* 自定义的注册函数,将notifier_block节点加到刚刚定义的test_chain这个链表中来
* raw_notifier_chain_register会调用notifier_chain_register
*/

int register_test_notifier(struct notifier_block *nb)
{
        return raw_notifier_chain_register(&test_chain, nb);
}
EXPORT_SYMBOL(register_test_notifier);

int unregister_test_notifier(struct notifier_block *nb)
{
        return raw_notifier_chain_unregister(&test_chain, nb);
}
EXPORT_SYMBOL(unregister_test_notifier);

/*
* 自定义的通知链表的函数,即通知test_chain
-time is 2024-01-03_12-56-36 -reboot reg is 2080 -reset mode is d -reason is kernel_crash -elfhdr_size is 0 -mem_num is 4 -crash_key is 0 -dump_mem_paddr is 0x9f146130 -board_arch is arm64 Vmcoreinfo: [kimage_voffset]: 0xffffffbf88000000 [phys_offset]: 0x80000000 [kaslr_offset]: 0x80000 [vabits_actual]: 39 linux memory 1: 0x80000000-0x17ffff000 sprd dump memory 1: 0x80000000-0xbfffffff sprd dump memory 2: 0xc0000000-0xffffffff sprd dump memory 3: 0x100000000-0x13fffffff sprd dump memory 4: 0x140000000-0x17fffefff =========== [exception_time: 2024-01-03_12-56-36] =========== [exception_serialno]: [exception_kernel_version]: Linux version 5.15.149-android13-8-00008-gbe074b05e5af-ab12096863 (build-user@build-host) (Android (8508608, based on r450784e) clang version 14.0.7 (https://android.googlesource.com/toolchain/llvm-project 4c603efb0cca074e9238af8b4106c30add4418f6), LLD 14.0.7) #1 SMP PREEMPT Tue Jul 16 15:36:08 UTC 2024 [exception_reboot_reason]: kernel_crash [exception_panic_reason]: sysrq triggered crash [exception_time]: 2024-01-03_12-56-36 [exception_file_info]: not-bugon [exception_task_id]: 8261 [exception_task_family]: [sh, 8261][modem_control, 888] [exception_pc_symbol]: [<ffffffc001809434>] sysdump_panic_event+0x218/0x8ec [sysdump] [exception_stack_info]: [<ffffffc001806994>] get_exception_stack_info+0x150/0x2d8 [sysdump] [<ffffffc0018067ec>] prepare_exception_info+0x16c/0x1c4 [sysdump] [<ffffffc001809988>] sysdump_panic_event+0x76c/0x8ec [sysdump] [<ffffffc0082044fc>] atomic_notifier_call_chain+0x8c/0x138 [<ffffffc0081b4d64>] panic+0x1b8/0x44c [<ffffffc008bea13c>] rcu_read_unlock.39331+0x0/0x54 [<ffffffc008be9484>] __handle_sysrq+0x124/0x25c [<ffffffc008bead70>] write_sysrq_trigger+0x11c/0x198 [<ffffffc0086c33d0>] proc_reg_write+0x100/0x200 [<ffffffc0085c6ea4>] vfs_write+0x170/0x40c [<ffffffc0085c6cc0>] ksys_write+0x7c/0xf0 [<ffffffc0085c6c34>] __arm64_sys_write+0x20/0x30 [<ffffffc00811fb68>] invoke_syscall+0x60/0x150 [<ffffffc00811fac8>] el0_svc_common+0xb8/0xf8 [<ffffffc00811f9a0>] do_el0_svc+0x28/0x98 [<ffffffc00977d248>] el0_svc+0x24/0x84 [<ffffffc00977d1c0>] el0t_64_sync_handler+0x88/0xec [<ffffffc00809164c>] el0t_64_sync+0x1b8/0x1bc
03-14
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值