UCOSIII summary ----- message queue

This section summarizes the kernel objects of the operating system UCOSIII -------- > message queues
Question what is message queuing?
Message queue is a structure whose type is OS_Q
typedef struct os_q OS_Q;
Expand to see structure members
struct os_q { /* Message Queue /
OS_ Obj_ Type type/ Variables that record the type of kernel/
CPU_ Char nameptr/ Record pointer to message queue name/
OS_ Pend_ List pendlist/* Wait list structure variable/
OS_ MSG_ Q msgq/ Message list structure variable*/
};

The following briefly describes the role of important members of the message queue structure
The function of PendList waiting list is very clear according to the semaphore section. The waiting list section is used to wait for semaphores when there are tasks, but it is found that no semaphores can be obtained. You can only mount the task in the waiting list, and then wait for the semaphore to arrive, so you can remove the task from the waiting list, and then continue to execute the task function. This section is also used to mount tasks, Just wait for the message queue in the task function. If no message is found in the message list MsgQ, mount the task to the waiting list and wait for the information.

The message list MsgQ is also a structure, which is the root node of the message
typedef struct os_msg_q OS_MSG_Q;
struct os_msg_q { /* OS_MSG_Q */
OS_MSG inptr/ Point to the next OS to be inserted into the queue_ Pointer to MSG*/
OS_MSG outptr/ Point to the next OS to be extracted from the queue_ Pointer to MSG/
OS_ MSG_ Qty nbrentriessize/ Variable - stores the maximum number of messages/
OS_ MSG_ Qty nbrentries/ Variable - records the number of current messages/
OS_MSG_QTY NbrEntriesMax; / Peak number of entries in the queue */
};

The structure function of message list MsgQ is very straightforward:
Case 1 is that if no task is waiting for messages, the published messages are temporarily placed on the message list MsgQ. Each packet of messages is first integrated into the OS_ In the MSG structure, future messages represent the OS_ A structure of the data type MSG
typedef struct os_msg OS_MSG;
struct os_msg {
OS_ MSG nextptr/ Pointer to insert into message list MsgQ*/
Void msgptr/ Pointer to store message content/
OS_ MSG_ Size msgsize/ Variable to store message content length/
CPU_TS MsgTS; / Time stamp of when message was sent */
};
The integration here is to assign values to the OS_ In the member corresponding to MSG, and then the OS_ The *NextPtr pointer in the MSG is inserted or deleted into the message list MsgQ through the one-way linked list

Case 2 if a message is found in a task publishing message that a task is waiting in the waiting list, first remove the task in the waiting list from the waiting list, and finally assign the message pointer and message length to the two members of the task control block on which the task is mounted on the waiting list. After the task switches to access the two members of the task control block, the message content can be read out
struct os_tcb {
#if OS_MSG_EN > 0u
Void msgptr/ Message content pointer/
OS_ MSG_ Size msgsize/ Message content length variable*/
#endif
};

I believe there are still some mysteries about the message queue

Question 1 message OS_ What principle is MSG inserted into message list MsgQ based on

Problem 2 when a task waits for a message, it is found that there is a message OS on the message list_ How does MSG get messages from MsgQ

Question 3 if a task publishes a message and finds that there are tasks waiting in the waiting list, first remove the tasks in the waiting list from the waiting list, and finally assign the message pointer and message length to the two members of the task control block on which the task is mounted on the waiting list. After the task switches to access the two members of the task control block, you can read the contents of the message. What is the specific operation

Answer question 1

In the publish message function OSQPost(); The opt option is used to determine the insertion policy
opt

  • OS_OPT_POST_FIFO inserts a message into the queue end pointer OS of the message list MsgQ_ MSG *inptr;
  • OS_OPT_POST_LIFO inserts a message into the pre queue pointer OS of the message list MsgQ_ MSG *outptr;

Answer question 2

