鸿蒙轻内核M核源码分析系列十七(2) 异常钩子函数的注册操作

本文中所涉及的源码,以OpenHarmony LiteOS-M内核为例,均可以在开源站点https://gitee.com/openharmony/kernel_liteos_m 获取。鸿蒙轻内核异常钩子模块代码主要在components\exchook目录下。异常钩子函数的注册、解注册、异常钩子类型定义在utils\los_debug.h|.c


1、异常钩子函数节点结构体和异常钩子函数节点数组

在文件components\exchook\los_exchook.c定义异常钩子的一些宏、函数节点结构体和一些全局变量函数节点数组。⑴处定义的宏设置当前系统支持的钩子函数的个数。⑵处定义的钩子函数节点结构体,每个节点除了异常钩子函数定义还有一个指向下一个节点的指针。⑶处定义的全局变量数组g_excNodes,注册的每一个异常钩子函数都使用一个节点来维护。⑷处定义异常钩子函数节点指针数组,数组的每个元素指针指向对应类型的异常钩子节点单向链表,而最后一个元素g_excHeads[EXC_TYPE_END]指向空闲的钩子函数节点链表。

    #ifndef LOSCFG_BASE_EXC_HOOK_LIMIT
⑴  #define LOSCFG_BASE_EXC_HOOK_LIMIT  16
    #endif

⑵  struct Node {
        ExcHookFn excHookFn;
        struct Node *next;
    };

⑶  STATIC struct Node g_excNodes[LOSCFG_BASE_EXC_HOOK_LIMIT];
⑷  STATIC struct Node *g_excHeads[EXC_TYPE_END + 1]; /* EXC_TYPE_END is used for the free list. */

2、异常钩子函数的注册操作

文件components\exchook\los_exchook.c中主要定义了异常钩子函数的注册LOS_RegExcHook和解除注册LOS_UnRegExcHook对外接口函数。接下来,我们分析注册操作的源代码。

2.1 注册LOS_RegExcHook

在分析注册钩子函数的函数之前,我们先分析下如何通过调用GetFreeNode()获取钩子函数空闲节点,代码如下。g_excHeads[EXC_TYPE_END]指向钩子函数空闲节点单向链表的第一个节点。⑴处如果为空说明未初始化或者空闲节点使用完毕。⑵处如果第1个空闲节点g_excNodes[0]被使用,说明已经没有空闲节点,返回NULL即可。否则执行⑶初始化空闲节点链表,初始化后g_excHeads[EXC_TYPE_END]执行g_excNodes数组的最后一个元素,然后数组的每个元素执行前一个元素,g_excNodes[0]是最后一个空闲节点,如下图所示。然后执行⑷处把函数DoExcHook注册为全局异常钩子函数g_excHook

如果空闲节点链表不为空,执行⑸获取第一个空闲节点,然后g_excHeads[EXC_TYPE_END]指向下一个空闲节点。

STATIC struct Node *GetFreeNode(VOID)
{
    struct Node *node = NULL;
    int i;
⑴  if (g_excHeads[EXC_TYPE_END] == NULL) {
⑵      if (g_excNodes[0].excHookFn != NULL) {
            /* no free node now */
            return NULL;
        } else {
            /* Initialize the free list */
⑶          for (i = 0; i < LOSCFG_BASE_EXC_HOOK_LIMIT; ++i) {
                g_excNodes[i].next = g_excHeads[EXC_TYPE_END];
                g_excHeads[EXC_TYPE_END] = &g_excNodes[i];
            }
⑷          OsExcHookRegister(DoExcHook);
        }
    }

⑸  node = g_excHeads[EXC_TYPE_END];
    g_excHeads[EXC_TYPE_END] = node->next;
    return node;
}

下面我们接着看注册异常钩子函数的LOS_RegExcHook函数的源代码。⑴处先判断传入参数的合法性,⑵处获取空闲钩子函数节点,如果获取节点为空,则无法注册钩子函数。⑶处设置节点的钩子函数成员变量为传入的钩子函数,然后设置其下一个节点为该异常类型对应的钩子函数链表的第一个节点,然后把最后注册的钩子函数节点设置为第一个节点。因此,同一个异常类型可以注册多个钩子函数,他们维护为单向链表,第一个节点为g_excHeads[excType]。后注册的在链表的靠近链表头部。如下图所示。

