Abstract: This article analyzes the source code of the Hongmeng light kernel queue module to grasp the difference in queue usage.
This article is shared from the Huawei Cloud Community " Light Kernel M Core Source Code Analysis Series 13 Message Queue Queue ", author: zhushy.
Queue is a data structure commonly used for communication between tasks. The task can read messages from the queue. When the message in the queue is empty, the reading task is suspended; when there is a new message in the queue, the suspended reading task is awakened and the new message is processed. Tasks can also write messages to the queue. When the queue is full of messages, the writing task is suspended; when there are idle message nodes in the queue, the suspended writing task is awakened and the message is written. If the timeout time of the read queue and the write queue is set to 0, the task will not be suspended, and the interface will return directly, which is the non-blocking mode. The message queue provides an asynchronous processing mechanism, allowing a message to be put into the queue, but not processed immediately. At the same time, the queue also has the function of buffering messages.
This article analyzes the source code of the Hongmeng light kernel queue module to grasp the difference in queue usage. The source code involved in this article, taking the OpenHarmony LiteOS-M kernel as an example, can be obtained at the open source site https://gitee.com/openharmony/kernel_liteos_m .
Next, let's take a look at the structure of the queue, the initialization of the queue, and the source code of the common operations of the queue.
1. Queue structure definition and common macro definition
1.1 Queue structure definition
Define the structure of the queue control block as LosQueueCB in the file kernel\include\los_queue.h. The source code of the structure is as follows. Queue state. QueueState takes the values OS_QUEUE_UNUSED, OS_QUEUE_INUSED, and other structure members see the comment section.
typedef struct {
UINT8 *queue; /**< 队列内存空间的指针 */
UINT16 queueState; /**< 队列的使用状态 */
UINT16 queueLen; /**< 队列长度,即消息数量 */
UINT16 queueSize; /**< 消息节点大小 */
UINT16 queueID; /**< 队列编号 */
UINT16 queueHead; /**< 消息头节点位置 */
UINT16 queueTail; /**< 消息尾节点位置 */
UINT16 readWriteableCnt[OS_READWRITE_LEN]; /**< 2维数组,可读、可写的消息数量, 0:可读, 1:可写 */
LOS_DL_LIST readWriteList[OS_READWRITE_LEN]; /**< 2维双向链表数组,阻塞读、写任务的双向链表, 0:读链表, 1:写链表 */
LOS_DL_LIST memList; /**< 内存节点双向链表 */
} LosQueueCB;
1.2 Queue commonly used macro definition
How many queues the system supports is defined by the macro LOSCFG_BASE_IPC_QUEUE_LIMIT according to the development board situation. Each queue queueID is of the queueID type, and the value is [0,LOSCFG_BASE_IPC_QUEUE_LIMIT), which represents the number of each queue in the queue pool.
(1) The macro at ⑴ obtains the queue control block corresponding to the specified queue number QueueID from the queue pool. (2) Obtain the memory address of the queue control block according to the doubly linked list node readWriteList[OS_QUEUE_WRITE].
⑴ #define GET_QUEUE_HANDLE(QueueID) (((LosQueueCB *)g_allQueue) + (QueueID))
⑵ #define GET_QUEUE_LIST(ptr) LOS_DL_LIST_ENTRY(ptr, LosQueueCB, readWriteList[OS_QUEUE_WRITE])
In addition, the queue also provides more important enumerations and macros related to queue read message operations. The enumeration QueueReadWrite distinguishes the read and write of the queue, the enumeration QueueHeadTail distinguishes the head and the end of the queue, and the enumeration QueuePointOrNot distinguishes whether a value or a pointer is used when reading and writing messages.
The operation type of the queue is represented by a 3-bit number, see the definition of the macro OS_QUEUE_OPERATE_TYPE, where the upper 1 bit indicates the read/write value or the pointer address, the middle 1 bit indicates the head or the end of the queue, and the lower 1 bit indicates whether to read or read. Write. The definitions of enumerations and macros are as follows:
typedef enum {
OS_QUEUE_READ,
OS_QUEUE_WRITE
} QueueReadWrite;
typedef enum {
OS_QUEUE_HEAD,
OS_QUEUE_TAIL
} QueueHeadTail;
typedef enum {
OS_QUEUE_NOT_POINT,
OS_QUEUE_POINT
} QueuePointOrNot;
#define OS_QUEUE_OPERATE_TYPE(ReadOrWrite, HeadOrTail, PointOrNot) \
(((UINT32)(PointOrNot) << 2) | ((UINT32)(HeadOrTail) << 1) | (ReadOrWrite))
#define OS_QUEUE_READ_WRITE_GET(type) ((type) & (0x01))
#define OS_QUEUE_READ_HEAD (OS_QUEUE_READ | (OS_QUEUE_HEAD << 1))
#define OS_QUEUE_READ_TAIL (OS_QUEUE_READ | (OS_QUEUE_TAIL << 1))
#define OS_QUEUE_WRITE_HEAD (OS_QUEUE_WRITE | (OS_QUEUE_HEAD << 1))
#define OS_QUEUE_WRITE_TAIL (OS_QUEUE_WRITE | (OS_QUEUE_TAIL << 1))
#define OS_QUEUE_OPERATE_GET(type) ((type) & (0x03))
#define OS_QUEUE_IS_POINT(type) ((type) & (0x04))
#define OS_QUEUE_IS_READ(type) (OS_QUEUE_READ_WRITE_GET(type) == OS_QUEUE_READ)
#define OS_QUEUE_IS_WRITE(type) (OS_QUEUE_READ_WRITE_GET(type) == OS_QUEUE_WRITE)
#define OS_READWRITE_LEN 2
2. Queue initialization
The queue is turned on by default in the kernel, and the user can turn it off through the macro LOSCFG_BASE_IPC_QUEUE. When the queue is turned on, when the system starts, call OsQueueInit() in kernel\src\los_init.c to initialize the queue module. Next, we analyze the code for queue initialization.
⑴Apply for memory for the queue. If the application fails, an error will be returned. (2) Initialize the two-way circular linked list g_freeQueueList, and maintain unused queues. (3) Initialize each queue in a loop, specify the index queueID for each queue node, and insert the queue node into the unused queue doubly linked list g_freeQueueList. It can be seen from the code that the node hanging on the doubly linked list of unused queues is the write blocking task linked list node of each queue control block. readWriteList[OS_QUEUE_WRITE].
LITE_OS_SEC_TEXT_INIT UINT32 OsQueueInit(VOID)
{
LosQueueCB *queueNode = NULL;
UINT16 index;
if (LOSCFG_BASE_IPC_QUEUE_LIMIT == 0) {
return LOS_ERRNO_QUEUE_MAXNUM_ZERO;
}
⑴ g_allQueue = (LosQueueCB *)LOS_MemAlloc(m_aucSysMem0, LOSCFG_BASE_IPC_QUEUE_LIMIT * sizeof(LosQueueCB));
if (g_allQueue == NULL) {
return LOS_ERRNO_QUEUE_NO_MEMORY;
}
(VOID)memset_s(g_allQueue, LOSCFG_BASE_IPC_QUEUE_LIMIT * sizeof(LosQueueCB),
0, LOSCFG_BASE_IPC_QUEUE_LIMIT * sizeof(LosQueueCB));
⑵ LOS_ListInit(&g_freeQueueList);
⑶ for (index = 0; index < LOSCFG_BASE_IPC_QUEUE_LIMIT; index++) {
queueNode = ((LosQueueCB *)g_allQueue) + index;
queueNode->queueID = index;
LOS_ListTailInsert(&g_freeQueueList, &queueNode->readWriteList[OS_QUEUE_WRITE]);
}
return LOS_OK;
}
3. Common operations of the queue
3.1 Queue creation
The function to create a queue is LOS_QueueCreate(). First look at the parameters of the function: queueName is the name of the queue, which is not actually used. len is the number of messages in the queue, queueID is the queue number, and flags remain unused. maxMsgSize is the maximum size of each message in the queue.
We analyze the code that creates the queue. ⑴ Check the parameters, the queue code cannot be empty, the queue message length cannot be too large, the number of queue messages and the queue message size cannot be 0. (2) Calculate the actual maximum size of the message msgSize, that is, maxMsgSize + sizeof (UINT32) the maximum size of the message plus 4 bytes, and the last 4 bytes of the message are used to store the actual length of the message. Then call the function LOS_MemAlloc() at ⑶ to dynamically apply for memory for the queue. If the memory application fails, an error code will be returned.
(4) It is judged whether g_freeQueueList is empty. If there is no available queue, release the memory previously requested. ⑸ If g_freeQueueList is not empty, get the first available queue node, then delete it from the doubly linked list g_freeQueueList, then call the macro GET_QUEUE_LIST to get LosQueueCB *queueCB, initialize the created queue information, including the length of the queue.queueLen, message size .queueSize, queue memory space.queue, message state.queueState, the number of readable.readWriteableCnt[OS_QUEUE_READ] is 0, the number of writable readWriteableCnt[OS_QUEUE_WRITE] is the length of the queue message len, the head position of the queue.queueHead and the tail position.queueTail Is 0.
⑹Initialize the doubly linked list. readWriteList[OS_QUEUE_READ], the message reading task blocked on this queue will hang on this linked list. Initialize the doubly linked list. readWriteList[OS_QUEUE_WRITE], the message writing task blocked on this queue will hang on this linked list. Initialize the doubly linked list.memList. ⑺ Assign a value to the output parameter *queueID, and subsequent programs use this queue number to perform other operations on the queue.
LITE_OS_SEC_TEXT_INIT UINT32 LOS_QueueCreate(CHAR *queueName,
UINT16 len,
UINT32 *queueID,
UINT32 flags,
UINT16 maxMsgSize)
{
LosQueueCB *queueCB = NULL;
UINT32 intSave;
LOS_DL_LIST *unusedQueue = NULL;
UINT8 *queue = NULL;
UINT16 msgSize;
(VOID)queueName;
(VOID)flags;
⑴ if (queueID == NULL) {
return LOS_ERRNO_QUEUE_CREAT_PTR_NULL;
}
if (maxMsgSize > (OS_NULL_SHORT - sizeof(UINT32))) {
return LOS_ERRNO_QUEUE_SIZE_TOO_BIG;
}
if ((len == 0) || (maxMsgSize == 0)) {
return LOS_ERRNO_QUEUE_PARA_ISZERO;
}
⑵ msgSize = maxMsgSize + sizeof(UINT32);
/* Memory allocation is time-consuming, to shorten the time of disable interrupt,
move the memory allocation to here. */
⑶ queue = (UINT8 *)LOS_MemAlloc(m_aucSysMem0, len * msgSize);
if (queue == NULL) {
return LOS_ERRNO_QUEUE_CREATE_NO_MEMORY;
}
intSave = LOS_IntLock();
⑷ if (LOS_ListEmpty(&g_freeQueueList)) {
LOS_IntRestore(intSave);
(VOID)LOS_MemFree(m_aucSysMem0, queue);
return LOS_ERRNO_QUEUE_CB_UNAVAILABLE;
}
⑸ unusedQueue = LOS_DL_LIST_FIRST(&(g_freeQueueList));
LOS_ListDelete(unusedQueue);
queueCB = (GET_QUEUE_LIST(unusedQueue));
queueCB->queueLen = len;
queueCB->queueSize = msgSize;
queueCB->queue = queue;
queueCB->queueState = OS_QUEUE_INUSED;
queueCB->readWriteableCnt[OS_QUEUE_READ] = 0;
queueCB->readWriteableCnt[OS_QUEUE_WRITE] = len;
queueCB->queueHead = 0;
queueCB->queueTail = 0;
⑹ LOS_ListInit(&queueCB->readWriteList[OS_QUEUE_READ]);
LOS_ListInit(&queueCB->readWriteList[OS_QUEUE_WRITE]);
LOS_ListInit(&queueCB->memList);
LOS_IntRestore(intSave);
⑺ *queueID = queueCB->queueID;
OsHookCall(LOS_HOOK_TYPE_QUEUE_CREATE, queueCB);
return LOS_OK;
}
3.2 Queue deletion
We can use the function LOS_QueueDelete(UINT32 queueID) to delete the queue. Let's see how to delete the queue by analyzing the source code.
(1) It is judged whether the queue ID exceeds LOSCFG_BASE_IPC_QUEUE_LIMIT, and if it exceeds, an error code is returned. If there is no problem with the queue number, get the queue control block LosQueueCB *queueCB. (2) It is judged that the queue to be deleted is in an unused state, then jump to the error label QUEUE_END for processing. (3) If the blocked read and blocked write task list of the queue is not empty, or the memory node linked list is not empty, it is not allowed to delete and jump to the error label for processing. ⑷ Check whether the readable and writable quantity of the queue is wrong.
⑸ Use the pointer UINT8 *queue to save the memory space of the queue, ⑹ make .queue empty, set .queueState to OS_QUEUE_UNUSED, and insert the queue node into the unused queue doubly linked list g_freeQueueList. Next, you need to call the function LOS_MemFree() at ⑺ to release the queue memory space.
LITE_OS_SEC_TEXT_INIT UINT32 LOS_QueueDelete(UINT32 queueID)
{
LosQueueCB *queueCB = NULL;
UINT8 *queue = NULL;
UINT32 intSave;
UINT32 ret;
⑴ if (queueID >= LOSCFG_BASE_IPC_QUEUE_LIMIT) {
return LOS_ERRNO_QUEUE_NOT_FOUND;
}
intSave = LOS_IntLock();
queueCB = (LosQueueCB *)GET_QUEUE_HANDLE(queueID);
⑵ if (queueCB->queueState == OS_QUEUE_UNUSED) {
ret = LOS_ERRNO_QUEUE_NOT_CREATE;
goto QUEUE_END;
}
⑶ if (!LOS_ListEmpty(&queueCB->readWriteList[OS_QUEUE_READ])) {
ret = LOS_ERRNO_QUEUE_IN_TSKUSE;
goto QUEUE_END;
}
if (!LOS_ListEmpty(&queueCB->readWriteList[OS_QUEUE_WRITE])) {
ret = LOS_ERRNO_QUEUE_IN_TSKUSE;
goto QUEUE_END;
}
if (!LOS_ListEmpty(&queueCB->memList)) {
ret = LOS_ERRNO_QUEUE_IN_TSKUSE;
goto QUEUE_END;
}
⑷ if ((queueCB->readWriteableCnt[OS_QUEUE_WRITE] + queueCB->readWriteableCnt[OS_QUEUE_READ]) !=
queueCB->queueLen) {
ret = LOS_ERRNO_QUEUE_IN_TSKWRITE;
goto QUEUE_END;
}
⑸ queue = queueCB->queue;
⑹ queueCB->queue = (UINT8 *)NULL;
queueCB->queueState = OS_QUEUE_UNUSED;
LOS_ListAdd(&g_freeQueueList, &queueCB->readWriteList[OS_QUEUE_WRITE]);
LOS_IntRestore(intSave);
OsHookCall(LOS_HOOK_TYPE_QUEUE_DELETE, queueCB);
⑺ ret = LOS_MemFree(m_aucSysMem0, (VOID *)queue);
return ret;
QUEUE_END:
LOS_IntRestore(intSave);
return ret;
}
Let's take a look at the read and write of the queue. There are two points to note:
- Reading and writing of the head and tail of the team
Only read from the beginning of the queue is supported, but not from the end of the queue, otherwise it will not be counted as a queue. In addition to the normal end-of-line writing message, it also provides a queue-cutting mechanism to support writing from the end of the line.
- Queue message data content
There are two types of messages written to the queue, namely, support for writing by address and writing by value (with copy). According to which type to write, you need to pair the corresponding type to read.
The types of queue reading interfaces are summarized as follows:
3.3 Queue read
We know that there are two queue reading methods, the function LOS_QueueRead() that reads by pointer address and the function LOS_QueueReadCopy() that reads by message value. Let us first look at the function LOS_QueueRead(). The function has 4 parameters, the queue ID queueID, the buffer address of the read message *bufferAddr, the buffer size of the read message bufferSize, and the read queue message Wait for the timeout time timeOut. The code is as follows, let's analyze the code.
⑴ Check the incoming parameters, the queue number cannot exceed the limit, the incoming pointer cannot be empty, and the buffer size cannot be 0. If timeout is not zero, the queue cannot be read in the interrupt. (2) The operation type means that the head of the queue reads the message pointer, and then calls the function OsQueueOperate() to further manipulate the queue.
LITE_OS_SEC_TEXT UINT32 LOS_QueueRead(UINT32 queueID, VOID *bufferAddr, UINT32 bufferSize, UINT32 timeOut)
{
UINT32 ret;
UINT32 operateType;
⑴ ret = OsQueueReadParameterCheck(queueID, bufferAddr, &bufferSize, timeOut);
if (ret != LOS_OK) {
return ret;
}
⑵ operateType = OS_QUEUE_OPERATE_TYPE(OS_QUEUE_READ, OS_QUEUE_HEAD, OS_QUEUE_POINT);
OsHookCall(LOS_HOOK_TYPE_QUEUE_READ, (LosQueueCB *)GET_QUEUE_HANDLE(queueID));
return OsQueueOperate(queueID, operateType, bufferAddr, &bufferSize, timeOut);
}
Let's further analyze the function OsQueueOperate(), which is a more general package. Reading and writing will call this function. Let's take the read queue as an example to analyze this function. ⑴ Get the operation type of the queue, which is a read operation. (2) At first, call the function OsQueueOperateParamCheck() to check the parameters. The check queue is the queue in use, and the read and write message size is checked. (3) If the readable quantity is 0, if it cannot be read, if it is zero wait, an error code will be returned. If the current lock task is scheduled, jump out of function execution. Otherwise, execute ⑷ to put the current task into the read message blocking queue of the queue, and then trigger the task scheduling, and the subsequent code will not be executed temporarily. If the readable quantity is not 0, when you can continue to read, execute the code at ⑹ to reduce the readable quantity by 1, and then continue to execute the code at ⑺ to read the queue.
After the read queue blocking timeout, or the queue can be read, continue to execute the code at ⑸. If a timeout occurs, the queue cannot be read yet, the task status is changed, and the function execution exits. If the queue can be read, continue to execute the code at ⑺ to read the queue. ⑻ After successfully reading the queue, if there is a task blocked in the writing queue, get the first task resumedTask in the blocked list, and then call the wake-up function OsSchedTaskWake() to put the task to be resumed into the ready queue and trigger a task Scheduling. If there are no blocking tasks, add 1 to the number of writable tasks.
UINT32 OsQueueOperate(UINT32 queueID, UINT32 operateType, VOID *bufferAddr, UINT32 *bufferSize, UINT32 timeOut)
{
LosQueueCB *queueCB = NULL;
LosTaskCB *resumedTask = NULL;
UINT32 ret;
⑴ UINT32 readWrite = OS_QUEUE_READ_WRITE_GET(operateType);
UINT32 readWriteTmp = !readWrite;
UINT32 intSave = LOS_IntLock();
queueCB = (LosQueueCB *)GET_QUEUE_HANDLE(queueID);
⑵ ret = OsQueueOperateParamCheck(queueCB, operateType, bufferSize);
if (ret != LOS_OK) {
goto QUEUE_END;
}
⑶ if (queueCB->readWriteableCnt[readWrite] == 0) {
if (timeOut == LOS_NO_WAIT) {
ret = OS_QUEUE_IS_READ(operateType) ? LOS_ERRNO_QUEUE_ISEMPTY : LOS_ERRNO_QUEUE_ISFULL;
goto QUEUE_END;
}
if (g_losTaskLock) {
ret = LOS_ERRNO_QUEUE_PEND_IN_LOCK;
goto QUEUE_END;
}
LosTaskCB *runTsk = (LosTaskCB *)g_losTask.runTask;
⑷ OsSchedTaskWait(&queueCB->readWriteList[readWrite], timeOut);
LOS_IntRestore(intSave);
LOS_Schedule();
intSave = LOS_IntLock();
⑸ if (runTsk->taskStatus & OS_TASK_STATUS_TIMEOUT) {
runTsk->taskStatus &= ~OS_TASK_STATUS_TIMEOUT;
ret = LOS_ERRNO_QUEUE_TIMEOUT;
goto QUEUE_END;
}
} else {
⑹ queueCB->readWriteableCnt[readWrite]--;
}
⑺ OsQueueBufferOperate(queueCB, operateType, bufferAddr, bufferSize);
⑻ if (!LOS_ListEmpty(&queueCB->readWriteList[readWriteTmp])) {
resumedTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&queueCB->readWriteList[readWriteTmp]));
OsSchedTaskWake(resumedTask);
LOS_IntRestore(intSave);
LOS_Schedule();
return LOS_OK;
} else {
⑼ queueCB->readWriteableCnt[readWriteTmp]++;
}
QUEUE_END:
LOS_IntRestore(intSave);
return ret;
}
Let's continue to see how the function OsQueueBufferOperate() specifically reads the queue. ⑴ The switch-case statement obtains the operation position according to the operation type. In the case of (2) head reading, first obtain the reading position queuePosition. Then, if the current head node position .queueHead plus 1 is equal to the length of the queue message, the head node position .queueHead is set to 0, otherwise it is increased by 1. In the case of head writing, if the current head node position.queueHead is equal to 0, the head node position.queueHead is set to the queue message length minus 1, that is, queueCB->queueLen-1, otherwise the head node position.queueHead minus 1. Then, get the position queuePosition to be written. For the case of ⑷ tail writing, first obtain the writing position queuePosition. Then, if the current tail node position.queueTail plus 1 is equal to the length of the queue message, the tail node position.queueTail is set to 0, otherwise it is increased by 1.
(5) Obtain the queue message node queueNode based on the obtained queue reading position. ⑹ If the operation type is to read and write messages by pointer, directly read the data of the message node and write the pointer corresponding to the buffer (UINT32 ) bufferAddr, or directly write the pointer corresponding to the buffer (UINT32 ) bufferAddr data Just enter the message node. We will then look at how to read and write messages according to the number of data. The code at ⑺ is used to read data messages. The last 4 bytes of each message node store the length of the message. First, get the length msgDataSize of the message, and then read the message content to the bufferAddr. Let’s take a look at how to write the queue message at ⑻. First write the message content to queueNode, and then write the message length content to queueNode + queueCB->queueSize-sizeof(UINT32), which is the last 4 of each message node byte.
static INLINE VOID OsQueueBufferOperate(LosQueueCB *queueCB, UINT32 operateType,
VOID *bufferAddr, UINT32 *bufferSize)
{
UINT8 *queueNode = NULL;
UINT32 msgDataSize;
UINT16 queuePosion;
errno_t rc;
/* get the queue position */
⑴ switch (OS_QUEUE_OPERATE_GET(operateType)) {
case OS_QUEUE_READ_HEAD:
⑵ queuePosion = queueCB->queueHead;
((queueCB->queueHead + 1) == queueCB->queueLen) ? (queueCB->queueHead = 0) : (queueCB->queueHead++);
break;
case OS_QUEUE_WRITE_HEAD:
⑶ (queueCB->queueHead == 0) ? (queueCB->queueHead = (queueCB->queueLen - 1)) : (--queueCB->queueHead);
queuePosion = queueCB->queueHead;
break;
case OS_QUEUE_WRITE_TAIL:
⑷ queuePosion = queueCB->queueTail;
((queueCB->queueTail + 1) == queueCB->queueLen) ? (queueCB->queueTail = 0) : (queueCB->queueTail++);
break;
default:
PRINT_ERR("invalid queue operate type!\n");
return;
}
⑸ queueNode = &(queueCB->queue[(queuePosion * (queueCB->queueSize))]);
⑹ if (OS_QUEUE_IS_POINT(operateType)) {
if (OS_QUEUE_IS_READ(operateType)) {
*(UINT32 *)bufferAddr = *(UINT32 *)(VOID *)queueNode;
} else {
*(UINT32 *)(VOID *)queueNode = *(UINT32 *)bufferAddr; // change to pp when calling OsQueueOperate
}
} else {
⑺ if (OS_QUEUE_IS_READ(operateType)) {
msgDataSize = *((UINT32 *)(UINTPTR)((queueNode + queueCB->queueSize) - sizeof(UINT32)));
rc = memcpy_s((VOID *)bufferAddr, *bufferSize, (VOID *)queueNode, msgDataSize);
if (rc != EOK) {
PRINT_ERR("%s[%d] memcpy failed, error type = %u\n", __FUNCTION__, __LINE__, rc);
return;
}
*bufferSize = msgDataSize;
} else {
⑻ *((UINT32 *)(UINTPTR)((queueNode + queueCB->queueSize) - sizeof(UINT32))) = *bufferSize;
rc = memcpy_s((VOID *)queueNode, queueCB->queueSize, (VOID *)bufferAddr, *bufferSize);
if (rc != EOK) {
PRINT_ERR("%s[%d] memcpy failed, error type = %u\n", __FUNCTION__, __LINE__, rc);
return;
}
}
}
}
3.4 Queue write
We know that there are four queue write methods, two end-of-line writes, and two first-line writes, including writing messages by pointer address and writing messages by value. LOS_QueueWrite() will call LOS_QueueWriteCopy(), LOS_QueueWriteHead() will call LOS_QueueWriteHeadCopy(), and after specifying different operation types, it will further call the function OsQueueOperate() that has been analyzed above.
summary
This article led everyone to analyze the source code of the queue module of the Hongmeng Light Core, including the structure of the queue, the initialization of the queue pool, the creation and deletion of the queue, and the reading and writing of messages. 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 161075fb95ff41 https://gitee.com/openharmony/kernel_liteos_m , follow Watch, like Star, and Fork to your account, thank you.
Click to follow and learn about Huawei Cloud's fresh technology for the first time~
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。