Pre queue pointer OS from message list MsgQ_ MSG *outptr; Get message
Wait a minute. You can see from the code of the insert and delete functions of the message list

See the picture for the final insertion effect

See the actual operation of the code
Insert message to message list function is OS_ Msgqput (os\u msg\u Q *p\u msg\u Q, / / message list pointer
Void *p_ Void, / / message content pointer
OS_ MSG_ Size MSG_ Size, // Message content length
OS_ Opt opt, // Insert options
CPU_TS ts,
OS_ Err *p_ ERR) // Error value returned

void  OS_MsgQPut (OS_MSG_Q     *p_msg_q,
                  void         *p_void,
                  OS_MSG_SIZE   msg_size,
                  OS_OPT        opt,
                  CPU_TS        ts,
                  OS_ERR       *p_err)
{
    OS_MSG  *p_msg; /*Message pointer */
    OS_MSG  *p_msg_in;

    if (p_msg_q->NbrEntries >= p_msg_q->NbrEntriesSize) {   //The number of messages in a message queue cannot exceed the preset maximum
       *p_err = OS_ERR_Q_MAX;                               /*Return error message queue full   */
        return;
    }

    if (OSMsgPool.NbrFree == (OS_MSG_QTY)0) {               /*Whether the message pool is empty */
       *p_err = OS_ERR_MSG_POOL_EMPTY;                    
        return;
    }

 /*Message pool is not empty */
 /*Notice here p_msg is a pointer. There is no memory space for the pointer, and the memory space is provided by the message pool*/
    p_msg             = OSMsgPool.NextPtr;                  /*Remove a memory block from the message pool to p_msg pointer if it has a pointer, it is the OS_MSG messages open up space  */
    OSMsgPool.NextPtr = p_msg->NextPtr;
    OSMsgPool.NbrFree--;
    OSMsgPool.NbrUsed++;
    if (OSMsgPool.NbrUsedMax < OSMsgPool.NbrUsed) {
        OSMsgPool.NbrUsedMax = OSMsgPool.NbrUsed;
    }
    if (p_msg_q->NbrEntries == (OS_MSG_QTY)0) {    /*If the message in the message queue is empty, this message is now inserted into the message queue as the first message  */
        p_msg_q->InPtr         = p_msg;                     
        p_msg_q->OutPtr        = p_msg;
        p_msg_q->NbrEntries    = (OS_MSG_QTY)1;
    } 
    else {                                                //Message queue has messages
     if ((opt & OS_OPT_POST_LIFO) == OS_OPT_POST_FIFO){  /*Insert the current message into the end of the message queue*/
            p_msg_in           = p_msg_q->InPtr;            /* FIFO */
            p_msg_in->NextPtr  = p_msg;
            p_msg->NextPtr     = (OS_MSG *)0;
            p_msg_q->InPtr     = p_msg;                    /*The end of line pointer InPtr moved to the right  */    
        } else {                                            //Insert the current message in front of the message queue
            p_msg->NextPtr     = p_msg_q->OutPtr;           /* LIFO */
            p_msg_q->OutPtr    = p_msg;                     /*The pointer OutPtr in front of the team moved to the right  */ 
        }
        p_msg_q->NbrEntries++;                              //Number of messages in the message queue plus 1
    }
    if (p_msg_q->NbrEntriesMax < p_msg_q->NbrEntries) {
        p_msg_q->NbrEntriesMax = p_msg_q->NbrEntries;
    }
    
    p_msg->MsgPtr  = p_void;                                /*Fill in the message content for this message
    p_msg->MsgSize = msg_size;                              //Fill in the message size for this message
    p_msg->MsgTS   = ts;
   *p_err          = OS_ERR_NONE;
}

The function to remove messages from the message list is *os_ Msgqget (os\u msg\u Q *p\u msg\u Q, / / message queue pointer
OS_ MSG_ Size *p_ MSG_ Size, / / message size variable pointer
CPU_TS *p_ts,
OS_ Err *p_ ERR) //f returned error value
Look at the code

void  *OS_MsgQGet (OS_MSG_Q     *p_msg_q,
                   OS_MSG_SIZE  *p_msg_size,
                   CPU_TS       *p_ts,
                   OS_ERR       *p_err)
{
    OS_MSG  *p_msg;
    void    *p_void;

    if (p_msg_q->NbrEntries == (OS_MSG_QTY)0) {   // If the message queue has no messages
       *p_msg_size = (OS_MSG_SIZE)0;              //Return message length is 0
        if (p_ts != (CPU_TS *)0) {                         
           *p_ts  = (CPU_TS  )0;                 
        }
       *p_err = OS_ERR_Q_EMPTY;                   //The error type is "no message in the queue"
        return ((void *)0);
    }
         /* If the message queue has messages */ 
    p_msg           = p_msg_q->OutPtr;            //Note: the message is extracted from the exit end of the message list, so the message is the pre queue pointer OS of the message list MsgQ_ MSG *outptr fetch message 
    p_void          = p_msg->MsgPtr;              //Extract message content
   *p_msg_size      = p_msg->MsgSize;             //Extract message length
    if (p_ts != (CPU_TS *)0) {
       *p_ts  = p_msg->MsgTS;
    }
    p_msg_q->OutPtr = p_msg->NextPtr;             //Modify the outgoing pointer of the queue
    if (p_msg_q->OutPtr == (OS_MSG *)0) {         //If the queue has no messages
        p_msg_q->InPtr      = (OS_MSG   *)0;      //Clear out of line pointer
        p_msg_q->NbrEntries = (OS_MSG_QTY)0;      //Number of reset messages
    } else {                                      //If the queue still has messages
        p_msg_q->NbrEntries--;                    //Number of messages queued minus 1     
    }
		
		 /* After extracting the message information from the message queue, release the message back to the message pool for further use */
    p_msg->NextPtr    = OSMsgPool.NextPtr;                  /*//Return message control block to free list              */
    OSMsgPool.NextPtr = p_msg;                                
    OSMsgPool.NbrFree++;                                      //Number of available messages in the message pool plus 1
    OSMsgPool.NbrUsed--;                                      //Number of used messages in the message pool minus 1
   *p_err             = OS_ERR_NONE;                          //Error type is "no error"
    return (p_void);
}

