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