Abstract: This paper analyzes the hongmeng light kernel event module source code, in-depth grasp the use of events.

This article is shared from huawei cloud community “Hongmeng light kernel M core source code analysis series twelve events Event”, original author: zhushy.

An Event is a mechanism for communication between tasks, which can be used for synchronization between tasks. In a multi-task environment, tasks often need to be synchronized, and a wait is a synchronization. Events can provide one-to-many or many-to-many synchronization. This article through the analysis of hongmeng light kernel event module source code, in-depth grasp the use of events. The source code covered in this article, taking the OpenHarmony LiteOS-M kernel as an example, can be found at the open source site gitee.com/openharmony… To obtain.

Next, let’s look at the event structure, event initialization, and the source code for common events.

1, event structure definition and common macro definition

1.1 Event structure definition

In the file kernel\include\los_event.h defined the event control block structure is EVENT_CB_S, structure source code is as follows, structure members explain see the comments section.

typedef struct tagEvent { UINT32 uwEventID; /**< event ID, each of which identifies a type of event */ LOS_DL_LIST stEventList; /**< read event task list */} EVENT_CB_S, *PEVENT_CB_S;Copy the code

1.2 Common event macros

When reading an event, you can select the read mode. The read mode is defined by the following macros:

  • All events (LOS_WAITMODE_AND) : Logical and, based on the eventMask of the event type passed in to the interface, only these events can be read successfully, otherwise the task will block wait or return an error code.

  • Any event (LOS_WAITMODE_OR) : logical or, based on the eventMask of the event type passed in to the interface, the read succeeds as long as one of these events occurs, otherwise the task blocks and waits or returns an error code.

  • Clear the event (LOS_WAITMODE_CLR) : This is a additional read mode, with all events or any event model used in combination (LOS_WAITMODE_AND | LOS_WAITMODE_CLR or LOS_WAITMODE_OR | LOS_WAITMODE_CLR). In this mode, the event type bit in the event control block is automatically cleared after all or any event mode is read successfully.

    #define LOS_WAITMODE_AND (4)

    #define LOS_WAITMODE_OR (2)

    #define LOS_WAITMODE_CLR (1)

2. Common operations on events

2.1 Initializing events

Before using an event, the function UINT32 LOS_EventInit(PEVENT_CB_S eventCB) must be used to initialize the event. The required parameter is the structure pointer variable PEVENT_CB_S eventCB. (1) The parameter passed in cannot be null, otherwise an error code is returned. UwEventID is initialized to 0, and the bidirectional circular list is initialized. StEventList is used to mount the task that reads the event.

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; }Copy the code

2.2 Verifying the Event Mask

We can use the UINT32LOS_EventPoll(UINT32 *eventId, UINT32 eventMask, UINT32 mode) function to verify the eventMask. The required parameters are the event encoding eventId of the event structure, the eventMask passed in by the user to be verified, eventMask, and the reading mode mode. The return value is 0, indicating that the event did not occur. Otherwise, the expected event did occur.

We look at the source code, first check the validity of the parameters passed in (1), the event code cannot be empty. Then execute the code at (2) for verification. In any event read mode, the following determination is not equal to indicating that at least one event occurred, but the return value ret indicates which events occurred. (3) In the all-things read mode, when the logic and operation *eventId & eventMask is equal to eventMask, it indicates that all expected events have occurred, and the return value ret indicates which events have occurred. In the case of ⑷, when RET is not 0 and the expected event occurs and is in the clear event reading mode, it is necessary to clear the things that have happened. It appears that this function not only queries whether an event has occurred, but also updates 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; }Copy the code

2.3 Read/Write events

2.3.1 Reading a Specified Event Type

We can read the event using the function LOS_EventRead(), which takes four arguments. EventCB is the initialized event structure, eventMask is the eventMask to be read, mode is the read mode described above, timeout is the read timeout, in ticks. When the function returns 0, the expected event did not occur, reading the event failed, and blocking occurs. A non-zero return indicates that the expected event occurred and the event was successfully read. Let’s take a look at the source code of the function to see how events are read.