What's more, what about the message pool
First, we insert a message OS_MSG to the message list MsgQ to build the message OS_ The MSG structure requires a little memory. Let's look at the above function to define a message OS_MSG is basically a pointer. It must have a point. This point must be the first address of a memory space. The message pool is dedicated to the message OS_MSG opens up memory space,
What is the message pool like and when is it initialized

#define OS_CFG_MSG_POOL_SIZE 100u
OS_ MSG oscfg_ Msgpool [os\cfg\msg\pool\u size]// 100 message pools defined
Typedef struct OS_ MSG_ Pool OS_ MSG_ Pool// Message pool list
struct os_msg_pool { /* OS_MSG POOL */
OS_ MSG *nextptr/* Message pool pointer/
OS_ MSG_ Qty nbrfree/ Variable that stores the number of messages in the message pool/
OS_ MSG_ Qty nbrused/ Store how many messages are currently used in the message pool/
OS_MSG_QTY NbrUsedMax; / Peak number of messages used */
};
OS_ MSG_ Pool osmsgpool// Message pool list
It can be seen from the above that the message pool list is loaded with 100 message pools that have been defined for a long time, and inserted into the message pool list OSMsgPool through the *NextPtr pointer of the message pool

Initialize the function osinit (os_err *p_err) in UCOSIII; The message pool is initialized by listing

Look at the code

OS_MSG  * const  OSCfg_MsgPoolBasePtr  = (OS_MSG    *)&OSCfg_MsgPool[0];  //OSCfg_MsgPoolBasePtr points to the first message pool
void  OSInit (OS_ERR  *p_err)
{
  
#if (OS_MSG_EN) > 0u                                    
    OS_MsgPoolInit(p_err);   //Message pool list initialization
    if (*p_err != OS_ERR_NONE) {
        return;
    }
#endif

}

