对于嵌入式开发工作人员和技术爱好者来说,深入了解常见任务间 IPC,有助于学习和研发内核。本文将从数据结构和算法解析 OpenHarmony 的事件机制,带大家深入了解内核任务间 IPC 原理。
关键数据结构
在解读事件的源码之前,首先了解下事件的关键的数据结构 PEVENT_CB_S:
typedef struct tagEvent {
UINT32 uwEventID;
LOS_DL_LIST stEventList; /**< Event control block linked list */
} EVENT_CB_S, *PEVENT_CB_S;
**uwEventID:**即标记任务的事件类型,每个bit可以标识一个事件,最多支持 31 个事件(第 25bit 保留)。
**stEventList:**即事件控制块的双向循环链表,理解这个字段是理解事件的关键。在双向循环链表中唯一不变的节点就是头节点,而这里的 stEventList 就是头节点。当有任务等待事件但事件还没发生时,任务会被挂载到等待链表中;当事件发生时,系统唤醒等待事件的任务,此时任务就会被剔出链表。
事件初始化
下面是事件初始化源码:
LITE_OS_SEC_TEXT_INIT UINT32 LOS_EventInit(PEVENT_CB_S eventCB)
{
if (eventCB == NULL) {
return LOS_ERRNO_EVENT_PTR_NULL;
}
eventCB->uwEventID = 0;
LOS_ListInit(&eventCB->stEventList);
OsHookCall(LOS_HOOK_TYPE_EVENT_INIT, eventCB);
return LOS_OK;
}
PEVENT_CB_S 相当于 EVENT_CB_S *, 因此 eventCB 是指针。
说明事件控制块由任务自己创建,内核事件模块只负责维护。任务定义自己的事件控制块变量,通过 LOS_EventInit 初始化,此时没有事件发生,事件链表为空。
用图来表达就是:
事件写操作
任务可以通过 LOS_EventWrite 来写触发一个或多个事件:
LITE_OS_SEC_TEXT UINT32 LOS_EventWrite(PEVENT_CB_S eventCB, UINT32 events)
{
...
eventCB->uwEventID |= events; ---1
if (!LOS_ListEmpty(&eventCB->stEventList)) { ---2
for (resumedTask = LOS_DL_LIST_ENTRY((&eventCB->stEventList)->pstNext, LosTaskCB, pendList);
&resumed