Abstract:This article analyzes the source code of the LiteOS queue module to understand the differences in queue usage.

This article is shared from the Huawei cloud community “LiteOS kernel source analysis series ten message Queue”, the original author: Zhushy.

A Queue is a data structure that is often used to communicate between tasks. A task can read messages from a queue. When the messages in the queue are empty, the reading task is suspended. When there is a new message in the queue, the pending read task is awakened to process the new message. A task can also write messages to a queue and suspend writing when the queue is full of messages. When there is an idle message node in the queue, the pending write task is woken up and the message is written. If the read queue and write queue timeouts are set to 0, the task is not suspended and the interface simply returns, which is non-blocking mode. Message Queuing provides an asynchronous processing mechanism that allows a message to be queued but not processed immediately. Queues also serve as buffers for messages.

This article analyzes the source code of the LiteOS queue module to understand the differences in queue usage. LiteOS queue module source code, can be in LiteOS https://gitee.com/LiteOS/LiteOS for open source site. Queue source code, development documentation, sample program code is as follows:

  • LiteOS kernel queue source code

Include the private header file of the queue kernel\base\include\los_queue_pri.h, the header file kernel\include\los_queue.h, the C source code file kernel\base\los_queue.c.

  • Development guidance documentation – Queues

Online document https://gitee.com/LiteOS/Lite…

Next, let’s look at the structure of the queue, queue initialization, and source code for common queue operations.

1. Queue structure definition and common macro definition

1.1 Definition of queue structure

The queue control block structure defined in the file kernel\base\include\los_queue_pri.h is LOQUEUECB. The source code of the structure is as follows. The queue status. QueueState OS_QUEUE_UNUSED, OS_QUEUE_INUSED values, queue memory type. QueueMemType OS_QUEUE_ALLOC_STATIC, OS_QUEUE_ALLOC_DYNAMIC values, Represents queue memory space allocated by counting users or system automatic allocation, respectively.

typedef struct { UINT8 *queueHandle; /**< queue space pointer */ UINT8 queueEstate; /**< queue usage status */ UINT8 queueEmType; /**< queue memory type; /**< queue memory type; /**< queue length, number of messages */ UINT16 queueSize; /**< message node size */ UINT32 queueId; /**< queue number */ UINT16 queueHead; /**< message header node location */ UINT16 queueTail; /**< / UINT16 ReadWriteablecnt [OS_QUEUE_N_RW]; /** LOS_DL_LIST readWriteList[OS_QUEUE_N_RW]; /** LOS_DL_LIST readWriteList[OS_QUEUE_N_RW]; /** * LOS_DL_LIST memList */ LOS_DL_LIST memList */ LOS_DL_LIST memList /**< memory node bidirectional linked list, compatible with CMSIS */} losqueuECB;

1.2 Queue common macro definitions

The number of queues that the system can create is defined by the macro LOSCFG_BASE_IPC_QUEUEID based on the development board, and the QUEUEID of each queue is of type UINT32. The queue queueId consists of two parts: count and index, which are at the high and low 16 bits respectively. When the queue is retrieved to the queue pool, the high 16 bits (count) of the queue queueID will be increased by 1, which can be used to represent the number of times the queue was created or deleted. The index value is [0,LOSCFG_BASE_IPC_QUEUE_LIMIT), which represents the number of each queue in the queue pool.

(1) The macro at (1) is used to split the number of digits of COUNT and INDEX, and the macro at (2) is used to update the queue number QueueID when the queue is deleted. It can be seen that the high 16-bit is COUNT and the low 16-bit is INDEX. ⑶ Gets the lowest 16 bits of the queue eid. (4) Get the number of times the corresponding queue was created and deleted according to queue queueID. — Gets the queue control block corresponding to the specified queue queueId from the queue pool

