Parsing the second hem of the QueueMail interface of Hongmeng kernel message queue

Posted by ron814 on Sat, 18 Sep 2021 10:48:03 +0200

Abstract: This paper leads you to analyze the source code of the two interfaces of QueueMail of the queue module of Hongmeng light kernel.

This article is shared from Huawei cloud community< Hongmeng light kernel M core source code analysis series 13 (Continued) message queue QueueMail interface >, author: zhushy.

I have analyzed the source code of Queue before, and learned about Queue initialization, Queue creation, deletion, Queue read and write, etc. The Queue also provides two interfaces, OsQueueMailAlloc and OsQueueMailFree. A Queue can be associated with a static memory pool. When a task applies for a memory block from the static memory pool, if it fails to apply, the task will be inserted into the memory blocking linked list of the Queue. When other tasks release memory, the task will be allocated a memory block.

Next, take a detailed look at the source code of these two interfaces.

1. Queue structure definition

1.1 definition of queue structure

Let's recall the definition of queue structure in the file kernel \ include \ LOS_ The queue control block structure defined in queue. H is LosQueueCB, and the structure source code is as follows. We need to look at the member variable memList. When the task does not apply to the free memory block from the static memory pool associated with the queue, it will insert the task into the memList memory blocking list, then schedule and switch the task. When other tasks release the free memory block to the static memory pool, the task applies for the free memory block, removes the task from the memlist memory blocking linked list, inserts it into the task ready queue, and triggers task scheduling.

typedef struct {
    UINT8 *queue;      /**< Pointer to queue memory space */
    UINT16 queueState; /**< Usage status of the queue */
    UINT16 queueLen;   /**< Queue length, i.e. number of messages */
    UINT16 queueSize;  /**< Message node size */
    UINT16 queueID;    /**< Queue number  */
    UINT16 queueHead;  /**< Header node location */
    UINT16 queueTail;  /**< Message tail node location */
    UINT16 readWriteableCnt[OS_READWRITE_LEN]; /**< 2 Dimension group, number of readable and writable messages, 0: readable, 1: writable */
    LOS_DL_LIST readWriteList[OS_READWRITE_LEN]; /**< 2 Dimensional bidirectional linked list array, bidirectional linked list blocking read and write tasks, 0: read linked list, 1: write linked list */
    LOS_DL_LIST memList; /**< Memory node bidirectional linked list */
} LosQueueCB;

2. Source code analysis of QueueMail interface

2.1 OsQueueMailAlloc interface

We can use the function VOID *OsQueueMailAlloc(UINT32 queueID, VOID *mailPool, UINT32 timeOut) to apply for free memory from the static memory pool associated with the queue. Let's see how to apply for memory by analyzing the source code. The function requires three parameters. queueID is the number of a queue in use, * mailPool is the address of the static memory pool associated with the queue, timeOut is the timeOut, and the value is [0,LOS_WAIT_FOREVER]. The interface function returns the requested memory address or NULL.

(1) start to verify the parameters, and (2) obtain the queue control structure queueCB according to the queue number, and then verify whether the queue is in use. (3) call the static memory allocation function Los at_ Memboxalloc obtains a free memory block, and then the obtained memory address is not NULL. Return the memory block address, otherwise execute subsequent codes. (4) obtain the currently running task control structure at (5), add the current task to the memory blocking linked list queueCB - > memlist of the queue at (5), and then trigger task scheduling.

After other tasks call OsQueueMailFree to release memory, the above blocked task will obtain the memory block, or exit the blocking list due to timeout and schedule the operation, and then start executing the statements at (6). (7) indicates that the task did not get the memory block because of the timeout. It jumps to the END tag and returns a NULL memory address. (8) indicates that the memory block has been obtained, set the msg of the task to NULL, and return the address of the obtained memory block.