UINT32 LOS_RegExcHook(EXC_TYPE excType, ExcHookFn excHookFn)
{
    UINT32 intSave;
    struct Node *node = NULL;
⑴  if (excType >= EXC_TYPE_END || excHookFn == NULL) {
        return LOS_ERRNO_SYS_PTR_NULL;
    }

    intSave = LOS_IntLock();
⑵  node = GetFreeNode();
    if (node == NULL) {
        LOS_IntRestore(intSave);
        return LOS_ERRNO_SYS_HOOK_IS_FULL;
    }

⑶  node->excHookFn = excHookFn;
    node->next = g_excHeads[excType];
    g_excHeads[excType] = node;
    LOS_IntRestore(intSave);
    return LOS_OK;
}

2.2 解除注册LOS_UnRegExcHook

我们再看看解除注册钩子函数的LOS_UnRegExcHook函数的源码,⑴处先判断传入参数的合法性。我们已经知道,同一个类型的异常钩子函数节点使用单向链表维护,我们需要执行
⑵处的循环进行遍历。遍历时,判断是否遍历到了要解除注册的函数,如果遍历到了,⑶成立,执行后续的代码。如果⑷成立,说明遍历到的节点不是第一个,把之前的节点执行当前要解除注册的节点的下一个节点,这样把要解除注册的节点从链表中进行删除。否则说明遍历到的节点为第一个,则执行⑸,把遍历到的下一个节点作为第一个节点,这样把要解除注册的节点从链表中进行删除。⑹处置空解除注册的节点,把该节点释放后作为空闲节点插入到钩子函数空闲节点链表g_excHeads[EXC_TYPE_END]的第一个位置上。

UINT32 LOS_UnRegExcHook(EXC_TYPE excType, ExcHookFn excHookFn)
{
    UINT32 intSave;
    struct Node *node = NULL;
    struct Node *preNode = NULL;
⑴  if (excType >= EXC_TYPE_END || excHookFn == NULL) {
        return LOS_ERRNO_SYS_PTR_NULL;
    }

    intSave = LOS_IntLock();
⑵  for (node = g_excHeads[excType]; node != NULL; node = node->next) {
⑶      if (node->excHookFn == excHookFn) {
⑷          if (preNode) {
                preNode->next = node->next;
            } else {
⑸              g_excHeads[excType] = node->next;
            }
⑹          node->excHookFn = NULL;
            node->next = g_excHeads[EXC_TYPE_END];
            g_excHeads[EXC_TYPE_END] = node;
        }
        preNode = node;
    }
    LOS_IntRestore(intSave);
    return LOS_OK;
}

3、异常钩子函数的执行

从上文中,我们了解到初始化钩子函数空闲链表后,通过语句OsExcHookRegister(DoExcHook)注册了异常钩子函数。现在我们就来分析下该函数的源码。DoExcHook函数会调用DoExcHookInRegOrder函数递归运行钩子函数链表上的所有节点维护的钩子函数。⑴处的代码调用函数DoExcHookInRegOrder,除了传入异常类型,还传入该异常类型对应的钩子函数节点链表的第一个节点。⑵处如果链表节点不为空,则递归调用该节点的下一个节点。⑶处执行异常钩子函数。因此,可以看得出,注册早的钩子函数在链表的尾部最先执行,注册晚的函数在链表的头部,最后执行。

STATIC VOID DoExcHookInRegOrder(EXC_TYPE excType, struct Node *node)
{
    if (node != NULL) {
⑵      DoExcHookInRegOrder(excType, node->next);
⑶      node->excHookFn(excType);
    }
}

STATIC VOID DoExcHook(EXC_TYPE excType)
{
    UINT32 intSave;
    if (excType >= EXC_TYPE_END) {
        return;
    }
    intSave = LOS_IntLock();
⑴  DoExcHookInRegOrder(excType, g_excHeads[excType]);
    LOS_IntRestore(intSave);
}


小结

本文介绍了异常钩子模块的对外注册函数LOS_RegExcHook和解除注册函数LOS_UnRegExcHook,对内部维护的钩子函数节点链表有了更深的理解。

如果大家想更加深入的学习 OpenHarmony 开发的内容,不妨可以参考以下相关学习文档进行学习,助你快速提升自己:

OpenHarmony 开发环境搭建:https://qr18.cn/CgxrRy