⑴ ⑴ #define SET_QUEUE_ID(count, 2) ⑴ #define SET_QUEUE_ID(count, 2) ⑴ #define SET_QUEUE_ID(count, 2) The index) (((count) < < QUEUE_SPLIT_BIT) | (index)) (3) # define GET_QUEUE_INDEX (queueId) ((queueId) & ((1 u < < QUEUE_SPLIT_BIT) ⑸ ⑸ #define GET_QUEUE_HANDLE(QUEUEID) ⑸ + define GET_QUEUE_HANDLE(QUEUEID) ⑸ + define GET_QUEUE_HANDLE(QUEUEID) (((LosQueueCB *)g_allQueue) + GET_QUEUE_INDEX(queueId))

In addition, the queue provides more important enumerations and macros related to queue read message operations. The type of read message operation on the queue is related to whether the first or last bit of the queue is written, so the type of operation is represented by a 2-bit number, with the higher 1 bit representing the first or last bit of the queue and the lower 1 bit representing the read or write. Definitions are as follows:

typedef enum { OS_QUEUE_READ = 0, OS_QUEUE_WRITE = 1, OS_QUEUE_N_RW = 2 } QueueReadWrite; typedef enum { OS_QUEUE_HEAD = 0, OS_QUEUE_TAIL = 1 } QueueHeadTail; #define OS_QUEUE_OPERATE_TYPE(ReadOrWrite, HeadOrTail) (((UINT32)(HeadOrTail) << 1) | (ReadOrWrite)) #define OS_QUEUE_READ_WRITE_GET(type) ((type) & 0x01U) #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) & 0x03U) #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)

2. Queue initialization

Queues are turned on by default in the kernel and can be turned off by the user via the LOSCFG_BASE_IPC_QUEUE macro. When the queue is turned on, call OqueueInit () in kernel\init\los_init.c to initialize the queue module at system startup. Next, let’s examine the queue initialization code.

⑴ Request memory for the queue. If the request fails, an error is returned. (2) Initialize G_FreequeList and maintain unused queues. ⑶ loop through each queue to initialize, specify index queueID for each queue node, and insert the queue node into G_FreequeUelist without using the queue biparticially linked list. As you can see from the code, the node hanging on the unused queue bidirectional linked list is the write blocking task linked list point for each queue control block. (4) If the queue query switch is turned on, the function OqueuedBginithook () is called to initialize.

LITE_OS_SEC_TEXT_INIT UINT32 OsQueueInit(VOID) { LosQueueCB *queueNode = NULL; UINT32 index; UINT32 size; size = LOSCFG_BASE_IPC_QUEUE_LIMIT * sizeof(LosQueueCB); ⑴ g_allQueue = (losqueueECB *)LOS_MemAlloc(m_aucSysMem0, size); ⑴ g_allQueue = (losqueueECB *)LOS_MemAlloc(m_aucSysMem0, size); if (g_allQueue == NULL) { return LOS_ERRNO_QUEUE_NO_MEMORY; } (VOID)memset_s(g_allQueue, size, 0, size); 2 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]); } ⑷ if (OsQueueDbgInitHook()! = LOS_OK) { return LOS_ERRNO_QUEUE_NO_MEMORY; } return LOS_OK; }

3. Queue common operations

3.1 Queue creation

There are two functions to create a queue: los_queueCreateStatic () and los_queueCreate (). The difference between the two is whether the memory space for the queue message is user-created or system created automatically. The former is available only when the macro LOSCFG_QUEUE_STATIC_ALLOCATION is enabled and the user allocates queue memory space, while the latter creates queue memory space dynamically when the queue is created. Let’s look at the passing of two functions: QueueName is the name of the queue and is not actually used. LEN is the length of the queue message, QUEUEID is the queue number, and FLAGS remains unused. MAXMsgSize is the maximum size of each message in the queue. For statically created queues, there are also two parameters that represent the address pointer QUEUEEM for the memory space of the user-created queue and the memory size MEMSIZE.