void  OS_MsgPoolInit (OS_ERR  *p_err) 
{
#ifdef OS_SAFETY_CRITICAL
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return;
    }
#endif

#if OS_CFG_ARG_CHK_EN > 0u
    if (OSCfg_MsgPoolBasePtr == (OS_MSG *)0) {
       *p_err = OS_ERR_MSG_POOL_NULL_PTR;
        return;
    }
    if (OSCfg_MsgPoolSize == (OS_MSG_QTY)0) {
       *p_err = OS_ERR_MSG_POOL_EMPTY;
        return;
    }
#endif

    OS_MsgPoolCreate(OSCfg_MsgPoolBasePtr, 
                     OSCfg_MsgPoolSize);  //The message pool list is used to mount 100 message pool functions, which is not expanded here. In fact, it is not difficult to understand that 100 nodes are inserted
    //Message pool list remaining member initialization                  
    OSMsgPool.NextPtr    =  OSCfg_MsgPoolBasePtr; //OSCfg_MsgPoolBasePtr points to the first message pool
    OSMsgPool.NbrFree    =  OSCfg_MsgPoolSize;
    OSMsgPool.NbrUsed    = (OS_MSG_QTY)0;
    OSMsgPool.NbrUsedMax = (OS_MSG_QTY)0;
   *p_err                =  OS_ERR_NONE;
}


Answer question 3

From the send message function OSQPost(); And wait message function OSQPend(); Internal parsing of this function

Void *osqpend (os_q p_q, / Message queue pointer/
OS_ Tick timeout, / Number of ticks required to wait for a message/
OS_ Opt opt, / Wait for message option*/
OS_ MSG_ Size P_ MSG_ Size, / Variable that returns the length of the message content*/
CPU_TS *p_ts,
OS_ Err p_ ERR) / Error value returned*/

According to the combination of opt and timeout, there are many ways to wait for messages
Opt
OS_OPT_PEND_BLOCKING means that when the specified message is invalid, the task is suspended to wait for the message
OS_ Opt_ Pend_ Non_ When the blocking message is invalid, the task returns directly. The task will not be suspended and the current task will continue to be executed

timeout=0 + Opt=OS_OPT_PEND_BLOCKING If the message cannot be received immediately, the task is suspended to wait for the message and block the task until the message is released. If the semaphore can be obtained immediately by waiting for the message, the task is not blocked
timeout>0 + Opt=OS_OPT_PEND_BLOCKING If the message can be obtained immediately after waiting for the message, the task will not be blocked. If the semaphore cannot be received immediately, the task will be suspended to wait for the message and block the task. After waiting for the timeout ticks, the message will not be received, and the task will continue to run. If the semaphore can only be received at these ticks, the task will also be suspended
timeout no matter how many + Opt=OS_OPT_PEND_NON_BLOCKING Whether the message can be received immediately or not, the task will continue to run without blocking or suspending

Note: this function cannot be used in interrupts. There are blocking factors in this function. Interrupts cannot be blocked for a long time, otherwise they will enter the hardware interrupt program and run away. "

Look at the code