《OpenHarmony源码解析》:https://qr18.cn/CgxrRy

  • 搭建开发环境
  • Windows 开发环境的搭建
  • Ubuntu 开发环境搭建
  • Linux 与 Windows 之间的文件共享
  • ……

系统架构分析:https://qr18.cn/CgxrRy

  • 构建子系统
  • 启动流程
  • 子系统
  • 分布式任务调度子系统
  • 分布式通信子系统
  • 驱动子系统
  • ……

OpenHarmony 设备开发学习手册:https://qr18.cn/CgxrRy

在这里插入图片描述

OpenHarmony面试题(内含参考答案):https://qr18.cn/CgxrRy

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/687609.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

PaddleSpeech MFA:阿米娅中文音色复刻计划

PaddleSpeech&#xff1a;阿米娅中文音色复刻计划 本篇项目是对iterhui大佬项目[PaddleSpeech 原神] 音色克隆之胡桃的复刻&#xff0c;使用的PaddleSpeech的版本较新&#xff0c;也针对新版本的PaddleSpeech做了许多配置之上的更新并加入了自己对语音的对齐、配置、训练其它任…

Javascript全解(基础篇)

语法与数据类型 语法 var\let\const var 声明一个变量&#xff0c;可选初始化一个值。 let 声明一个块作用域的局部变量&#xff0c;可选初始化一个值。 const 声明一个块作用域的只读常量。 用 var 或 let 语句声明的变量&#xff0c;如果没有赋初始值&#xff0c;则其值为 …

毫米波雷达深度学习技术-1.6目标识别1

1.6 目标识别 利用检测和跟踪在距离、多普勒和角度这两个维度中的任意一个进行精确的目标定位后&#xff0c;将检测到的目标分类到所需的类别中。与检测类似&#xff0c;提出了多种框架来同时使用图像和点云进行目标分类。使用图像进行目标分类的最常见方法是从检测到的目标特征…

k8s:优雅关闭pod的简单例子

先通过Dockerfile创建一个image vim Dockerfie <<<< 内容如下&#xff1a; FROM centosRUN sed -i -e "s|mirrorlist|#mirrorlist|g" /etc/yum.repos.d/CentOS-* RUN sed -i -e "s|#baseurlhttp://mirror.centos.org|baseurlhttp://vault.centos.o…

不要当网管,网管得会静态路由和路由表

1、路由表 路由表的组成 路由表由多个路由条目组成&#xff0c;每个条目通常包含以下信息&#xff1a; 目的地网络&#xff08;Destination Network&#xff09;&#xff1a; 这是数据包要到达的目标网络地址&#xff0c;通常以CIDR&#xff08;无类别域间路由&#xff09;格…

centos系统清理docker日志文件

centos系统清理docker日志文件 1.查看docker根目录位置2.清理日志 1.查看docker根目录位置 命令&#xff1a;docker info ,将Docker Root Dir 的值复制下来。如果目录中包含 等特殊符号的目录&#xff0c;需要转义 2.清理日志 创建文件&#xff1a;vim docker_logs_clean.…

Nvidia/算能 +FPGA+AI大算力边缘计算盒子:自动清理机器

总部位于硅谷的 ViaBot 正在为用于企业的机器人进行试行测试。 2016 年&#xff0c;Gregg Ratanaphanyarat 和 Dawei Ding从宾州州立大学辍学后&#xff0c;创办了一家户外清洁机器人初创公司。 如今&#xff0c;这场赌博似乎正在取得回报。二人的初创公司 ViaBot 正在与一家…

python免安装版本使用方法(win环境下)

文章目录 需求背景python下载下载免安装版本下载pip安装 参考文章&#xff1a;https://blog.csdn.net/u010835747/article/details/123731542 需求背景 在同一业务多种不同的单机需求中&#xff0c;存在业务地单一电脑运行多个不同开发人员制作的python脚本&#xff0c;但是由…

Vue07-MVVM模型

一、MVVM模型的定义 M&#xff1a;模型&#xff08;model&#xff09;&#xff1a;对应data中的数据&#xff1b;V&#xff1a;视图&#xff08;view&#xff09;&#xff1a;模版&#xff1b;VM&#xff1a;视图模型&#xff08;ViewModel&#xff09;Vue的实例对象。 Vue.js…

