引言

在 OpenBMC 的设计中,命令模式(Command Pattern)被广泛应用于各种场景,特别是 IPMI 命令处理、异步操作封装和用户请求管理等。本文将深入分析 OpenBMC 中命令模式的实现原理、架构设计以及完整的执行流程,并通过实际代码展示其强大之处。

一、命令模式的核心思想

命令模式是一种行为设计模式,它将请求封装为对象,从而使你可以参数化客户端与不同的请求、队列或日志请求,并支持可撤销的操作。在 OpenBMC 中,这种模式特别适合处理:

  • IPMI 命令的接收与分发
  • 异步操作的封装
  • 用户请求的队列管理
  • 命令的撤销/重做机制

二、OpenBMC 命令模式架构

2.1 整体架构

OpenBMC 中的命令模式实现通常包含以下核心组件:

  1. Command 接口:定义执行操作的接口
  2. ConcreteCommand:实现具体的命令操作
  3. Invoker:负责调用命令对象
  4. Receiver:知道如何执行与请求相关的操作
  5. Client:创建具体命令对象并设置接收者
+----------------+       +-------------------+       +-----------------+
|    Client      |------>|  ConcreteCommand  |------>|    Receiver     |
+----------------+       +-------------------+       +-----------------+^      ||      ||      v+-----------------+|     Invoker     |+-----------------+

2.2 IPMI 命令处理架构

phosphor-ipmi-host 项目中,命令模式的实现尤为典型:

+---------------------+
|   IPMI NetFn Handler|  (Invoker)
+---------------------+|| 创建并执行v
+---------------------+
|   IPMI Command      |  <接口>
|   + execute()       |
|   + getResponse()   |
+---------------------+^|
+---------------------+
| 具体命令实现         |
| - GetDeviceId       |
| - GetSensorReading  |
| - SetPowerState     |
| - ...               |
+---------------------+

三、详细实现与执行流程

3.1 基础接口定义

首先看命令接口的定义 (ipmi_command.hpp):

namespace ipmi
{class Command
{
public:virtual ~Command() = default;// 执行命令virtual void execute() = 0;// 获取响应数据virtual std::vector<uint8_t> getResponse() = 0;// 支持撤销操作(可选)virtual void undo() { /* 默认实现为空 */ }// 命令描述(用于日志)virtual std::string toString() const = 0;
};} // namespace ipmi

3.2 具体命令实现

以获取传感器读数的命令为例 (get_sensor_reading.hpp):