Let’s examine the code that creates the queue. See static create first, the improvement in function called OsQueueCreateParameterCheck () to check the parameters, and to validate the incoming memory space, to ensure that is large enough to put the message queue, which maxMsgSize + sizeof (UINT32) message maximum size, An additional four bytes, the last four bytes of the message, are used to hold the actual length of the message. Then we call the function OqueueCreateInternal () at ⑶ to complete the queue creation. (4) dynamically apply memory for the queue, and then call the function osqueueCreateInternal () to complete the queue creation. The two functions call the same internal creation queue function, osqueueCreateInternal ().

#ifdef LOSCFG_QUEUE_STATIC_ALLOCATION LITE_OS_SEC_TEXT_INIT UINT32 LOS_QueueCreateStatic(CHAR *queueName, UINT16 len, UINT32 *queueId, UINT32 flags, UINT16 maxMsgSize, VOID *queueMem, UINT16 memSize) { UINT32 ret; UINT16 msgSize; (VOID)queueName; (VOID)flags; (1) ret = OsQueueCreateParameterCheck (len, queueId, maxMsgSize); if (ret ! = LOS_OK) { return ret; } if (queueMem == NULL) { return LOS_ERRNO_QUEUE_CREAT_PTR_NULL; } ⑵ msgSize = maxmsgSize + sizeof(UINT32);} ⑵ msgSize = maxmsgSize + sizeof(UINT32); if (memSize < ((UINT32)msgSize * len)) { return LOS_ERRNO_QUEUE_CREATE_NO_MEMORY; } ⑶ return osqueueCreateInternal (Len, queueID, msgSize, queueEM, OS_QUEUE_ALLOC_STATIC); } #endif LITE_OS_SEC_TEXT_INIT UINT32 LOS_QueueCreate(CHAR *queueName, UINT16 len, UINT32 *queueId, UINT32 flags, UINT16 maxMsgSize) { UINT32 ret; UINT8 *queueMem = NULL; UINT16 msgSize; (VOID)queueName; (VOID)flags; ret = OsQueueCreateParameterCheck(len, queueId, maxMsgSize); if (ret ! = LOS_OK) { return ret; } msgSize = maxMsgSize + sizeof(UINT32); ⑷ queueEM = (UINT8 *)LOS_MemAlloc(m_aucSysMem1, (UINT32)len * msgSize); if (queueMem == NULL) { return LOS_ERRNO_QUEUE_CREATE_NO_MEMORY; } ret = OsQueueCreateInternal(len, queueId, msgSize, queueMem, OS_QUEUE_ALLOC_DYNAMIC); if (ret ! = LOS_OK) { (VOID)LOS_MemFree(m_aucSysMem1, queueMem); return ret; } return LOS_OK; }

Let’s look at the internal function that creates the queue, osqueueCreateInternal (). (1) If there is no available queue, call the function osqueueCheckHook (). This function needs to turn on the queue switch. This function will be analyzed in the following series. (2) If g_freequeUelist is not empty, then get the first available queue node, then remove it from the bivarially linked list g_freequeUelist, then call the macro GET_QUEUE_LIST to get LOSQUEUECB * QUEUECB, initialize the queue information created. (3) If g_freequeUelist is not empty, then get the first available queue node from the bivarially linked list g_freequeUelist, then get LOSQUEUECB * QUEUECB, initialize the queue information created. QueueState, QueueState, QueueState, QueueState, QueueEmType, QueueSize, QueueSize, QueueSize, QueueSize, QueueSize, QueueSize, QueueHandle, QueueState, QueueEmType, ReadWriteableNT [OS_QUEUE_WRITE] = queue message length len, queueHead, queueTail, queueTail = 0

ReadWriteList [OS_QUEUE_READ] is used to read messages that are blocked on this queue. ReadWriteList is used to read messages on this list. ReadWriteList [OS_QUEUE_WRITE] initializes the bidirectional linked list. Write tasks blocking on this queue will hang on this list. Initialize bi-linked list.memlist, which is used when the CMSIS compatible macro LOSCFG_COMPAT_CMSIS is turned on. ⑷ Assign a value to the output parameter * queueID, which is used by subsequent programs to perform other operations on the queue.