LITE_OS_SEC_TEXT VOID *OsQueueMailAlloc(UINT32 queueID, VOID *mailPool, UINT32 timeOut)
{
    VOID *mem = (VOID *)NULL;
    UINT32 intSave;
    LosQueueCB *queueCB = (LosQueueCB *)NULL;
    LosTaskCB *runTsk = (LosTaskCB *)NULL;

⑴  if (queueID >= LOSCFG_BASE_IPC_QUEUE_LIMIT) {
        return NULL;
    }

    if (mailPool == NULL) {
        return NULL;
    }

    if (timeOut != LOS_NO_WAIT) {
        if (OS_INT_ACTIVE) {
            return NULL;
        }
    }

    intSave = LOS_IntLock();
⑵  queueCB = GET_QUEUE_HANDLE(queueID);
    if (queueCB->queueState == OS_QUEUE_UNUSED) {
        goto END;
    }

⑶  mem = LOS_MemboxAlloc(mailPool);
    if (mem == NULL) {
        if (timeOut == LOS_NO_WAIT) {
            goto END;
        }

⑷      runTsk = (LosTaskCB *)g_losTask.runTask;
⑸      OsSchedTaskWait(&queueCB->memList, timeOut);
        LOS_IntRestore(intSave);
        LOS_Schedule();

⑹      intSave = LOS_IntLock();
        if (runTsk->taskStatus & OS_TASK_STATUS_TIMEOUT) {
⑺          runTsk->taskStatus &= (~OS_TASK_STATUS_TIMEOUT);
            goto END;
        } else {
            /* When enters the current branch, means the current task already got a available membox,
             * so the runTsk->msg can not be NULL.
             */
⑻          mem = runTsk->msg;
            runTsk->msg = NULL;
        }
    }

END:
    LOS_IntRestore(intSave);
    return mem;
}

2.2 OsQueueMailFree

We can use the function UINT32 OsQueueMailFree(UINT32 queueID, VOID *mailPool, VOID *mailMem) to release free memory into the static memory pool associated with the queue. Let's see how to release memory by analyzing the source code. The function requires three parameters. queueID is the number of a queue in use, * mailPool is the address of the static memory pool associated with the queue, * mailMem represents the address of the memory block to be released. The return value type of this interface is an unsigned integer, indicating whether it is successful or error code.

(1) start to verify the parameters. (2) call the static memory release function Los at_ Memboxfree releases the free memory block. If the release fails, an error code is returned. (3) obtain the queue control structure queueCB according to the queue number, and then verify whether the queue is in use. After the memory is released successfully, if the memory blocking list of the queue is not empty and there are blocking tasks, execute (4). It gets the first task control structure from the blocking list, then calls the interface OsSchedTaskWake to remove the task from the blocking list and adds it to the task ready queue. (6) apply for a memory block from the static memory pool. If the application fails, an error code is returned. Otherwise, execute (7), assign the applied memory to the msg member variable of the task control structure, and then trigger the scheduling.

LITE_OS_SEC_TEXT UINT32 OsQueueMailFree(UINT32 queueID, VOID *mailPool, VOID *mailMem)
{
    VOID *mem = (VOID *)NULL;
    UINT32 intSave;
    LosQueueCB *queueCB = (LosQueueCB *)NULL;
    LosTaskCB *resumedTask = (LosTaskCB *)NULL;

⑴  if (queueID >= LOSCFG_BASE_IPC_QUEUE_LIMIT) {
        return LOS_ERRNO_QUEUE_MAIL_HANDLE_INVALID;
    }

    if (mailPool == NULL) {
        return LOS_ERRNO_QUEUE_MAIL_PTR_INVALID;
    }

    intSave = LOS_IntLock();

⑵  if (LOS_MemboxFree(mailPool, mailMem)) {
        LOS_IntRestore(intSave);
        return LOS_ERRNO_QUEUE_MAIL_FREE_ERROR;
    }

⑶  queueCB = GET_QUEUE_HANDLE(queueID);
    if (queueCB->queueState == OS_QUEUE_UNUSED) {
        LOS_IntRestore(intSave);
        return LOS_ERRNO_QUEUE_NOT_CREATE;
    }

⑷  if (!LOS_ListEmpty(&queueCB->memList)) {
⑸      resumedTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&queueCB->memList));
        OsSchedTaskWake(resumedTask);
⑹      mem = LOS_MemboxAlloc(mailPool);
        if (mem == NULL) {
            LOS_IntRestore(intSave);
            return LOS_ERRNO_QUEUE_NO_MEMORY;
        }
⑺      resumedTask->msg = mem;
        LOS_IntRestore(intSave);
        LOS_Schedule();
    } else {
        LOS_IntRestore(intSave);
    }
    return LOS_OK;
}

Summary

This paper leads you to analyze the source code of the two interfaces of QueueMail of the queue module of Hongmeng light kernel. Thank you for reading. If you have any questions or suggestions, you can leave a message to me. Thank you.

Click focus to learn about Huawei cloud's new technologies for the first time~

Topics: RabbitMQ data structure interface message queue