vue2组件封装实战系列之aside组件

组件之 GfSide 侧边栏组件一般有固定宽度用于导航菜单,布局 效果预览 属性 参数类型说明可选值默认值widthString侧边栏的宽度30% 代码实现 这里我们使用了 function 组件来实现 space 组件&#xff0c;比较简洁灵活 <template><aside class"el-aside" …

2种方法!一键批量下载1688主图、sku图、视频和详情页

最近关于如何一键下载1688主图、sku图、视频和详情页相关的问题被商友们问爆了。店雷达直接上实操教程&#xff0c;建议收藏&#xff0c;不迷路&#xff01; 方法一&#xff1a;通过选品中心下载 1、在店雷达选品中心&#xff08;如果想在1688进货的就在1688选品库中选品&…

如何选择Unity的4种批处理方式

1&#xff09;如何选择Unity的4种批处理方式 2&#xff09;Unity编辑器卡顿 3&#xff09;如何解决横屏APP在鸿蒙悬浮窗错误的变为竖屏了 4&#xff09;Hindi问题 这是第388篇UWA技术知识分享的推送&#xff0c;精选了UWA社区的热门话题&#xff0c;涵盖了UWA问答、社区帖子等技…

Ambari集成Apache Kyuubi实践

目前还有很多公司基于HDP来构建自己的大数据平台&#xff0c;随着Apache Kyuubi的持续热度&#xff0c;如何基于原有的HDP产品来集成Apache Kyuubi&#xff0c;很多人都迫切的需求。集成Apache Kyuubi到HDP中&#xff0c;主要涉及Ambari的二次开发。本文详细叙述了集成Apache K…

视频监控管理平台LntonCVS视频汇聚平台充电桩视频监控应用方案

随着新能源汽车的广泛使用&#xff0c;公众对充电设施的安全性和可靠性日益重视。为了提高充电桩的安全管理和站点运营效率&#xff0c;LntonCVS公司推出了一套全面的新能源汽车充电桩视频监控与管理解决方案。 该方案通过安装高分辨率摄像头&#xff0c;对充电桩及其周边区域进…

【C++ | this指针】一文了解C++的this指针

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; ⏰发布时间⏰&#xff1a; 本文未经允许…

【C语言】详解static和extern关键字

文章目录 1. 前言2. 作用域和生命周期2.1 作用域2.1.1 全局变量和局部变量 2.2 生命周期 3. static关键字3.1 static修饰的局部变量 4. extern关键字5. extern和static关键字的相互作用5.1 static修饰函数 6.总结 1. 前言 可能在你遇到这篇文章之前&#xff0c;你可能并未听过…

IDEA2023.1.4配置springboot项目

新建“Spring Initializr”项目 勾选以下三个依赖项即可。 springboot分为代码层、资源层和测试层。 代码层 根目录&#xff1a;src/main/java 入口启动类及程序的开发目录。在这个目录下进行业务开发、创建实体层、控制器层、数据连接层等。 资源层 根目录&#xff1a;src…

奇迹MU最强法师介绍

1、黑龙波 释放出深渊中的黑龙之魂&#xff0c;对一定范围内的目标造成中等程度伤害。 奥义&#xff1a; 怒哮——法师释放出深渊龙魂的怨怒之力&#xff0c;在电闪雷鸣中中咆哮的龙魂将对敌人额外造成少量伤害。 魂阵——法师利用法阵控制黑龙之魂进行更大范围的攻击&…

史上最强 AI 翻译诞生了!拳打谷歌,脚踢 DeepL

CoT 推理范式 默认情况下&#xff0c;大语言模型通常是直接给出问题的最终答案&#xff0c;中间推理过程是隐含的、不透明的&#xff0c;无法发挥出大模型最极致的理解能力。如果你用它来充当翻译&#xff0c;可能效果和传统的机器翻译也差不了太多。 如果我们给大模型设计一…

天行健咨询 | 谢宁DOE培训的课程内容有哪些?

谢宁DOE培训的课程内容丰富而深入&#xff0c;旨在帮助学员掌握谢宁问题解决方法在质量管理中的重要作用&#xff0c;并学会如何运用这一方法工具&#xff0c;在不中断生产过程的前提下&#xff0c;找出并解决生产中遇到的复杂而顽固的问题。 首先&#xff0c;课程会详细介绍谢…