LITE_OS_SEC_TEXT_INIT STATIC UINT32 OsQueueCreateInternal(UINT16 len, UINT32 *queueId, UINT16 msgSize, UINT8 *queue, UINT8 queueMemType) { LosQueueCB *queueCB = NULL; LOS_DL_LIST *unusedQueue = NULL; UINT32 intSave; SCHEDULER_LOCK(intSave); ⑴ if (los_listEmpty (&g_freequeUelist)) {SCHEDULER_UNLOCK(intSave); OsQueueCheckHook(); return LOS_ERRNO_QUEUE_CB_UNAVAILABLE; } ⑵ unusedQueue = LOS_DL_LIST_FIRST(&g_freequeList); LOS_ListDelete(unusedQueue); queueCB = GET_QUEUE_LIST(unusedQueue); queueCB->queueLen = len; queueCB->queueSize = msgSize; queueCB->queueHandle = queue; queueCB->queueState = OS_QUEUE_INUSED; queueCB->queueMemType = queueMemType; queueCB->readWriteableCnt[OS_QUEUE_READ] = 0; queueCB->readWriteableCnt[OS_QUEUE_WRITE] = len; queueCB->queueHead = 0; queueCB->queueTail = 0; (3) LOS_ListInit (& queueCB - > readWriteList [OS_QUEUE_READ]); LOS_ListInit(&queueCB->readWriteList[OS_QUEUE_WRITE]); LOS_ListInit(&queueCB->memList); OsQueueDbgUpdateHook(queueCB->queueId, OsCurrTaskGet()->taskEntry); SCHEDULER_UNLOCK(intSave); (4) * queueId = queueCB - > queueId; LOS_TRACE(QUEUE_CREATE, *queueId, len, msgSize - sizeof(UINT32), (UINTPTR)queue, queueMemType); return LOS_OK; }

3.2 Queue deletion

We can use the function LOS_QUEUEDELETE (UINT32 QUEUEID) to delete the queue. Let’s look at the source code to see how to delete the queue.

(1) If the queueID of the queue exceeds LOSCFG_BASE_IPC_QUEUE_LIMIT, the error code is returned. If the queue number is OK, get the queue control block LOSQUEUECB * QUEUECB. Where the queue queueID to be deleted matches, or where the queue to be deleted is not in use, jump to the error label QUEUE_END ‘for processing. (3) If the list of blocking read and blocking write tasks of the queue is not empty, or the linked list of memory nodes is not empty, it is not allowed to delete, jump to the error label for processing. (4) Check whether the number of readable and writable queues is wrong.

— get the memory space of the queue. If the memory is dynamically created, then call the function LOS_MemFree(). ⑹ Set.queueState to unused OS_QUEUE_UNUSED, set the queue number.queueID, and insert the queue node into the unused biparticially linked list g_freequeUelist.

