OpenBMC 中命令模式的深度解析:從原理到實現

引言

在 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…