上面一篇文章大致描述了一下插件開發框架整體結構。這篇描述一下核心層的設計和實現。
至於核心層的設計,我想借鑒 一下微內核的思想。核心層只負責實現下面幾個功能:
1、 插件的加載,檢測,初始化。
2、 服務的注冊。
3、 服務的調用。
4、 服務的管理。
插件的加載,檢測,初始化
插件的加載利用linux共享庫的動態加載技術。具體的方法可以看一下IBM網站的一篇資料《Linux 動態庫剖析》 。
服務的注冊
服務的注冊與調用采用表驅動的方法。核心層中維護一個服務注冊表。
//插件間交互消息類型
typedef enum __Service_Type
{
Service_Max,
}Service_Type;
//插件用於和其他插件通信接口函數,由插件提供。
typedef PRsp_Ele_Stream (*PF_Invoke_Service_Func)(PReq_Ele_Stream pele_str);
//驅動表
typedef PF_Invoke_Service_Func Service_Drive_Table[Service_Max];
驅動表是一個數組,下標為插件間交互消息類型,成員為插件提供的接收的消息處理函數,由插件初始化的時候,調用插件框架的的注冊函數注冊到驅動表。
插件的初始化實現為:
//插件用於注冊處理的消息類型的函數,由插件框架提供。
typedef RET_RESULT (*PF_Service_Register_Func)(Service_Type service_type);
//插件用於和其他插件通信接口函數,由插件框架提供。
typedef PRsp_Ele_Stream (*PF_Invoke_Service_Func)(PReq_Ele_Stream pele_str);
//插件回復響應函數。插件收到異步請求後,處理完成後,發送響應消息給請求的插件。由插件框架提供
typedef void (*PF_Send_Response_Func)(PRsp_Ele_Stream pele_str);
//初始化插件信息
typedef struct Plugin_Init_St
{
PF_Service_Register_Func register_func;//服務注冊函數,要注冊一系列的枚舉值。插件可以處理的服務枚舉值
PF_Invoke_Service_Func invoke_serv_func;//和其他組件交互時,調用的用於和其他組件交互的函數。發送請求消息。
PF_Send_Response_Func send_rsp_func;//再設計一個回復響應消息的接口。收到異步請求後,處理完畢後通知請求模塊處理結果。
} Plugin_Init_St, *PPlugin_Init_St;
//初始化插件函數,類似於構造函數。由插件提供,供插件框架加載插件時初始化插件使用。
void PF_Init_Plugin(PPlugin_Init_St pinit_info);
插件在函數PF_Init_Plugin中調用函數register_func來注冊插件要處理的消息類型。
服務的調用
//信元結構體
typedef struct Ele_St
{
Ele_Tag tag;
Ele_Length len;
Ele_Value value;
PEle_St next;
}Ele_St, *PEle_St;
//請求消息,信元流格式。
typedef struct Req_Ele_Stream
{
Plugin_ID src_id;//源插件id
Service_Type req_type;//請求類型
PEle_St ele;
} Req_Ele_Stream, *PReq_Ele_Stream;
//響應消息,信元流格式。
typedef struct Rsp_Ele_Stream
{
Plugin_ID dest_id;//目的插件id
Service_Type req_type;//響應對應的請求的類型。
Execute_Result result;//記錄執行結果
Execute_Reason reason;//記錄執行結果的原因
PEle_St ele;
} Rsp_Ele_Stream, *PRsp_Ele_Stream;
//接收插件調用服務請求函數,由插件提供,入參為請求信元流。返回值為響應信元流,用於同步請求處理。
PRsp_Ele_Stream PF_Receive_Invoke_Proc(PReq_Ele_Stream pele_str);
//插件收到響應消息的處理入口函數,由插件提供。如此為響應信元流。
void PF_Receive_Rsponse_Porc(PRsp_Ele_Stream pele_str);
插件間的依賴關系是通過信元流來實現的。至於信元流的使用在我的另一篇博客《使用信元流(TLVStream)規范、簡化模塊(C/C++)間交互 》 中有描述。插件對外的接口都是統一的。
如果插件要和其他的插件通信,則調用PF_Init_Plugin函數的傳遞的服務調用接口: invoke_serv_func。插件框架根據信元流的類型,查找驅動表,找到對應的服務接收函數。插件用函數 PF_Receive_Invoke_Proc接受其他插件的請求,此函數是插件想插件框架主動注冊到驅動表的。
如果服務時同步的,這直接通過此函數返回,返回的信息在響應信元流中。如果是異步的請求,這插件在處理完成後,通過 send_rsp_func函數來發送響應。
插件的卸載
//卸載插件時調用的函數,類似於析構函數。由插件提供,供插件框架卸載插件時調用。
void PF_Destroy_Func();