namespace ipmi
{class GetSensorReading : public Command
{
public:explicit GetSensorReading(uint8_t sensorNum, sdbusplus::bus::bus& bus = sdbusplus::bus::new_default()): sensorNum_(sensorNum), bus_(bus) {}void execute() override{try {// 1. 获取传感器服务名auto service = getService(bus_, sensorNum_);// 2. 读取传感器值value_ = getProperty<uint8_t>(bus_, service, "/xyz/openbmc_project/sensors/" + getSensorType(sensorNum_),"xyz.openbmc_project.Sensor.Value", "Value");// 3. 更新状态status_ = 0x00; // 成功状态} catch (const std::exception& e) {status_ = 0xFF; // 错误状态value_ = 0x00;}}std::vector<uint8_t> getResponse() override{return {status_, value_};}std::string toString() const override{return fmt::format("GetSensorReading(sensor={}, status={}, value={})",sensorNum_, status_, value_);}private:uint8_t sensorNum_;uint8_t value_ = 0;uint8_t status_ = 0xFF; // 默认错误状态sdbusplus::bus::bus& bus_;
};} // namespace ipmi

3.3 调用者实现

命令的调用者通常是 IPMI 消息处理器 (ipmi_handler.cpp):

namespace ipmi
{class IpmiHandler
{
public:// 处理原始IPMI请求std::vector<uint8_t> handleRequest(const std::vector<uint8_t>& request){// 1. 解析请求auto cmd = parseRequest(request);// 2. 记录命令接收logCommand(cmd->toString(), "Received");try {// 3. 执行命令cmd->execute();// 4. 获取响应auto response = cmd->getResponse();// 5. 记录成功logCommand(cmd->toString(), "Completed");return response;} catch (const std::exception& e) {// 6. 错误处理logCommand(cmd->toString(), fmt::format("Failed: {}", e.what()));return {0xFF}; // 错误响应}}private:std::unique_ptr<Command> parseRequest(const std::vector<uint8_t>& request){// 根据请求数据创建具体命令对象switch (request[0]) { // 命令字节case CMD_GET_SENSOR_READING:return std::make_unique<GetSensorReading>(request[1]);case CMD_GET_DEVICE_ID:return std::make_unique<GetDeviceId>();// 其他命令...default:throw std::runtime_error("Unsupported command");}}void logCommand(const std::string& cmdStr, const std::string& status){std::cerr << fmt::format("[{}] {}: {}", std::chrono::system_clock::now(), cmdStr, status) << std::endl;}
};} // namespace ipmi

3.4 完整执行流程

  1. 请求接收阶段

    BMC ClientIPMI HandlerConcrete Command发送IPMI请求数据parseRequest() 创建具体命令记录命令接收日志BMC ClientIPMI HandlerConcrete Command
  2. 命令执行阶段

    sequenceDiagramparticipant Handler as IPMI Handlerparticipant Command as Concrete Commandparticipant D-Bus as D-Bus ServiceHandler->>Command: execute()Command->>D-Bus: 获取传感器数据D-Bus-->>Command: 返回传感器值Command->>Command: 更新内部状态
    
  3. 响应返回阶段

    IPMI HandlerConcrete CommandBMC ClientgetResponse()返回响应数据记录完成日志返回IPMI响应IPMI HandlerConcrete CommandBMC Client

四、高级应用:命令队列与异步处理

OpenBMC 中更复杂的命令模式实现还包括命令队列管理:

class CommandQueue
{
public:void addCommand(std::unique_ptr<Command> cmd){std::lock_guard<std::mutex> lock(queueMutex_);queue_.emplace(std::move(cmd));cv_.notify_one();}void processCommands(){while (running_) {std::unique_ptr<Command> cmd;{std::unique_lock<std::mutex> lock(queueMutex_);cv_.wait(lock, [this]{ return !queue_.empty() || !running_; });if (!running_) break;cmd = std::move(queue_.front());queue_.pop();}cmd->execute();// 处理响应...}}void stop() { running_ = false; cv_.notify_all(); }private:std::queue<std::unique_ptr<Command>> queue_;std::mutex queueMutex_;std::condition_variable cv_;bool running_ = true;
};

五、设计优势分析

  1. 解耦:将请求发送者与执行者解耦
  2. 可扩展:添加新命令不影响现有代码
  3. 组合命令:可以轻松实现宏命令
  4. 撤销/重做:通过保存命令历史实现
  5. 异步处理:命令可以放入队列延迟执行

六、实际应用示例

以下是一个完整的 IPMI 命令处理示例:

int main()
{// 1. 初始化IPMI处理器ipmi::IpmiHandler handler;// 2. 模拟接收IPMI请求 (获取传感器#5的值)std::vector<uint8_t> request = {CMD_GET_SENSOR_READING, 0x05};// 3. 处理请求auto response = handler.handleRequest(request);// 4. 输出响应std::cout << "Response: ";for (auto byte : response) {std::cout << std::hex << static_cast<int>(byte) << " ";}std::cout << std::endl;return 0;
}

结论

OpenBMC 中的命令模式实现展示了这一经典设计模式在嵌入式管理控制器中的强大应用。通过将 IPMI 命令封装为对象,OpenBMC 实现了:

  1. 清晰的命令处理流水线
  2. 灵活的命令扩展机制
  3. 可靠的错误处理和日志记录
  4. 支持同步和异步处理模式

这种设计不仅使代码更易于维护和扩展,还为 OpenBMC 提供了处理复杂管理操作的坚实基础。理解这一实现对于开发 OpenBMC 功能或进行二次开发都具有重要意义。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/93202.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/93202.shtml
英文地址,请注明出处:http://en.pswp.cn/web/93202.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从0开始跟小甲鱼C语言视频使用linux一步步学习C语言(持续更新)8.15

第十七天 第五十七&#xff0c;五十八&#xff0c;五十九和六十集 第五十六集 删除链表结点 没什么好说的关键部分代码如图 链表的插入操作 依旧没有啥可以说的代码部分大家看视频就能看懂&#xff0c;大家应该是没有什么问题的吧&#xff1f; 第五十七集 共用体形式结构与结构…

云服务器网站无法访问的系统化故障排查指南及多维度解决方案

当云服务器上的网站突然无法访问时&#xff0c;这种突发状况往往让人措手不及。别担心&#xff0c;我们可以通过系统化的排查流程快速定位问题根源。以下是经过实战验证的故障排除指南&#xff0c;帮您分步解决网站访问异常问题。一、基础状态确认 服务器的生命体征就像人体的脉…

strings命令和findstr命令验证iso文件中ntkrnlmp.exe系统版本

strings命令和findstr命令验证iso文件中ntkrnlmp.exe系统版本D:\chsads3647\i386>expand.exe Microsoft (R) File Expansion Utility Version 5.2.3647.0 版本所有 (c) Microsoft Corporation. 保留所有权利。未指定文件。D:\chsads3647\i386>strings.exe ntkrnlmp.exe …

C语言:指针(5)

1. sizeof与strlen的对比1.1 sizeofsizeof属于是操作符&#xff0c;用于计算变量所占的空间大小&#xff0c;单位为字节。如果操作数是类型的话&#xff0c;计算的是使用类型创建的变量所占内存空间的大小。sizeof只计算数据在内存中所占的空间大小&#xff0c;而不在乎内存中存…

rent8 安装部署教程之 Windows

1. Apache 安装与配置 1.1. 获取并解压 Apache 在 Apache Lounge 网址下载编译版的 Apache。下载完成后&#xff0c;将压缩包解压到 d:\web\Apache24 作为 Apache 的安装目录。 1.2. 配置 Apache 打开配置文件 conf\httpd.conf&#xff0c;找到第 37 行配置。 ​ Define SRVROO…

边缘智能实战手册:攻克IoT应用三大挑战的AI战术

前言&#xff1a;在当前的AIoT&#xff08;人工智能物联网&#xff09;赛道上&#xff0c;将AI能力下沉至边缘设备已不再是“要不要做”的选择题&#xff0c;而是“如何做好”的必答题。然而&#xff0c;在实际项目中&#xff0c;工程师们常常会遇到性能、功耗和隐私这“三座大…

【React】use-immer vs 原生 Hook:谁更胜一筹?

1.概述 use-immer 不属于官方 Hook&#xff0c;是社区维护的第三方库&#xff01;use-immer 通过封装 Immer 的不可变更新机制&#xff0c;为 React 开发者提供了一种更直观、高效的状态管理方式。它尤其适合处理复杂嵌套状态或需要频繁更新的场景&#xff0c;同时保持了与 Re…

【案例】Vue3 实现高性能级横向循环滚动生产线效果:基于 requestAnimationFrame 的流畅动画方案

动画效果在工业监控系统、生产看板等场景中&#xff0c;经常需要模拟生产线的动态运行效果。本文将基于 Vue3 和 requestAnimationFrame 实现一个高性能的横向循环滚动效果&#xff0c;完美模拟生产线传输带的视觉体验。我们将从代码实现到原理分析&#xff0c;全面讲解如何打造…

万字长文解码如何玩转Prompt(附实践应用)

在AI技术迅猛发展的今天&#xff0c;如何与大型语言模型高效“对话”已成为释放其潜力的关键。本文深入探讨了提示词工程&#xff08;Prompt Engineering&#xff09;这一新兴领域&#xff0c;系统解析了从基础概念到高级技巧的完整知识体系&#xff0c;并结合“淘宝XX业务数科…

easyExcel嵌套子集合导出Excel

我想要的Excel效果说明: 1.创建两个自定义注解:ExcelMerge(表示主对象内的单个属性,后续会根据子集合的大小合并下面的单元格),ExcelNestedList(表示嵌套的子集合) 2.NestedDataConverter.java 会把查询到的数据转换为一行一行的,相当于主表 left join 子表 ON 主.id子.主id的形…

基于 C# WinForm 字体编辑器开发记录:从基础到进阶

目录 基础版本实现 进阶版本改进 字体设置窗体增强 主窗体改进 功能对比 项目在本文章的绑定资源中免费的&#xff0c;0积分就可以下载哦~ 在 Windows Forms 应用开发中&#xff0c;字体编辑功能是许多文本处理软件的基础功能。本文将分享一个简易字体编辑器的开发过程&a…

Linux基本使用和Java程序部署(含 JDK 与 MySQL)

文章目录Linux 背景知识Linux 基本使用Linux 常用的特殊符号和操作符Linux 常用命令文本处理与分析系统管理与操作用户与权限管理文件/目录操作与内容处理工具Linux系统防火墙Shell 脚本与实践搭建 Java 部署环境apt&#xff08;Debian/Ubuntu 系的包管理利器&#xff09;介绍安…

抗辐照CANFD通信芯片在高安全领域国产化替代的研究

摘要&#xff1a;随着现代科技的飞速发展&#xff0c;高安全领域如航空航天、卫星通信等对电子设备的可靠性与抗辐照性能提出了极高的要求。CANFD通信芯片作为数据传输的关键组件&#xff0c;其性能优劣直接关系到整个系统的稳定性与安全性。本文聚焦于抗辐照CANFD通信芯片在高…

Mybatis 源码解读-SqlSession 会话源码和Executor SQL操作执行器源码

作者源码阅读笔记主要采用金山云文档记录的&#xff0c;所有的交互图和代码阅读笔记都是记录在云文档里面&#xff0c;本平台的文档编辑实在不方便&#xff0c;会导致我梳理的交互图和文档失去原来的格式&#xff0c;所以整理在文档里面&#xff0c;供大家阅读交流. 【金山文档…

Java集合类综合练习题

代码 import java.util.*; class ScoreRecord {private String studentId;private String name;private String subject;private int score;public ScoreRecord(String studentId, String name, String subject, int score) {this.studentId studentId;this.name name;this.s…

秒懂边缘云|1分钟了解边缘安全加速 ESA

普通开发者如何搭建安全快速的在线业务才能性价比最高 &#xff1f;阿里云现已为开发者推出免费版边缘安全加速 ESA&#xff0c;1 个产品就能把 CDN 缓存 API 加速 DNS WAF DDoS 防护全部搞定&#xff0c;还支持边缘函数快速部署网站和 AI 应用&#xff0c;性价比拉满。 1…

数据结构:串、数组与广义表

&#x1f4cc;目录&#x1f524; 一&#xff0c;串的定义&#x1f330; 二&#xff0c;案例引入场景1&#xff1a;文本编辑器中的查找替换场景2&#xff1a;用户手机号验证&#x1f4da; 三&#xff0c;串的类型定义、存储结构及其运算&#xff08;一&#xff09;串的抽象类型定…

服务器路由相关配置Linux和Windows

服务器路由相关配置Linux和Windowscentos路由系统核心概念传统工具集(命令)iproute2 工具集&#xff08;推荐&#xff09;NetworkManager 工具路由配置文件体系高级路由功能策略路由多路径路由路由监控工具系统级路由配置启用IP转发路由守护进程路由问题诊断流程Windows 路由Wi…

Spring Boot启动事件详解:类型、监听与实战应用

1. Spring Boot启动事件概述1.1 什么是Spring Boot启动事件在Spring Boot的应用生命周期中&#xff0c;从main方法执行到应用完全就绪&#xff0c;期间会发生一系列事件&#xff08;Event&#xff09;。这些事件由Spring Boot框架在特定时间点触发&#xff0c;用于通知系统当前…

Python闭包详解:理解闭包与可变类型和不可变类型的关系

一、定义闭包&#xff08;Closure&#xff09; 指的是一个函数对象&#xff0c;即使其外部作用域的变量已经不存在了&#xff0c;仍然能访问这些变量。简单来说&#xff0c;闭包是由函数及其相关的环境变量组成的实体。def outer():x 10def inner():print(x)return innerf ou…