void  *OSQPend (OS_Q         *p_q,
                OS_TICK       timeout,
                OS_OPT        opt,
                OS_MSG_SIZE  *p_msg_size,
                CPU_TS       *p_ts,
                OS_ERR       *p_err)
{
    OS_PEND_DATA  pend_data;
    void         *p_void;
    CPU_SR_ALLOC();
//Parameter check code omitted
    CPU_CRITICAL_ENTER();
		/************improtance function***************/
    p_void = OS_MsgQGet(&p_q->MsgQ,                     /* This function gets a message from the message queue*/
                        p_msg_size,                    //This variable stores the length of the message content     
                        p_ts,
                        p_err);
    if (*p_err == OS_ERR_NONE) {                            //If the message is obtained successfully
        CPU_CRITICAL_EXIT();
        return (p_void);                            /*The returned message content is the first address of the message queue*/
    }

		/*  If the message is not obtained successfully             */
    if ((opt & OS_OPT_PEND_NON_BLOCKING) != (OS_OPT)0) {    /* If no blocking task is selected */
        CPU_CRITICAL_EXIT();
       *p_err = OS_ERR_PEND_WOULD_BLOCK;      /* The returned error type is OS_ERR_PEND_WOULD_BLOCK*/
        return ((void *)0);                  //The parameter returned here is 0, which actually allows you to return to continue the task
    } else {                                 //If blocking task is selected
        if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) {            /*This is when the scheduler is locked   */
            CPU_CRITICAL_EXIT();
           *p_err = OS_ERR_SCHED_LOCKED;                                       
            return ((void *)0);
        }
    }
            //Blocking task - the scheduler is not locked
    OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT();                 
    OS_Pend(&pend_data,                                     /*Block the current task and wait for the message queue */
           (OS_PEND_OBJ *)((void *)p_q), //The current task is removed from the ready list and inserted into the waiting list and beat list 
            OS_TASK_PEND_ON_Q,
            timeout);
    OS_CRITICAL_EXIT_NO_SCHED();
    OSSched();                          /*Find the task with the highest priority in the current ready state and switch to this task */

    /* The current task (getting messages from the message queue) continues to run */
    CPU_CRITICAL_ENTER();                                 //Off interrupt
    switch (OSTCBCurPtr->PendStatus) {                 //Process according to the waiting status of the current running task
        case OS_STATUS_PEND_OK:                        //If the waiting status is normal (note here is the key point) 
             p_void     = OSTCBCurPtr->MsgPtr;          //Extract messages from the task control block (placed at the time of Publishing)
            *p_msg_size = OSTCBCurPtr->MsgSize;           //Extract message size
             if (p_ts  != (CPU_TS *)0) {                  //If p_ts not empty
                *p_ts   =  OSTCBCurPtr->TS;               //Get the timestamp when the task waits for the message
             }
            *p_err      = OS_ERR_NONE;                    //Error type is "no error"
             break;                                       //Jump out

        case OS_STATUS_PEND_ABORT:                        //If the wait is aborted
             p_void     = (void      *)0;                 //The returned message content is empty
            *p_msg_size = (OS_MSG_SIZE)0;                 //Return message size is 0
             if (p_ts  != (CPU_TS *)0) {                  //If p_ts not empty
                *p_ts   =  OSTCBCurPtr->TS;               //Gets the timestamp when the wait is aborted
             }
            *p_err      = OS_ERR_PEND_ABORT;              //The error type is "wait aborted"
             break;                                       //Jump out

        case OS_STATUS_PEND_TIMEOUT:                      //If the wait times out
             p_void     = (void      *)0;                 //The returned message content is empty
            *p_msg_size = (OS_MSG_SIZE)0;                 //Return message size is 0
             if (p_ts  != (CPU_TS *)0) {                  //If p_ts not empty
                *p_ts   = (CPU_TS  )0;                    //Clear p_ts
             }
            *p_err      = OS_ERR_TIMEOUT;                 //The error type is "wait timeout"
             break;                                       //Jump out

        case OS_STATUS_PEND_DEL:                          //If the waiting kernel object is deleted
             p_void     = (void      *)0;                 //The returned message content is empty
            *p_msg_size = (OS_MSG_SIZE)0;                 //Return message size is 0
             if (p_ts  != (CPU_TS *)0) {                  //If p_ts not empty
                *p_ts   =  OSTCBCurPtr->TS;               //Get the timestamp when the object is deleted
             }
            *p_err      = OS_ERR_OBJ_DEL;                 //The error type is "waiting for the object to be deleted"
             break;                                       //Jump out

        default:                                          //If the waiting state exceeds the expectation
             p_void     = (void      *)0;                 //The returned message content is empty
            *p_msg_size = (OS_MSG_SIZE)0;                 //Return message size is 0
            *p_err      = OS_ERR_STATUS_INVALID;          //Error type is "illegal state"
             break;                                       //Jump out
    }
    CPU_CRITICAL_EXIT();                                  //On / off
    return (p_void);                                      //Return message content
}

