ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

F´ 框架中的 Svc::FatalHandler 组件:FATAL 事件处理与平台差异化实现解析

F´ 框架中的 Svc::FatalHandler 组件:FATAL 事件处理与平台差异化实现解析 嵌入式系统编程【免费下载链接】fprimeF´ - A flight software and embedded systems framework项目地址https://gitcode.com/gh_mirrors/fp/fprime点击查看免费下载导读Svc::FatalHandler是 F´F Prime飞行软件与嵌入式系统框架中负责响应 FATAL致命事件的核心被动组件当系统中任何组件上报 FATAL 事件后它负责执行临终动作——在 Unix 类系统上延迟一秒后主动触发段错误退出以生成 core 文件、在 VxWorks 上挂起当前线程、在裸机Baremetal环境下陷入死循环。本文以 Svc/FatalHandler/docs/sdd.md 为主线结合仓库源码深入讲解其端口设计、平台差异化实现、部署方式与单元测试方法帮助读者理解 F´ 中 FATAL 事件的完整处理链路并掌握如何按项目需求替换该组件以实现复位等自定义行为。1. 组件职责概述Svc::FatalHandler的职责在 Svc/FatalHandler/docs/sdd.md 中被明确定义为处理来自系统的 FATAL 事件通知。在 F´ 的事件体系中FATAL 是最高严重级别的事件表示系统已经处于不可恢复的错误状态。该组件作为 FATAL 通知的最终接收与处置者通常被放置在整个事件链路的末端。从其软件设计文档中的需求表可以看到组件需要满足三条核心需求注意原文档中 FH-002 行存在重复编号需求编号描述验证方法FH-001Svc::FatalHandler组件应处理 FATAL 通知单元测试FH-002Svc::FatalHandler组件应关闭 Unix 进程单元测试FH-002Svc::FatalHandler组件应挂起触发 FATAL 的线程单元测试这里虽然需求编号出现重复应为 FH-002 与 FH-003但语义清晰Unix 类平台上组件需要终止进程VxWorks 平台上组件需要挂起线程。这两种行为在后续的源码实现中得到了一一印证。2. 端口设计与组件结构2.1 FPP 定义一个同步输入端口Svc::FatalHandler是一个典型的被动组件passive component其完整定义位于 Svc/FatalHandler/FatalHandler.fppmodule Svc { Handles FATAL calls passive component FatalHandler { FATAL event receive port sync input port FatalReceive: Svc.FatalEvent } }从定义可以看出组件只暴露一个端口FatalReceive类型为Svc.FatalEvent方向为同步输入sync input port即调用该端口时处理逻辑会在调用线程内同步执行完毕。2.2 端口数据类型Svc::FatalFatalReceive端口使用的Svc.FatalEvent端口类型定义在 Svc/Fatal/Fatal.fppmodule Svc { Fatal announce port with FATAL Event ID port FatalEvent( Id: FwEventIdType The ID of the FATAL event ) }该端口仅携带一个参数Id类型FwEventIdType即触发 FATAL 的事件的 ID。端口类型更详细的说明可参考 Svc::Fatal 端口设计文档其中指出该端口用于宣布 FATAL 事件已经发生且不携带任何可序列化类型No serializables。FatalEvent 端口类型定义示意图上图展示的是Svc.FatalEvent端口类型的 UML 定义«PortType»构造型FatalReceive输入端口正是基于该端口类型实现的调用时传入 FATAL 事件的 ID。2.3 组件类层次在源码层面组件采用标准化头文件 实现类的组织方式Svc/FatalHandler/FatalHandler.hpp 通过typedef FatalHandlerComponentImpl FatalHandler;将公开名称Svc::FatalHandler别名到实现类Svc/FatalHandler/FatalHandlerComponentImpl.hpp 声明了实现类FatalHandlerComponentImpl它继承自 FPP 自动生成的FatalHandlerComponentBase并提供构造、init、析构以及FatalReceive_handler端口处理函数Svc/FatalHandler/FatalHandlerComponentCommonImpl.cpp 中实现构造、init与析构等通用逻辑直接透传给基类。真正的平台差异化行为体现在FatalReceive_handler的三种平台实现中下面逐一展开。3. 平台差异化行为三种实现的深入解析根据设计文档的 Functional Description功能描述组件的行为随平台不同而不同而仓库源码恰好提供了 Unix/Linux、VxWorks、Baremetal 三套实现是理解该设计的最佳佐证。3.1 Unix/Linux 平台延迟一秒后触发 SIGABRT 并退出设计文档指出对于 Unix 变体组件先延迟一秒再以段错误segmentation fault方式退出。这样做的目的有二一是给 FATAL 事件足够的时间传回地面系统ground system让用户能够看到发生了什么事件二是在ulimit设置正确的前提下为调试生成 core 转储文件。对应的实现位于 Svc/FatalHandler/FatalHandlerComponentLinuxImpl.cppvoid FatalHandlerComponentImpl::FatalReceive_handler( const NATIVE_INT_TYPE portNum, FwEventIdType Id) { // for **nix, delay then exit with error code Fw::Logger::logMsg(FATAL %d handled.\n,Id,0,0,0,0,0); (void)Os::Task::delay(Fw::Time(1, 0)); Fw::Logger::logMsg(Exiting with abort signal and core dump file.\n,0,0,0,0,0,0); (void)raise( SIGABRT ); exit(1); }逐行解析这段代码的执行流程记录 FATAL 事件 ID通过 Fw/Logger/Logger.hpp 的Fw::Logger::logMsg输出FATAL %d handled.其中%d即事件 ID延迟 1 秒调用 Os/Task.hpp 中的Os::Task::delay(Fw::Time(1, 0))参数Fw::Time(1, 0)表示 1 秒 0 微秒这一秒正是设计文档中提到的传播窗口让 FATAL 通知有机会下传到地面系统提示即将退出再次通过 Logger 输出Exiting with abort signal and core dump file.触发 SIGABRT调用raise(SIGABRT)向当前进程发送 SIGABRT 信号。这里值得注意设计文档中提到的是段错误segmentation fault而实际实现选择的是SIGABRT。两者都能产生 core 文件在ulimit -c允许的前提下但SIGABRT语义上更贴合主动放弃abort的场景且能保证退出码与信号的确定性兜底退出最后调用exit(1)确保即使 SIGABRT 信号被捕获或忽略进程也以非零退出码终止。由此可见设计文档中的描述与实现存在细微差别文档说 segment fault实现用 abort signal但二者的设计意图完全一致制造一个可观测的进程异常终止并产生 core 供事后调试。3.2 VxWorks 平台挂起触发线程设计文档指出对于 VxWorks组件会挂起suspend调用 FATAL 的线程。实现位于 Svc/FatalHandler/FatalHandlerComponentVxWorksImpl.cppvoid FatalHandlerComponentImpl::FatalReceive_handler( const NATIVE_INT_TYPE portNum, FwEventIdType Id) { Fw::Logger::logMsg(FATAL %d handled.\n,Id,0,0,0,0,0); taskSuspend(0); }VxWorks 是实时操作系统进程模型与 Unix 不同因此不能直接退出进程。这里通过 VxWorks 的taskLib.h提供的taskSuspend(0)系统调用以参数0表示挂起当前任务VxWorks 中 tid 为 0 即调用者自身从而冻结触发 FATAL 的线程防止其在系统已经处于致命状态后继续执行而引发二次故障。这段实现直接对应需求表中的挂起触发 FATAL 的线程。3.3 裸机Baremetal平台死循环等待仓库中还提供了第三套实现位于 Svc/FatalHandler/FatalHandlerComponentBaremetalImpl.cppvoid FatalHandlerComponentImpl::FatalReceive_handler( const NATIVE_INT_TYPE portNum, FwEventIdType Id) { // for **nix, delay then exit with error code Os::Log::logMsg(FATAL %d handled.\n,Id,0,0,0,0,0); while (true) {} // Returning might be bad }在无操作系统Baremetal环境中既没有进程退出机制也没有任务挂起机制因此实现采用最朴素也最可靠的手段记录日志后用while (true) {}死循环卡住调用线程。代码注释// Returning might be bad直白地说明了设计意图——FATAL 发生后绝不允许处理函数返回否则系统会继续在已损坏的状态下运行。注意该实现使用的是Os::Log::logMsg而非 Linux 版中的Fw::Logger::logMsg反映了两套日志抽象在不同平台的适配。3.4 平台实现的构建选择从文件组织可以看出平台差异通过同名源文件分目录/分平台编译的方式隔离FatalHandlerComponentCommonImpl.cpp存放通用代码FatalHandlerComponentLinuxImpl.cpp、FatalHandlerComponentVxWorksImpl.cpp、FatalHandlerComponentBaremetalImpl.cpp分别针对三类目标平台。具体选择哪个实现由 Svc/FatalHandler/CMakeLists.txt 在构建时按目标平台决定。这种公共实现 平台桩的模式在整个 F´ 框架中广泛使用如Drv/LinuxGpioDriver、Os/目录等便于在保持组件接口一致的前提下为不同硬件平台提供不同行为。4. 在拓扑中的部署与连接4.1 实例化在参考部署Ref中FatalHandler被实例化为名为fatalHandler的组件实例见 Ref/Top/instances.fppinstance fatalHandler: Svc.FatalHandler base id 0x4300base id 0x4300为该实例分配了以 0x4300 为起始的组件基 IDFPP 工具会在此基础上自动为组件的端口、事件、遥测等分配后续 ID。4.2 连接方式FatalHandler的FatalReceive是同步输入端口需要与产生 FATAL 通知的组件的Fatal输出端口相连。在 F´ 拓扑中典型做法是在topology.fpp中用fatalHandler.FatalReceive - 某组件.Fatal的方式建立连接使 FATAL 事件沿着端口链路由事件源同步送达FatalHandler。由于该端口是同步调用FATAL 处置逻辑延迟、退出、挂起会在触发组件的上下文中同步执行完毕这保证了 FATAL 后的系统状态是确定、可控的。5. 可替换性按项目需求定制 FATAL 行为设计文档特别强调项目可以替换该组件换成执行项目特定行为如系统复位的组件。这是 F´ 组件化设计思想的重要体现FatalHandler只依赖Svc.FatalEvent这一标准端口类型任何实现了相同FatalReceive输入端口或对应Fatal输出端口的组件都可以与之互换例如飞行器地面测试中更常见的做法是收到 FATAL 后复位微控制器而非生成 core 文件此时只需实现一个新的被动组件其FatalReceive_handler中调用目标平台的重启/复位 API如看门狗触发或直接跳转到复位向量然后在拓扑中用新组件替换fatalHandler实例即可其余事件链路上的组件无需任何改动从代码结构看替换时只需仿照 FatalHandlerComponentImpl.hpp 声明并实现FatalReceive_handler即可FPP 自动生成的端口机制保证了接口兼容性。6. 单元测试与覆盖率根据设计文档Svc::FatalHandler没有状态机Section 3.4、没有显著算法Section 3.5字典Dictionary部分标记为 TBD因此其验证重点集中在单元测试。设计文档给出验证方式运行fprime-util check --coverage查看单元测试覆盖率。这是 F´ 框架的标准测试命令它会构建单元测试目标并输出覆盖率报告。结合需求表可知验证点集中在 FH-001处理 FATAL 通知与 FH-002关闭进程 / 挂起线程两条行为需求上。7. 变更记录设计文档末尾记录了组件设计的演进日期描述9/26/2016设计评审修订Design review edits总结Svc::FatalHandler虽是一个仅有一个输入端口的小型被动组件却是 F´ 系统安全设计的关键一环它决定了系统在无可挽回的致命错误发生后的最终归宿。通过 FatalHandler.fpp 的端口定义、FatalHandlerComponentLinuxImpl.cpp 的延迟 1 秒 SIGABRT exit(1)、FatalHandlerComponentVxWorksImpl.cpp 的taskSuspend(0)以及 FatalHandlerComponentBaremetalImpl.cpp 的死循环兜底可以看出 F´ 用同一接口、多平台实现的方式优雅地解决了跨平台 FATAL 处置问题同时其组件化与可替换性设计又为项目定制复位等专属行为保留了充分的扩展空间。赞分享嵌入式系统编程【免费下载链接】fprimeF´ - A flight software and embedded systems framework项目地址https://gitcode.com/gh_mirrors/fp/fprime点击查看免费下载相关推荐F´ FatalHandler 组件解析FATAL 事件处理、平台化实现与自定义替换指南F´ FatalHandler 组件解析FATAL 事件处理、平台化实现与自定义替换指南 Svc::FatalHandler 是 F´F Prime飞行软嵌入式系统编程F´ 框架中的 FW_ASSERT 到 FATAL 事件转换Svc::AssertFatalAdapter 组件深度解析F´ 框架中的 FW_ASSERT 到 FATAL 事件转换Svc::AssertFatalAdapter 组件深度解析 导读 Svc::AssertFata嵌入式系统编程F´ 框架 Svc::Fatal 致命事件端口深度解析从端口定义到平台化故障处理F´ 框架 Svc::Fatal 致命事件端口深度解析从端口定义到平台化故障处理 Svc::Fatal 是 F´F Prime飞行软件与嵌入式系统框架中嵌入式系统编程上一篇如何高效调试AMD Ryzen处理器参数3个步骤解锁SMUDebugTool的专业级硬件调控能力下一篇3大核心功能让M3U8视频下载效率提升100%的实用指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表