LITE_OS_SEC_TEXT_INIT UINT32 LOS_QueueDelete(UINT32 queueId) { LosQueueCB *queueCB = NULL; UINT8 *queue = NULL; UINT32 intSave; UINT32 ret = LOS_OK; ⑴ if (GET_QUEUE_INDEX(queueeid) >= LOSCFG_BASE_IPC_QUEUE_LIMIT) {return LOS_ERRNO_QUEUE_NOT_FOUND; ⑴ if (GET_QUEUE_INDEX(queueeid) >= LOSCFG_BASE_IPC_QUEUE_LIMIT); } queueCB = (LosQueueCB *)GET_QUEUE_HANDLE(queueId); LOS_TRACE(QUEUE_DELETE, queueId, queueCB->queueState, queueCB->readWriteableCnt[OS_QUEUE_READ]); SCHEDULER_LOCK(intSave); 2 the if ((queueCB - > queueId! = queueId) || (queueCB->queueState == OS_QUEUE_UNUSED)) { ret = LOS_ERRNO_QUEUE_NOT_CREATE; goto QUEUE_END; } (3) 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 ((queueECB-> ReadWriteableNT [OS_QUEUE_WRITE] + queueECB-> ReadWriteableNT [OS_QUEUE_READ]) + queueECB-> ReadWriteableNT [OS_QUEUE_READ]) = queueCB->queueLen) { ret = LOS_ERRNO_QUEUE_IN_TSKWRITE; goto QUEUE_END; } ⑸ queue = queueECB-> queueHandle; [6] queueCB - > queueHandle = NULL; queueCB->queueState = OS_QUEUE_UNUSED; queueCB->queueId = SET_QUEUE_ID(GET_QUEUE_COUNT(queueCB->queueId) + 1, GET_QUEUE_INDEX(queueCB->queueId)); OsQueueDbgUpdateHook(queueCB->queueId, NULL); LOS_ListTailInsert(&g_freeQueueList, &queueCB->readWriteList[OS_QUEUE_WRITE]); SCHEDULER_UNLOCK(intSave); If (queueECB-> queueEmType == OS_QUEUE_ALLOC_DYNAMIC) {⑺ ret = LOS_MemFree(m_aucSysMem1, (VOID *)queue); if (queueECB-> queueEmType == OS_QUEUE_ALLOC_DYNAMIC) {⑺ ret = LOS_MemFree(m_aucSysMem1, (VOID *)queue); } return ret; QUEUE_END: SCHEDULER_UNLOCK(intSave); return ret; }

Let’s take a look at queue reads and writes. There are two things to note:

  • (1) Reading and writing at the head and back of the team

Only the first queue read is supported, otherwise it is not a queue. In addition to the normal back-of-queue writing, there is also a queue-cutting mechanism that supports writing from the front of the queue.

  • (2) Queue message data content

There are two types of messages written to the queue, namely write by address and write by value (with copy). The type of the write, the need to pair according to the corresponding type to read.

Queue read interfaces are classified as follows:

3.3 Queue reading

We know that there are two queue read methods. The los_queueRead () function that reads by reference takes the message address value bufferAddr as a value, and further calls the los_queueReadCopy () function that reads by value.

LITE_OS_SEC_TEXT UINT32 LOS_QueueRead(UINT32 queueId, VOID *bufferAddr, UINT32 bufferSize, UINT32 timeout)
{
    return LOS_QueueReadCopy(queueId, bufferAddr, &bufferSize, timeout);
}

Look at the los_queueReadCopy () function. (1) Check the incoming parameters, the queue number cannot exceed the limit, and the passed pointer cannot be empty. Cannot read queue in interrupt if timeout is not zero and would block. ⑵ The operation type indicates the queue first reads, and then calls the function osQueueOperate () to operate on the queue further.

LITE_OS_SEC_TEXT UINT32 LOS_QueueReadCopy(UINT32 queueId, VOID *bufferAddr, UINT32 *bufferSize, UINT32 timeout) { UINT32 ret; UINT32 operateType; (1) ret = OsQueueReadParameterCheck (queueId, bufferAddr, bufferSize, timeout); if (ret ! = LOS_OK) { return ret; } ⑵ operateType = OS_QUEUE_OPERATE_TYPE(OS_QUEUE_READ, OS_QUEUE_HEAD);} ⑵ operateType = os_queue_type (OS_QUEUE_READ, OS_QUEUE_HEAD); return OsQueueOperate(queueId, operateType, bufferAddr, bufferSize, timeout); }

Let’s take a closer look at the function osQueueOperate (), which is a generic wrapper that calls both read and write. Let’s examine the function using the read queue as an example. (1) The operation type of the queue is read. ⑵ Call the function OqueueOperateParamCheck () to check the parameters. The check queue is the queue in use, and check the size of read and write messages. (3) If the number of readables is 0, if the number of readables cannot be read, if the number of readables is zero, the error code is returned. If the current lock task is scheduled, jump out of the function execution. Otherwise, a read message that puts the current task into the queue blocks the queue and triggers the task scheduling, with subsequent code temporarily not executing. If the number of readables is not zero, you can continue reading by subtracting the number of readables by one, and then continue executing the ⑺ code read queue.