The function OsEventReadParamCheck() is called for basic verification, such as that the 25th bit reserve is not available, the eventMask cannot be zero, and whether the read mode combination is valid. ⑵ indicates that the read event cannot be interrupted. The checksum function OsEventPoll() is called at ⑶ to check whether the event eventMask has occurred. If the event occurs and ret is not 0, it is returned directly after successful reading. If ret is 0, the event does not occur, then execute the ⑷; if timeout is 0, the caller can not wait, then return directly. ⑸ If the event cannot be read when the task is scheduled, return error code.

⑹ update the blocking eventMask of the current task eventMask and eventread mode eventMode. Execute ⑺ to call the function OsSchedTaskWait to change the status of the current task to blocked and mount it to the task blocked list of the event. If timeout is not a permanent wait, the task is set to the OS_TASK_STATUS_PEND_TIME state and the wait time is set. The ⑻ operation triggers the task scheduling, and the subsequent program cannot continue until the event is read.

Procedure (9) If the event cannot be read after a timeout, an error code is returned from this task. If the specified event can be read, perform the ritual check to see if the event eventMask occurred and return the resulting 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; [6] runTsk - > eventMask = eventMask; runTsk->eventMode = mode; Once OsSchedTaskWait (& eventCB - > stEventList, timeOut); LOS_IntRestore(intSave); Being LOS_Schedule (); 'levies 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; } → 10 = LOS_EventPoll(&eventCB->uwEventID, eventMask, mode); } LOS_IntRestore(intSave); return ret; }Copy the code

2.3.2 Writing the specified event type

We can write the specified event type using the UINT32LOS_EventWrite(PEVENT_CB_S eventCB, UINT32 Events) function. The code looks like this:

Let’s examine the source code to see how to write the event type. (1) The code performs logic 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. (2) If the task list waiting for the event is not empty, it is necessary to process whether any task can read the corresponding event after writing the event. (3) the for loop iterates over the tasks on the event-blocking list and (4) gets the nextTask nextTask. ⑸ determine whether the event meets the requirements of task resumedTask read event according to different read modes. If it meets the requirements of read event, execute the ⑹ setting exitFlag exitFlag, and then call the function OsSchedTaskWake() to change the status of the task reading the event and put it into the ready queue, and continue to execute the task. Iterates over each task in the blocking task list of events. ⑻ If an event is read from a task, the task scheduling needs to be triggered.

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(); (1) eventCB - > uwEventID | = events; OsHookCall(LOS_HOOK_TYPE_EVENT_WRITE, eventCB); 2 the 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); } work = work; } if (exitFlag == 1) { LOS_IntRestore(intSave); Being LOS_Schedule (); return LOS_OK; } } LOS_IntRestore(intSave); return LOS_OK; }Copy the code

2.4 Clearing Events

We can use the UINT32LOS_EventClear(PEVENT_CB_S eventCB, UINT32 eventMask) to clear the specified event type.

Function arguments are the event structure eventCB and the event type eventMask to clear. Clearing events will first verify that the structure parameters are null, which is relatively simple. (1) carry out logic and calculation on the eventMask of the event structure and the event type eventMask to be cleared, so as 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(); (1) eventCB - > uwEventID & = eventMask; LOS_IntRestore(intSave); OsHookCall(LOS_HOOK_TYPE_EVENT_CLEAR, eventCB); return LOS_OK; }Copy the code

2.5 Destruction Events

We can use the UINT32LOS_EventDestroy(PEVENT_CB_S eventCB) function to destroy the specified event control block.

The function argument is an event structure, and when destroying the event, it first checks whether the structure argument is null, which is relatively simple. (1) If the task blocking list of the event is not empty, the event cannot be destroyed. (2) Set the stEventList 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(); (1) 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; }Copy the code

summary

This article leads you to analyze the hongmeng light kernel event module source code, including the event structure, event initialization, event creation and deletion, release application. Thanks for reading. If you have any questions or suggestions, please leave a message at gitee.com/openharmony… . To make it easier to find the Hongmunlightweight kernel repository, you are advised to visit gitee.com/openharmony… , pay attention to Watch, like Star, and Fork into your account, thank you.

Click follow to learn about the fresh technologies of Huawei Cloud