Briefly describe the operation process
First on OS_MsgQGet(); Function to find out whether there is any message in the message list. If there is any message, exit the function. If there is no message, if you choose to wait for messages indefinitely, you can go through the OS_Pend(); Function to insert a task into the waiting list, and then the task switches
Until the message is received
OS on switch_ Status_ Pend_ The OK option indicates that the message was received correctly
case OS_STATUS_PEND_OK: / / if the wait status is normal (note here is the key point)
P_ Void = ostcbcurptr->msgptr// Extract messages from the task control block (placed at the time of Publishing)
*P_ MSG_ Size = ostcbcurptr->msgsize// Extract message size
It can be seen from this that the message is extracted through the two members of the task control block of the task handle. As for when to send the message function to these two members

Message sending function OSQPost()

Void osqpost (os_q *p_q, / / message queue pointer
Void *p_ Void, / / message content pointer
OS_ MSG_ Size MSG_ Size, / / message content length variable
OS_ Opt opt, / / publish message options
OS_ Err *p_ ERR)// Return error value

There are many ways to send messages according to opt

opt Corresponding function
1,OS_OPT_POST_FIFO The released message is put in the message list queue end pointer *InPrt. When it is found that there is no task waiting for a message in the waiting list, it will take the message from the message list until there is a task waiting for a message; On the contrary, if there is a task waiting message in the waiting list, the message will be directly sent to the first task in the waiting list
2,OS_OPT_POST_LIFO Put the published message in front of the message list queue pointer *OutPrt when it is found that there is no task waiting for a message in the waiting list, until there is a task waiting for a message, and then take the message from the message list; On the contrary, if there is a task waiting message in the waiting list, the message will be directly sent to the first task in the waiting list
3,OS_OPT_POST_FIFO + OS_OPT_POST_ALL The released message is put in the message list queue end pointer *InPrt. When it is found that there is no task waiting for a message in the waiting list, it will take the message from the message list until there is a task waiting for a message; On the contrary, if the waiting list has a task waiting message, the message will be directly sent to all tasks in the waiting list
4,OS_OPT_POST_LIFO + OS_OPT_POST_ALL Put the published message in front of the message list queue pointer *OutPrt when it is found that there is no task waiting for a message in the waiting list, until there is a task waiting for a message, and then take the message from the message list; On the contrary, if the waiting list has a task waiting message, the message will be directly sent to all tasks in the waiting list
5,OS_OPT_POST_FIFO + OS_OPT_POST_NO_SCHED The released message is put in the message list queue end pointer *InPrt. When it is found that there is no task waiting for a message in the waiting list, it will take the message from the message list until there is a task waiting for a message; On the contrary, if there is a task waiting message in the waiting list, the message will be directly sent to the first task in the waiting list, but the task scheduling will not be performed, and the current task will continue to run
6,OS_OPT_POST_LIFO + OS_OPT_POST_NO_SCHED Put the published message in front of the message list queue pointer *OutPrt when it is found that there is no task waiting for a message in the waiting list, until there is a task waiting for a message, and then take the message from the message list; On the contrary, if there is a task waiting message in the waiting list, the message will be directly sent to the first task in the waiting list, but the task scheduling will not be performed, and the current task will continue to run
7,OS_OPT_POST_FIFO + OS_OPT_POST_ALL + OS_OPT_POST_NO_SCHED The released message is put in the message list queue end pointer *InPrt. When it is found that there is no task waiting for a message in the waiting list, it will take the message from the message list until there is a task waiting for a message; On the contrary, if there is a task waiting message in the waiting list, the message will be directly sent to all tasks in the waiting list, but the task scheduling will not be performed, and the current task will continue to run
8,OS_OPT_POST_FIFO + OS_OPT_POST_ALL + OS_OPT_POST_NO_SCHED Put the published message in front of the message list queue pointer *OutPrt when it is found that there is no task waiting for a message in the waiting list, until there is a task waiting for a message, and then take the message from the message list; On the contrary, if there is a task waiting message in the waiting list, the message will be directly sent to all tasks in the waiting list, but the task scheduling will not be performed, and the current task will continue to run