After the read queue blocks out or the queue can be read, continue to execute the code at ⑸. If timeout occurs, the queue can not be read, change the task state, jump out of the function execution. If the queue is ready to be read, continue with the code where ⑺ reads the queue. ⑻ after reading the queue successfully, if there is a task blocking in the write queue, then get the first task in the blocked linked list ResumedTask, and then call the wake function OstaskWake () to put the task to be recovered into the ready queue, triggering a task scheduling. If there are no blocking tasks, increase the number of writable tasks by 1.

UINT32 OsQueueOperate(UINT32 queueId, UINT32 operateType, VOID *bufferAddr, UINT32 *bufferSize, UINT32 timeout) { LosQueueCB *queueCB = (LosQueueCB *)GET_QUEUE_HANDLE(queueId); LosTaskCB *resumedTask = NULL; UINT32 ret; ⑴ UINT32 readWrite = OS_QUEUE_READ_WRITE_GET(operateType); ⑴ UINT32 readWrite = OS_QUEUE_READ_WRITE_GET(operateType); UINT32 intSave; LOS_TRACE(QUEUE_RW, queueId, queueCB->queueSize, *bufferSize, operateType, queueCB->readWriteableCnt[OS_QUEUE_READ], queueCB->readWriteableCnt[OS_QUEUE_WRITE], timeout); SCHEDULER_LOCK(intSave); ⑵ Ret = osQueueOperateParamCheck (queueECB, queueId, operateType, BufferSize); ⑵ Ret = osQueueOperateParamCheck (queueECB, queueId, operateType, BufferSize); if (ret ! = LOS_OK) { goto QUEUE_END; } ⑶ if (timeout == LOS_NO_WAIT) {ret = OS_QUEUE_IS_READ(operateType)?  LOS_ERRNO_QUEUE_ISEMPTY : LOS_ERRNO_QUEUE_ISFULL; goto QUEUE_END; } if (! OsPreemptableInSched()) { ret = LOS_ERRNO_QUEUE_PEND_IN_LOCK; goto QUEUE_END; } ⑷ OSTASKWAIT (&QUEUECB-> ReadWriteList [ReadWrite], OS_TASK_STATUS_PEND, timeout); OsSchedResched(); SCHEDULER_UNLOCK(intSave); SCHEDULER_LOCK(intSave); ⑸ if (OsCurrTaskGet()->taskStatus & OS_TASK_STATUS_TIMEOUT) {OsCurrTaskGet()->taskStatus &= ~OS_TASK_STATUS_TIMEOUT; ret = LOS_ERRNO_QUEUE_TIMEOUT; goto QUEUE_END; }} else {⑹ queueECB-> ReadWriteableNT [ReadWrite]--; } ⑺ osQueueBufferOperate (queueECB, OperateType, BufferAddr, BufferSize); Being the if (! LOS_ListEmpty(&queueCB->readWriteList[!readWrite])) { resumedTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&queueCB->readWriteList[!readWrite])); OsTaskWake(resumedTask, OS_TASK_STATUS_PEND); SCHEDULER_UNLOCK(intSave); LOS_MpSchedule(OS_MP_CPU_ALL); LOS_Schedule(); return LOS_OK; } else {requestECB -> ReadWriteAbleCnt [! ReadWrite]++; } QUEUE_END: SCHEDULER_UNLOCK(intSave); return ret; }

