Linux 内核的 notifier 机制

news/2024/6/18 21:40:56 标签: linux, 运维, 服务器

Linux内核使用通知链的机制在内核各子系统之间进行事件通知(注:无法用于内核态和用户态之

Linux内核中的notifier机制是一种重要的组件间通信机制,它允许在内核中的某些事件发生时,相关的组件能够得到通知并作出相应的处理。这种机制常用于各种内核子系统,如网络、文件系统、设备驱动等,以确保当系统状态发生变化时,所有相关部分都能得到更新。

具体来说,notifier机制包括以下几个关键概念:

  1. Notifier Block:这是一个数据结构,它包含了处理特定事件的通知函数和处理函数的回调指针,以及一个优先级值。每个希望接收通知的模块都需要注册自己的notifier block。

  2. Notifier Chain:这是由一组notifier block组成的链表。当事件发生时,内核会遍历这个链表,并调用每个block中的回调函数。

  3. Notification Types:这些是预定义的事件类型,如NETDEV_CHANGE、NETDEV_UP、NETDEV_DOWN等,每个事件类型对应于内核中可能发生的一种状态变化。

  4. Registration and Unregistration:模块通过特定的内核API注册自己的notifier block到某个notifier chain中,并在不需要时将其注销。

  5. Notification Call:当检测到某个事件发生时,内核会调用notifier_call_chain()函数,这个函数会遍历相应的notifier chain,并调用每个notifier block中的回调函数。

通过这种机制,Linux内核能够以一种松耦合的方式,让不同的组件对系统中的各种事件做出响应,从而增强了系统的灵活性和可扩展性。

二、通知链应用

以系统睡眠唤醒为例,介绍可阻塞通知链的使用。

## kernel/power/main.c
## 1.初始化通知链pm_chain_head
static BLOCKING_NOTIFIER_HEAD(pm_chain_head);
​
## kernel/power/wakeup_reason.c
## 2.注册通知链
## 2.1通知链回调函数实现
static int wakeup_reason_pm_event(struct notifier_block *notifier,
        unsigned long pm_event, void *unused)
{
    switch (pm_event) {
    case PM_SUSPEND_PREPARE:
        ...
    }
}
​
static struct notifier_block wakeup_reason_pm_notifier_block = {
    .notifier_call = wakeup_reason_pm_event,
};
​
## 2.2注册通知链
int __init wakeup_reason_init(void)
{
    ...
    retval = register_pm_notifier(&wakeup_reason_pm_notifier_block);
    ....
}
​
int register_pm_notifier(struct notifier_block *nb)
{
    return blocking_notifier_chain_register(&pm_chain_head, nb);
}
​
## kernel/power/suspend.c
## 3.通知
static int suspend_prepare(suspend_state_t state)
{
    ...
    ## 3.1 发送PM_SUSPEND_PREPARE通知时,调用.notifier_call()对应的wakeup_reason_pm_event()函数处理。
    error = __pm_notifier_call_chain(PM_SUSPEND_PREPARE, -1, &nr_calls);
    ...
}
​
int __pm_notifier_call_chain(unsigned long val, int nr_to_call, int *nr_calls)
{
    ...
    ret = __blocking_notifier_call_chain(&pm_chain_head, val, NULL,
                        nr_to_call, nr_calls);
    ...
}


http://www.niftyadmin.cn/n/5520439.html

相关文章

Go-知识并发控制RWMutex

Go-知识并发控制RWMutex 1. 介绍2. 原理2.1 读写锁的数据结构2.2 接口定义2.3 Lock() 写锁定 原理2.4 Unlock() 写锁定解锁 原理2.5 RLock() 读锁定 原理2.6 RUnlock() 读锁定解锁 原理 3. 场景分析3.1 写锁定如何阻塞写锁定3.2 写锁定如何阻塞读锁定3.3 读锁定如何阻塞写锁定3…

SpringBoot + Maven 项目的创建

文章目录 1、Maven2、SpringBoot3、二者之间的联系4、项目的创建 在创建项目之前,肯定要知道他们之间的区别 1、Maven maven是一个跨平台的项目管理工具。它是Apache的一个开源项目,主要服务于基于Java平台的项目构建、依赖管理和项目信息管理。 比如说…

利用Cesium和JS实现地点点聚合功能

引言 在实现基于地图的业务场景时,当地图上需要展示过多的标记点时,大量的分散点会使地图上显得杂乱无章,导致标记点对地图上的其他重要信息造成遮挡和混淆,降低地图整体的可读性。 标记点的聚合就很好的解决了这些痛点的同时&a…

【分形技术在神经网络建模中的应用】

分形技术在神经网络建模中的应用 随着大数据时代的到来,神经网络的应用越来越广泛。神经网络的优势在于其能通过学习的方式将任务的模式记忆下来并预测未知的数据。然而,神经网络的主要缺点是需要大量的训练数据和计算资源,这使得它难以解决…

Linux文件系统【真的很详细】

目录 一.认识磁盘 1.1磁盘的物理结构 1.2磁盘的存储结构 1.3磁盘的逻辑存储结构 二.理解文件系统 2.1如何管理磁盘 2.2如何在磁盘中找到文件 2.3关于文件名 哈喽,大家好。今天我们学习文件系统,我们之前在Linux基础IO中研究的是进程和被打开文件…

C#——只读属性readonly

只读属性readonly 类的字段可以通过一个readonly(只读)表示这个为只读字段,不能被构造函数之外地方进行修改,静态只读字段不能在非静态的构造函数中使用 定义 只读属性的特点: 字段是只读的非静态 只能在非静态方法中进行修改 字段是只读的…

JavaEE——声明式事务管理案例:实现用户登录

一、案例要求 本案例要求在控制台输入用户名密码,如果用户账号密码正确则显示用户所属班级,如果登录失败则显示登录失败。实现用户登录项目运行成功后控制台效果如下所示。 欢迎来到学生管理系统 请输入用户名: zhangsan 请输入zhangsan的密…

大话C语言:第24篇 预处理

1 C语言编译流程 C语言的编译流程包括: 预编译:将.c 中的头文件展开、宏展开,生成的文件是.i 文件。gcc指令:gcc -E file.c -o file.i 编译:将预处理之后的.i 文件生成 .s 汇编文件。gcc指令:gcc -S file…