The Master said, “What is my knowledge? Ignorance is. There is a meer to ask me, empty, I knock at both ends of how.” The Analects of Confucius: A rare chapter
A hundred blog series. This is:
- [v30. Xx HongMeng kernel source code analysis control (events) | intertask synchronization scheme of many-to-many
Process communication related articles are:
- V26. Xx HongMeng kernel source code analysis (spinlocks) | when chastity memorial arch good comrade
- V27. Xx HongMeng kernel source code analysis (mutex) | than full spinlock mutex
- V28. Xx HongMeng kernel source code analysis (process) | took nine interprocess communication speed
- V29. Xx HongMeng kernel source code analysis (semaphore) | who is responsible for solving task synchronization
- V30. Xx HongMeng kernel source code analysis control (events) | intertask synchronization scheme of many-to-many
- V33. Xx HongMeng kernel source code analysis (message queue) | how to asynchronous communication between processes the data
This article clarifies the events.
Before reading this article, it is recommended to read hongmeng kernel source code analysis (total directory) other.
The official summary of
Start with the official version of events.
Events are a communication mechanism between tasks and can be used for synchronization between tasks.
In a multi-task environment, tasks often need to be synchronized. A wait is a synchronization. Events can provide one-to-many, many-to-many synchronization operations.
-
One-to-many synchronization model: A task waits for multiple events to be triggered. The task processing event can be woken up when any one event occurs, or after several events occur.
-
Many-to-many synchronization model: Multiple tasks wait for multiple events to be triggered.
The events provided by Hongmeng have the following characteristics:
- Tasks trigger events or wait for events by creating event control blocks.
- Events are independent of each other and are internally implemented as a 32-bit unsigned integer, with each bit identifying an event type. Bit 25 is not available, so up to 31 event types can be supported.
- Events are only used for synchronization between tasks and do not provide data transmission.
- Writing the same event type to the event control block more than once before being cleared is equivalent to writing it once.
- Multiple tasks can read and write to the same event.
- Support event read and write timeout mechanism.
Now look at the event diagram
Notice the three concepts mentioned in the diagram event control block Event tasks are then combined with code to understand the implementation of the event module.
What does an event control block look like?
typedef struct tagEvent {
UINT32 uwEventID; /**< Event mask in the Event control block, Each one identifies a type of event that has been processed. */
LOS_DL_LIST stEventList; /**< Event control block linked list */// Read the list of event tasks} EVENT_CB_S, * PEVENT_CB_S;Copy the code
UwEventID: Identifies the types of events that occur in a task. Each bit indicates an event type (0 indicates that the event type does not occur and 1 indicates that the event type has occurred). There are 31 types of events.
StEventList, this is a bidirectional linked list, bidirectional linked list is the most important structure of the kernel, you can go to the Hongmeng kernel source code analysis (total directory) view bidirectional linked list. The LOS_DL_LIST sticks to the host structure like a dog’s skin plaster. The stEventList hangs all the tasks waiting for this event.
Relationship between the event control block <> event <> task
It’s important to understand how these three relate to each other, or you won’t understand how the event module works.
-
A task is an event producer. Through LOS_EventWrite, it broadcasts the occurrence of the XX event and wakes up the XX task that has been registered in the event control block to wait for the occurrence of the XX event.
-
The event control block EVENT_CB_S is the logger and only does two events:
1. UwEventID bitwise logs which events occur, it just logs and doesn’t care how you consume them.
2. StEventList records which tasks are waiting for events, but it also does not record which events the task is waiting for
-
Tasks are also consumers, consuming through LOS_EventRead, and only the tasks themselves know what events to consume in what manner. Let’s review the task structure LosTaskCB’s description of the event part:
typedef struct { / /... Cut out the irrelevant parts VOID *taskEvent; // The event control block associated with the task UINT32 eventMask; // Which events to mask UINT32 eventMode; // Three modes of event (LOS_WAITMODE_AND, LOS_WAITMODE_OR, LOS_WAITMODE_CLR) } LosTaskCB; Copy the code
TaskEvent points to EVENT_CB_S
EventMask Which events in the event control block are masked
EventMode What are the three ways to consume events
#define LOS_WAITMODE_AND 4U #define LOS_WAITMODE_OR 2U #define LOS_WAITMODE_CLR 1U Copy the code
-
All events (LOS_WAITMODE_AND) : logical and, based on the eventMask of the event type passed in by the interface, can only be read successfully if all of these events have occurred, otherwise the task will block and wait or return an error code.
-
Any event (LOS_WAITMODE_OR) : logic or eventMask based on the event type passed in by the interface. If any of these events occur, the task will block and wait or return an error code.
-
Clear 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, when all or any event modes are read successfully, the corresponding event type bits in the event control block are automatically cleared.
-
-
Events in an event control block EVENT_CB_S can come from multiple tasks, and multiple tasks can simultaneously consume events in the event control block, and these tasks can have no relationship to each other!
Function list
Events can be applied to a variety of task synchronization scenarios and can replace semaphores in some synchronization scenarios.
Read OsEventWrite and OsEventRead to understand the event module.
Event initialization -> LOS_EventInit
// Initialize an event control block
LITE_OS_SEC_TEXT_INIT UINT32 LOS_EventInit(PEVENT_CB_S eventCB)
{
UINT32 intSave;
intSave = LOS_IntLock(a);/ / lock
eventCB->uwEventID = 0; // Each bit represents an event type (0 indicates that the event type did not occur and 1 indicates that the event type has occurred)
LOS_ListInit(&eventCB->stEventList);// Initializes the event list
LOS_IntRestore(intSave);// Resume interrupt
return LOS_OK;
}
Copy the code
Code interpretation:
- Events are shared resources, so no interruption can occur during operations.
- Initialize two loggers
uwEventID
stEventList
Event production process -> OsEventWrite
LITE_OS_SEC_TEXT VOID OsEventWriteUnsafe(PEVENT_CB_S eventCB, UINT32 events, BOOL once, UINT8 *exitFlag)
{
LosTaskCB *resumedTask = NULL;
LosTaskCB *nextTask = NULL;
BOOL schedFlag = FALSE;
eventCB->uwEventID |= events;// Label the corresponding bit
if (!LOS_ListEmpty(&eventCB->stEventList)) {// Wait for the list of events to determine, processing the task waiting for the event
for (resumedTask = LOS_DL_LIST_ENTRY((&eventCB->stEventList)->pstNext, LosTaskCB, pendList); &resumedTask->pendList ! = &eventCB->stEventList;) {// Loop through the list of tasks
nextTask = LOS_DL_LIST_ENTRYPendList. PstNext, LosTaskCB, pendList);// Get the task entity
if (OsEventResume(resumedTask, eventCB, events) {// Whether to resume the task
schedFlag = TRUE;// The task has been added to the ready queue
}
if (once == TRUE) {// Whether to process only one task
break;// Exit the loop
}
resumedTask = nextTask;// Check the next task in the list}}if((exitFlag ! =NULL) && (schedFlag == TRUE)) {// Whether to let the outside dispatch
*exitFlag = 1; }}// Write event
LITE_OS_SEC_TEXT STATIC UINT32 OsEventWrite(PEVENT_CB_S eventCB, UINT32 events, BOOL once)
{
UINT32 intSave;
UINT8 exitFlag = 0;
SCHEDULER_LOCK(intSave); // Disable scheduling
OsEventWriteUnsafe(eventCB, events, once, &exitFlag);// Write event
SCHEDULER_UNLOCK(intSave); // Allow scheduling
if (exitFlag == 1) { // Scheduling needs to occur
LOS_MpSchedule(OS_MP_CPU_ALL);// Notify all cpus of scheduling
LOS_Schedule(a);// Perform scheduling
}
return LOS_OK;
}
Copy the code
Code interpretation:
-
To the corresponding event label, eventCB – > uwEventID | = events; Note that uwEventID is managed bitwise. Each bit indicates whether an event is written. For example, uwEventID = 00010010 indicates that a 1,4 event is generated
-
The loop retrieves tasks waiting for this event from the stEventList to determine whether to wake up the task. OsEventResume
// The event resumes to determine whether to wake up the task
LITE_OS_SEC_TEXT STATIC UINT8 OsEventResume(LosTaskCB * resumedTask,const PEVENT_CB_S eventCB, UINT32 events)
{
UINT8 exitFlag = 0;// Whether to wake up
if(((resumedTask->eventMode & LOS_WAITMODE_OR) && ((resumedTask->eventMask & events) ! =0)) ||
((resumedTask->eventMode & LOS_WAITMODE_AND) &&
((resumedTask->eventMask & eventCB->uwEventID) == resumedTask->eventMask))) {// Logic and logic or processing
exitFlag = 1;
resumedTask->taskEvent = NULL;
OsTaskWake(resumedTask);// Wake up the task and join the ready queue
}
return exitFlag;
}
Copy the code
3. Wake up the task OsTaskWake only adds the task back to the ready queue and needs to apply for a LOS_Schedule immediately.
Event consumption Process -> OsEventRead
LITE_OS_SEC_TEXT STATIC UINT32 OsEventRead(PEVENT_CB_S eventCB, UINT32 eventMask, UINT32 MODE, UINT32 TIMEOUT, BOOL once)
{
UINT32 ret;
UINT32 intSave;
SCHEDULER_LOCK(intSave);
ret = OsEventReadImp(eventCB, eventMask, mode, timeout, once);// Read the event implementation function
SCHEDULER_UNLOCK(intSave);
return ret;
}
// Reads the implementation function of the specified event type. The timeout is relative time: Tick
LITE_OS_SEC_TEXT STATIC UINT32 OsEventReadImp(PEVENT_CB_S eventCB, UINT32 eventMask, UINT32 MODE, UINT32 TIMEOUT, BOOL once)
{
UINT32 ret = 0;
LosTaskCB *runTask = OsCurrTaskGet(a); runTask->eventMask = eventMask; runTask->eventMode = mode; runTask->taskEvent = eventCB;// Event control block
ret = OsTaskWait(&eventCB->stEventList, timeout, TRUE)// The task enters the wait state and hangs in the blocking list
if (ret == LOS_ERRNO_TSK_TIMEOUT) {// If timeout is returned
runTask->taskEvent = NULL;
return LOS_ERRNO_EVENT_READ_TIMEOUT;
}
ret = OsEventPoll&eventCB->uwEventID, eventMask, mode);// Check whether the event is as expected
return ret;
}
Copy the code
Code interpretation:
- Event control blocks are used by tasks that give conditions for reading an event
eventMask
Tell the system to mask these events and not be interested in the masked events.eventMode
What is the way to consume events? Should all events satisfy the given conditions, or should only one be satisfied and then respond.- After the condition is finished, he enters the waiting state
OsTaskWait
How long to waittimeout
It’s up to you. It’s up to you. OsEventPoll
What does it mean to check if the event is as expected? Just look at the code// According to the event value, event mask, and verification mode passed in by the user, returns whether the event passed in by the user meets the expectation LITE_OS_SEC_TEXT UINT32 OsEventPoll(UINT32 *eventID, UINT32 eventMask, UINT32 mode) { UINT32 ret = 0;// Whether the event occurred LOS_ASSERT(OsIntLocked());// The assertion is not allowed to interrupt LOS_ASSERT(LOS_SpinHeld(&g_taskSpin));// Task spin lock if (mode & LOS_WAITMODE_OR) {// If the mode is to read any event in the mask if((*eventID & eventMask) ! =0) { ret = *eventID & eventMask; / / happened}}else {// Wait for all events to happen if((eventMask ! =0) && (eventMask == (*eventID & eventMask))) {// All events must be met ret = *eventID & eventMask; / / happened}}if (ret && (mode & LOS_WAITMODE_CLR)) {// Whether to clear the event *eventID = *eventID & ~ret; } return ret; } Copy the code
Programming instance
This example implements the following flow.
In the example, task Example_TaskEntry creates a task Example_Event, Example_Event reads event blocking, and Example_TaskEntry writes events to the task. You can understand the task switching that accompanies event operations from the order printed in the sample log.
- Create task Example_Event on task Example_TaskEntry, where task Example_Event has a higher priority than Example_TaskEntry.
- 0x00000001 is read in task Example_Event, which blocks. Task switchover occurs, and task Example_TaskEntry is executed.
- After task Example_TaskEntry writes event 0x00000001 to task Example_Event, task switchover occurs and task Example_Event is executed.
- Example_Event is executed until the task ends.
- Example_TaskEntry can be executed until the task ends.
#include "los_event.h"
#include "los_task.h"
#include "securec.h"
/* Task ID */
UINT32 g_testTaskId;
/* Event control structure */
EVENT_CB_S g_exampleEvent;
/* Waiting event type */
#define EVENT_WAIT 0x00000001
/* Use case task entry function */
VOID Example_Event(VOID)
{
UINT32 ret;
UINT32 event;
/* Wait for the timeout mode to read the event. The timeout period is 100 ticks. If the specified event is not read after 100 ticks, the read event will timeout and the task will wake up directly
printf("Example_Event wait event 0x%x \n", EVENT_WAIT); event =LOS_EventRead(&g_exampleEvent, EVENT_WAIT, LOS_WAITMODE_AND,100);
if (event == EVENT_WAIT) {
printf("Example_Event, read Event :0x%x\n"That event); }else {
printf("Example_Event, read event timeout\n"); }}UINT32 Example_TaskEntry(VOID)
{
UINT32 ret;
TSK_INIT_PARAM_S task1;
/* Event initialization */
ret = LOS_EventInit(&g_exampleEvent);
if(ret ! = LOS_OK) {printf("init event failed .\n");
return - 1;
}
/* Create a task */
(VOID)memset_s(& task1,sizeof(TSK_INIT_PARAM_S),0.sizeof(TSK_INIT_PARAM_S));
task1.pfnTaskEntry = (TSK_ENTRY_FUNC)Example_Event;
task1.pcName = "EventTsk1";
task1.uwStackSize = OS_TSK_DEFAULT_STACK_SIZE;
task1.usTaskPrio = 5;
ret = LOS_TaskCreate(& g_testTaskId, & task1);if(ret ! = LOS_OK) {printf("task create failed .\n");
return LOS_NOK;
}
/* Write g_testTaskId to wait for events */
printf("Example_TaskEntry write event .\n");
ret = LOS_EventWrite(&g_exampleEvent, EVENT_WAIT);
if(ret ! = LOS_OK) {printf("event write failed .\n");
return LOS_NOK;
}
/* Clear the flag */
printf("EventMask:%d\n", g_exampleEvent. UwEventID);LOS_EventClear(& g_exampleEvent, ~ g_exampleEvent. UwEventID);printf("EventMask:%d\n", g_exampleEvent. UwEventID);/* Delete the task */
ret = LOS_TaskDelete(g_testTaskId);
if(ret ! = LOS_OK) {printf("task delete failed .\n");
return LOS_NOK;
}
return LOS_OK;
}
Copy the code
The results
Example_Event wait event 0x1Example_TaskEntry write event. Example_Event, read event:0x1
EventMask:1
EventMask:0
Copy the code
Intensive reading of the kernel source code
Four code stores synchronous annotation kernel source code, >> view the Gitee repository
Analysis of 100 blogs. Dig deep into the core
Add comments to hongmeng kernel source code process, sort out the following article. Content based on the source code, often in life scene analogy as much as possible into the kernel knowledge of a scene, with a pictorial sense, easy to understand memory. It’s important to speak in a way that others can understand! The 100 blogs are by no means a bunch of ridiculously difficult concepts being put forward by Baidu. That’s not interesting. More hope to make the kernel become lifelike, feel more intimate. It’s hard, it’s hard, but there’s no turning back. 😛 and code bugs need to be constantly debug, there will be many mistakes and omissions in the article and annotation content, please forgive, but will be repeatedly amended, continuous update. Xx represents the number of modifications, refined, concise and comprehensive, and strive to create high-quality content.
Compile build | The fundamental tools | Loading operation | Process management |
---|---|---|---|
Compile environment The build process Environment script Build tools Designed.the gn application Ninja ninja |
Two-way linked list Bitmap management In the stack way The timer Atomic operation Time management |
The ELF format The ELF parsing Static link relocation Process image |
Process management Process concept Fork Special process Process recycling Signal production Signal consumption Shell editor Shell parsing |
Process of communication | Memory management | Ins and outs | Task management |
spinlocks The mutex Process of communication A semaphore Incident control The message queue |
Memory allocation Memory management Memory assembly The memory mapping Rules of memory Physical memory |
Total directory Scheduling the story Main memory slave The source code comments Source structure Static site |
The clock task Task scheduling Task management The scheduling queue Scheduling mechanism Thread concept Concurrent parallel The system calls Task switching |
The file system | Hardware architecture | ||
File concept The file system The index node Mount the directory Root file system Character device VFS File handle Pipeline file |
Compilation basis Assembly and the cords Working mode register Anomaly over Assembly summary Interrupt switch Interrupt concept Interrupt management |
HongMeng station | into a little bit every day, the original is not easy, welcome to reprint, please indicate the source.