Note: 1 – 4 options do not select OS_OPT_POST_NO_SCHED means that if there are tasks waiting for messages in the waiting list, the current task directly publishes messages to one or more tasks in the waiting list, and then performs task switching. However, if the task that publishes messages has higher priority than the task that waits for messages, even if the task is switched, it should switch back to the original task, which is equivalent to continuing to run the current task without task scheduling; Otherwise, the task with low priority will be switched to the task waiting for messages

Look at the code

void  OSQPost (OS_Q         *p_q,
               void         *p_void,
               OS_MSG_SIZE   msg_size,
               OS_OPT        opt,
               OS_ERR       *p_err)
{
    CPU_TS  ts;

 /* Parameter check code omitted  */
#if OS_CFG_ISR_POST_DEFERRED_EN > 0u
    if (OSIntNestingCtr > (OS_NESTING_CTR)0) { 
        OS_IntQPost((OS_OBJ_TYPE)OS_OBJ_TYPE_Q,            /*This function is used by interrupt level to send messages  */
                    (void      *)p_q,
                    (void      *)p_void,
                    (OS_MSG_SIZE)msg_size,
                    (OS_FLAGS   )0,
                    (OS_OPT     )opt,
                    (CPU_TS     )ts,
                    (OS_ERR    *)p_err);
        return;
    }
#endif

		/*********************improtance funtion*********************************/
    OS_QPost(p_q,    /* This function is used to send messages at the task level  */
             p_void,
             msg_size,
             opt,
             ts,
             p_err);
}

The main content is OS_QPost(); function