Let’s move on to see how the OqueueBufferOperate () function reads the queue. The switch-case statement on the ⑴ retrieves the operation location. For the case where the ⑵ header is read, first get the read position QueuePosition. And 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 plus 1. For a ⑶ header write, if the current head node position.queueHead plus 1 equals the length of the queue message, and the head node position.queueHead is set to the length of the queue message minus 1, otherwise the head node position.queueHead minus 1. Then, get the position QueuePosition to write to. In the case of a write to the end of ⑷, get the write location QueuePosition first. And then, if the current tail-position — queueTail plus 1 equals the length of the queue message, the tail-position — queueTail is set to 0, otherwise plus 1.

⑸ Gets queue message node QueueNode based on the retrieved queue read location. The last 4 bytes of each message node store the length of the message. We first get the length of the message, msgDataSize, and then run the ⑺ code to read the message content to bufferAddr. Next, see how to write the queue message by writing the content of the message to queueNode, then executing the content of the message length to queueNode + queueECB -> queuesize-sizeof (UINT32), that is, the last 4 bytes of each message node.

STATIC VOID OsQueueBufferOperate(LosQueueCB *queueCB, UINT32 operateType, VOID *bufferAddr, UINT32 *bufferSize) { UINT8 *queueNode = NULL; UINT32 msgDataSize; UINT16 queuePosition; /* switch (OS_QUEUE_OPERATE_GET(operateType)) {case OS_QUEUE_READ_HEAD: queuePosition = queueCB->queueHead; ⑵ ⑵ (queueECB ->queueHead + 1) == queueECB ->queueLen)? (queueCB->queueHead = 0) : (queueCB->queueHead++); break; Case OS_QUEUE_WRITE_HEAD: ⑶ (queueecb-> queueHead == 0)? (queueCB->queueHead = queueCB->queueLen - 1) : (--queueCB->queueHead); queuePosition = queueCB->queueHead; break; Case OS_QUEUE_WRITE_TAIL: ⑷ queuePosition = queueECB-> queueTail; ((queueCB->queueTail + 1) == queueCB->queueLen) ? (queueCB->queueTail = 0) : (queueCB->queueTail++); break; default: /* read tail, reserved. */ PRINT_ERR("invalid queue operate type! \n"); return; (QueuePosition * (QueuePosition * (QueueCEB-> QueueHandle))]); If (OS_QUEUE_IS_READ(operateType)) {if (memcpy_s(&msgdatasize, sizeof(UINT32)); queueNode + queueCB->queueSize - sizeof(UINT32), sizeof(UINT32)) ! = EOK) { PRINT_ERR("get msgdatasize failed\n"); return; } ⑺ if (memcpy_s(BufferAddr, * BufferSize, queueNode, msgDataSize)! = EOK) { PRINT_ERR("copy message to buffer failed\n"); return; } *bufferSize = msgDataSize; } else {⑻ if (memcpy_s(queueNode, queueECB -> queuesSize, bufferAddr, *bufferSize)! = EOK) { PRINT_ERR("store message failed\n"); return; } margin (memcpy_s(queueNode + queueCEb0 queueSize - sizeof(UINT32), sizeof(UINT32), bufferSize, sizeof(UINT32))! = EOK) { PRINT_ERR("store message size failed\n"); return; }}}

3.4 Queue write

We know that there are four queue write methods, two end-of-queue writes and two head-queue writes, which include a message written by reference address and a message written by value. Los_queueWrite () calls los_queueWriteCopy (), los_queueWriteHead () calls los_queueWriteHeadCopy (), and los_queueWriteHeadCopy () calls los_queueWriteHeadCopy (). A further call is made to the function osQueueOperate () that we analyzed earlier.

summary

This article takes you to analyze the source code of LiteOS queue module, including queue structure, queue pool initialization, queue creation and deletion, read and write messages, etc. Thanks for reading, if you have any question, advice, can leave a message to us: https://gitee.com/LiteOS/Lite… . In order to more easily find LiteOS code warehouse, it is suggested that visit https://gitee.com/LiteOS/LiteOS, pay attention to Watch, thumb up Star, and the Fork to their accounts, thank you.

Click on the attention, the first time to understand Huawei cloud fresh technology ~