Abstract: This article analyzes the source code of the Hongmeng light kernel event module to gain an in-depth understanding of the use of events.
This article is shared from the HUAWEI cloud community " light core M core source code analysis series of twelve events Event ", the original author: zhushy.
Event is a communication mechanism between tasks, which can be used for synchronization between tasks. In a multitasking environment, tasks often need to be synchronized, and a wait is a synchronization. Events can provide one-to-many and many-to-many synchronization operations. This article analyzes the source code of the Hongmeng Light Kernel Event Module to gain an in-depth understanding of the use of events. The source code involved in this article, taking the OpenHarmony LiteOS-M kernel as an example, can be obtained from the open source site https://gitee.com/openharmony/kernel_liteos_m .
Next, let's look at the structure of the event, event initialization, and the source code of the common operations of the event.
1. Event structure definition and common macro definition
1.1 Event structure definition
The event control block structure defined in the file kernel\include\los_event.h is EVENT_CB_S. The source code of the structure is as follows. See the comment section for the explanation of the structure members.
typedef struct tagEvent {
UINT32 uwEventID; /**< 事件ID,每一位标识一种事件类型 */
LOS_DL_LIST stEventList; /**< 读取事件的任务链表 */
} EVENT_CB_S, *PEVENT_CB_S;
1.2 Common macro definitions for events
When reading events, you can select the reading mode. The read mode is defined by the following macros:
- all events (LOS_WAITMODE_AND):
Logical AND, based on the event type mask eventMask passed in by the interface, the read can only be successful if these events have occurred, otherwise the task will block waiting or return an error code.
- either event (LOS_WAITMODE_OR):
Logical OR, based on the event type mask eventMask passed in by the interface, as long as any of these events occurs, the reading can be successful, otherwise the task will block waiting or return an error code.
- clear event (LOS_WAITMODE_CLR):
This is an additional read mode that needs to be used in conjunction with all event modes or any event mode (LOS_WAITMODE_AND | LOS_WAITMODE_CLR or LOS_WAITMODE_OR | LOS_WAITMODE_CLR). In this mode, when all the set event modes or any event mode are successfully read, the corresponding event type bit in the event control block will be automatically cleared.
#define LOS_WAITMODE_AND (4)
#define LOS_WAITMODE_OR (2)
#define LOS_WAITMODE_CLR (1)
3. Common operations for events
3.1 Initialization event
Before using the event, you must use the function UINT32 LOS_EventInit (PEVENT_CB_S eventCB) to initialize the event. The required parameter is the structure pointer variable PEVENT_CB_S eventCB. Analyze the code, ⑴ indicates that the parameter passed in cannot be empty, otherwise an error code will be returned. (2) Initialize the event code.uwEventID to 0, and then initialize the two-way circular linked list.stEventList, which is used to mount the task of reading events.
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);
return LOS_OK;
}
3.2 Verify event mask
We can use the function UINT32 LOS_EventPoll(UINT32 *eventId, UINT32 eventMask, UINT32 mode) to verify the event mask. The required parameters are the event code eventId of the event structure, the event mask to be verified passed in by the user, eventMask and read Take the mode mode and return whether the event passed in by the user has occurred: When the return value is 0, it means that the event that the user expects has not occurred, otherwise, it means that the event that the user expects has occurred.
Let's look at the source code. (1) First check the validity of the incoming parameters, and the event code cannot be empty. Then execute the code at ⑵ to verify. If it is any event reading mode, the next judgment does not mean that at least one event has occurred, and the return value ret indicates which events have occurred. (3) If it is the all things reading mode, when the logical AND operation *eventId & eventMask is still equal to eventMask, it means that all the expected events have occurred, and the return value ret indicates which events have occurred. (4) When ret is not 0, the expected event occurs, and it is in the clear event reading mode, it is necessary to clear the events that have occurred. It seems that this function is not only to query whether the event has occurred, but also to update the event code.
LITE_OS_SEC_TEXT UINT32 LOS_EventPoll(UINT32 *eventID, UINT32 eventMask, UINT32 mode)
{
UINT32 ret = 0;
UINT32 intSave;
⑴ if (eventID == NULL) {
return LOS_ERRNO_EVENT_PTR_NULL;
}
intSave = LOS_IntLock();
⑵ if (mode & LOS_WAITMODE_OR) {
if ((*eventID & eventMask) != 0) {
ret = *eventID & eventMask;
}
} else {
⑶ if ((eventMask != 0) && (eventMask == (*eventID & eventMask))) {
ret = *eventID & eventMask;
}
}
⑷ if (ret && (mode & LOS_WAITMODE_CLR)) {
*eventID = *eventID & ~(ret);
}
LOS_IntRestore(intSave);
return ret;
}
3.3 Read/write events
3.3.1 Read the specified event type
We can use the function LOS_EventRead() to read the event, which requires 4 parameters. eventCB is the initialized event structure, eventMask represents the event mask that needs to be read, mode is the read mode described above, timeout is the read timeout, and the unit is Tick. When the function returns 0, it means that the desired event has not occurred, the reading of the event fails, and the block is entered. When it returns non-zero, it means that the expected event has occurred, and the event is successfully read. Let's analyze the source code of the function to see how to read the event.
(1) Call the function OsEventReadParamCheck() to perform basic check, such as the 25th bit is reserved and cannot be used, the event mask eventMask cannot be zero, and the read mode combination is legal. ⑵ indicates that the read event cannot be interrupted. (3) Call the verification function OsEventPoll() to check whether the event eventMask has occurred. If the event occurs, ret is not 0, and the successful read will return directly. ret is 0, when the event does not occur, execute ⑷, if the timeout time is 0, when the caller cannot wait, return directly. ⑸ If the event cannot be read when the lock task is scheduled, an error code will be returned.
⑹Update the blocking event mask.eventMask and event reading mode.eventMode of the current task. Execute (7) call the function OsSchedTaskWait to change the state of the current task to the blocking state, and mount it on the task blocking list of the event. If the timeout is not waiting forever, the task will be set to the OS_TASK_STATUS_PEND_TIME state and the waiting time will be set. ⑻ Task scheduling is triggered, and subsequent programs will not continue execution until the event is read.
⑼ If the waiting time expires and the event is still unreadable, if the task cannot read the specified event, an error code will be returned. If the specified event can be read, execute ⑽ to check whether the event eventMask occurs, and then return the result value.
LITE_OS_SEC_TEXT UINT32 LOS_EventRead(PEVENT_CB_S eventCB, UINT32 eventMask, UINT32 mode, UINT32 timeOut)
{
UINT32 ret;
UINT32 intSave;
LosTaskCB *runTsk = NULL;
⑴ ret = OsEventReadParamCheck(eventCB, eventMask, mode);
if (ret != LOS_OK) {
return ret;
}
⑵ if (OS_INT_ACTIVE) {
return LOS_ERRNO_EVENT_READ_IN_INTERRUPT;
}
intSave = LOS_IntLock();
⑶ ret = LOS_EventPoll(&(eventCB->uwEventID), eventMask, mode);
OsHookCall(LOS_HOOK_TYPE_EVENT_READ, eventCB, eventMask, mode);
if (ret == 0) {
⑷ if (timeOut == 0) {
LOS_IntRestore(intSave);
return ret;
}
⑸ if (g_losTaskLock) {
LOS_IntRestore(intSave);
return LOS_ERRNO_EVENT_READ_IN_LOCK;
}
runTsk = g_losTask.runTask;
⑹ runTsk->eventMask = eventMask;
runTsk->eventMode = mode;
⑺ OsSchedTaskWait(&eventCB->stEventList, timeOut);
LOS_IntRestore(intSave);
⑻ LOS_Schedule();
⑼ intSave = LOS_IntLock();
if (runTsk->taskStatus & OS_TASK_STATUS_TIMEOUT) {
runTsk->taskStatus &= ~OS_TASK_STATUS_TIMEOUT;
LOS_IntRestore(intSave);
return LOS_ERRNO_EVENT_READ_TIMEOUT;
}
⑽ ret = LOS_EventPoll(&eventCB->uwEventID, eventMask, mode);
}
LOS_IntRestore(intSave);
return ret;
}
3.3.2 Write the specified event type
We can use the function UINT32 LOS_EventWrite(PEVENT_CB_S eventCB, UINT32 events) to write the specified event type. The code is as follows:
Let's look at how to write the event type by analyzing the source code. ⑴ The code performs logical OR calculation on the event mask of the event structure and the event type events to be written to complete the writing of the event. ⑵If the task list waiting for the event is not empty, it is necessary to process whether there is a task that can read the corresponding event after the event is written. (3) The for loop traverses the tasks on the event blocking list in turn, and (4) gets the next task nextTask. ⑸ place
Different reading modes are used to determine whether the event meets the requirements of the task resumedTask reading event. If the reading event is satisfied, execute ⑹Set the exit flag exitFlag, and then call the function OsSchedTaskWake() to change the status of the task reading event and put it into the ready queue , Continue to execute ⑺, traverse each task in the blocked task list of the event. ⑻If a task reads an event, it needs to trigger task scheduling.
LITE_OS_SEC_TEXT UINT32 LOS_EventWrite(PEVENT_CB_S eventCB, UINT32 events)
{
LosTaskCB *resumedTask = NULL;
LosTaskCB *nextTask = (LosTaskCB *)NULL;
UINT32 intSave;
UINT8 exitFlag = 0;
if (eventCB == NULL) {
return LOS_ERRNO_EVENT_PTR_NULL;
}
if ((eventCB->stEventList.pstNext == NULL) || (eventCB->stEventList.pstPrev == NULL)) {
return LOS_ERRNO_EVENT_NOT_INITIALIZED;
}
if (events & LOS_ERRTYPE_ERROR) {
return LOS_ERRNO_EVENT_SETBIT_INVALID;
}
intSave = LOS_IntLock();
⑴ eventCB->uwEventID |= events;
OsHookCall(LOS_HOOK_TYPE_EVENT_WRITE, eventCB);
⑵ if (!LOS_ListEmpty(&eventCB->stEventList)) {
⑶ for (resumedTask = LOS_DL_LIST_ENTRY((&eventCB->stEventList)->pstNext, LosTaskCB, pendList);
&resumedTask->pendList != (&eventCB->stEventList);) {
⑷ nextTask = LOS_DL_LIST_ENTRY(resumedTask->pendList.pstNext, LosTaskCB, pendList);
⑸ if (((resumedTask->eventMode & LOS_WAITMODE_OR) && (resumedTask->eventMask & events) != 0) ||
((resumedTask->eventMode & LOS_WAITMODE_AND) &&
((resumedTask->eventMask & eventCB->uwEventID) == resumedTask->eventMask))) {
⑹ exitFlag = 1;
OsSchedTaskWake(resumedTask);
}
⑺ resumedTask = nextTask;
}
if (exitFlag == 1) {
LOS_IntRestore(intSave);
⑻ LOS_Schedule();
return LOS_OK;
}
}
LOS_IntRestore(intSave);
return LOS_OK;
}
3.4 Clear event
We can use the function UINT32 LOS_EventClear(PEVENT_CB_S eventCB, UINT32 eventMask) to clear the specified event type. Let’s analyze the source code to see how to clear the event type.
The function parameters are the event structure eventCB and the event type eventMask to be cleared. When the event is cleared, the first check is whether the structure parameter is empty. These are relatively simple. (1) Perform logical AND calculation on the event mask of the event structure and the event type eventMask to be cleared to complete the event cleaning.
LITE_OS_SEC_TEXT_MINOR UINT32 LOS_EventClear(PEVENT_CB_S eventCB, UINT32 eventMask)
{
UINT32 intSave;
if (eventCB == NULL) {
return LOS_ERRNO_EVENT_PTR_NULL;
}
intSave = LOS_IntLock();
⑴ eventCB->uwEventID &= eventMask;
LOS_IntRestore(intSave);
OsHookCall(LOS_HOOK_TYPE_EVENT_CLEAR, eventCB);
return LOS_OK;
}
3.5 Destruction event
We can use the function UINT32 LOS_EventDestroy (PEVENT_CB_S eventCB) to destroy the specified event control block. Let's analyze the source code to see how to destroy the event.
The function parameter is the event structure. When the event is destroyed, it will first check whether the structure parameter is empty. These are relatively simple. (1) If the task blocking list of the event is not empty, the event cannot be destroyed. (2) Set the task list stEventList of the read event of the event structure to empty to complete the destruction of the event.
LITE_OS_SEC_TEXT_INIT UINT32 LOS_EventDestroy(PEVENT_CB_S eventCB)
{
UINT32 intSave;
if (eventCB == NULL) {
return LOS_ERRNO_EVENT_PTR_NULL;
}
intSave = LOS_IntLock();
⑴ if (!LOS_ListEmpty(&eventCB->stEventList)) {
LOS_IntRestore(intSave);
return LOS_ERRNO_EVENT_SHOULD_NOT_DESTORY;
}
⑵ eventCB->stEventList.pstNext = (LOS_DL_LIST *)NULL;
eventCB->stEventList.pstPrev = (LOS_DL_LIST *)NULL;
LOS_IntRestore(intSave);
OsHookCall(LOS_HOOK_TYPE_EVENT_DESTROY);
return LOS_OK;
}
summary
This article led everyone to analyze the source code of the event module of the Hongmeng Light Core, including the structure of the event, event initialization, event creation and deletion, application release, etc. Thanks for reading. If you have any questions or suggestions, you can leave a message to us: https://gitee.com/openharmony/kernel_liteos_m/issues . light kernel code warehouse easier, it is recommended to visit 160fa29afd45e7 https://gitee.com/openharmony/kernel_liteos_m , follow Watch, like Star, and Fork to your account, thank you.
Click to follow, and get to know the fresh technology of Huawei Cloud for the first time~
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。