void  OS_QPost (OS_Q         *p_q,
                void         *p_void,
                OS_MSG_SIZE   msg_size,
                OS_OPT        opt,
                CPU_TS        ts,
                OS_ERR       *p_err)
{
    OS_OBJ_QTY     cnt;
    OS_OPT         post_type;
    OS_PEND_LIST  *p_pend_list;
    OS_PEND_DATA  *p_pend_data;
    OS_PEND_DATA  *p_pend_data_next;
    OS_TCB        *p_tcb;
    CPU_SR_ALLOC();



    OS_CRITICAL_ENTER();
    p_pend_list = &p_q->PendList;                    //Get the waiting list of the queue              
if (p_pend_list->NbrEntries == (OS_OBJ_QTY)0) {  /*NbrEntries=0 (Description no task is waiting for a message) */
        if ((opt & OS_OPT_POST_LIFO) == (OS_OPT)0) {        /*Publish messages to the end of the queue  */
            post_type = OS_OPT_POST_FIFO; 
        } else {                                            //Publish messages to the front of the queue
            post_type = OS_OPT_POST_LIFO;
        }
        OS_MsgQPut(&p_q->MsgQ,                              /*//Put the message on the message queue */
                   p_void,
                   msg_size,
                   post_type,
                   ts,
                   p_err);
        OS_CRITICAL_EXIT();
        return;                                            //Return, execution completed
        
/* If a task is waiting for the queue, it indicates that a task is waiting for a message */
    if ((opt & OS_OPT_POST_ALL) != (OS_OPT)0) {          /*If you want to publish the message to all waiting tasks */
        cnt = p_pend_list->NbrEntries;                   /*Get the number of waiting tasks */
    } else {                                             //If you want to publish a message to a waiting task
        cnt = (OS_OBJ_QTY)1;                             /*The number of tasks to process is 1 */
    }
    p_pend_data = p_pend_list->HeadPtr;                   //Get the header of the wait list (first task)
    while (cnt > 0u) {                                    //Publish one by one according to the number of tasks to be published
        p_tcb            = p_pend_data->TCBPtr;
        p_pend_data_next = p_pend_data->NextPtr;
        OS_Post((OS_PEND_OBJ *)((void *)p_q),              //Post message to task  
                p_tcb,
                p_void,
                msg_size,
                ts);
        p_pend_data = p_pend_data_next;
        cnt--;
    }
    OS_CRITICAL_EXIT_NO_SCHED();
    if ((opt & OS_OPT_POST_NO_SCHED) == (OS_OPT)0) {        //If "do not schedule tasks after publishing" is not selected
        OSSched();                                          /*task scheduling */
    }
   *p_err = OS_ERR_NONE;                                    //Error type is "no error"
}
void  OS_Post (OS_PEND_OBJ  *p_obj,
               OS_TCB       *p_tcb,
               void         *p_void,
               OS_MSG_SIZE   msg_size,
               CPU_TS        ts)
{
    switch (p_tcb->TaskState) {
 //Code omission
        case OS_TASK_STATE_PEND:
        case OS_TASK_STATE_PEND_TIMEOUT:
             if (p_tcb->PendOn == OS_TASK_PEND_ON_MULTI) {       //Wait for multiple kernel objects (here, the embedded message queue and embedded message semaphore are executed)
                 OS_Post1(p_obj,                                
                          p_tcb,
                          p_void,
                          msg_size,
                          ts);
             } else {                                            //Message queue execution
#if (OS_MSG_EN > 0u)
                 p_tcb->MsgPtr  = p_void;                    /*Put the contents of the message into the task control block*/
                 p_tcb->MsgSize = msg_size;               /*Put message size into task control block   */
#endif
                 p_tcb->TS      = ts;
             }
             if (p_obj != (OS_PEND_OBJ *)0) {                    //Waiting kernel object is not empty
                 OS_PendListRemove(p_tcb);                 /*Delete the waiting task in the waiting list */
//Code omission
             }
             OS_TaskRdy(p_tcb); /*If the wait is limited, the task in the clock beat list should be deleted and the task is in the ready state*/
             p_tcb->TaskState  = OS_TASK_STATE_RDY;              //Task status is ready
             p_tcb->PendStatus = OS_STATUS_PEND_OK;              /*The status flag of task waiting is o */
             p_tcb->PendOn     = OS_TASK_PEND_ON_NOTHING;        /*Waiting kernel object is empty  */
             break;
 //Code omission         
             }
             p_tcb->TaskState  = OS_TASK_STATE_SUSPENDED;
             p_tcb->PendStatus = OS_STATUS_PEND_OK;              /* Clear pend status                                 */
             p_tcb->PendOn     = OS_TASK_PEND_ON_NOTHING;        /* Indicate no longer pending                        */
             break;

        default:
             break;
    }
}

Briefly describe the sending process
If there is no task waiting for messages in the waiting list, put the published messages on the message list through the OS_MsgQPut() function: if there is a task in the waiting list, publish the message to the task in the waiting list through the OS_Post() function
On OS_ Of the post() function
switch options
case OS_TASK_STATE_PEND:
case OS_TASK_STATE_PEND_TIMEOUT:
#if (OS_MSG_EN > 0u)
P_ Tcb->msgptr = P_ Void/ Put the contents of the message into the task control block/
P_ Tcb->msgsize = MSG_ Size/* Put message size into task control block*/
#endif
The message reflected in this code is that the task of the waiting list is through the task control block

Overall summary

Tags: Operating System

Posted by mynameisbob on Wed, 01 Jun 2022 00:52:41 +0530