diff --git a/include/openthread/message.h b/include/openthread/message.h index 987f6ee46..f6f31402d 100644 --- a/include/openthread/message.h +++ b/include/openthread/message.h @@ -238,7 +238,6 @@ typedef struct } otMessageQueue; /** - * * Initialize the message queue. * * This function MUST be called once and only once for a `otMessageQueue` instance before any other `otMessageQueue` @@ -262,6 +261,18 @@ void otMessageQueueInit(otMessageQueue *aQueue); */ otError otMessageQueueEnqueue(otMessageQueue *aQueue, otMessage *aMessage); +/** + * This function adds a message at the head/front of the given message queue. + * + * @param[in] aQueue A pointer to the message queue. + * @param[in] aMessage The message to add. + * + * @retval OT_ERROR_NONE Successfully added the message to the queue. + * @retval OT_ERROR_ALREADY The message is already enqueued in a queue. + * + */ +otError otMessageQueueEnqueueAtHead(otMessageQueue *aQueue, otMessage *aMessage); + /** * This function removes a message from the given message queue. * diff --git a/src/core/api/message_api.cpp b/src/core/api/message_api.cpp index d1e5a1742..c5e0e4cc9 100644 --- a/src/core/api/message_api.cpp +++ b/src/core/api/message_api.cpp @@ -123,6 +123,13 @@ otError otMessageQueueEnqueue(otMessageQueue *aQueue, otMessage *aMessage) return queue->Enqueue(*message); } +otError otMessageQueueEnqueueAtHead(otMessageQueue *aQueue, otMessage *aMessage) +{ + Message *message = static_cast(aMessage); + MessageQueue *queue = static_cast(aQueue); + return queue->Enqueue(*message, MessageQueue::kQueuePositionHead); +} + otError otMessageQueueDequeue(otMessageQueue *aQueue, otMessage *aMessage) { Message *message = static_cast(aMessage); diff --git a/src/core/common/message.cpp b/src/core/common/message.cpp index 65cabe99d..49a2c518c 100644 --- a/src/core/common/message.cpp +++ b/src/core/common/message.cpp @@ -811,29 +811,32 @@ MessageQueue::MessageQueue(void) SetTail(NULL); } -void MessageQueue::AddToList(uint8_t aList, Message &aMessage) +void MessageQueue::AddToList(uint8_t aList, Message &aMessage, QueuePosition aPosition) { - Message *head; - assert((aMessage.Next(aList) == NULL) && (aMessage.Prev(aList) == NULL)); if (GetTail() == NULL) { aMessage.Next(aList) = &aMessage; aMessage.Prev(aList) = &aMessage; + + SetTail(&aMessage); } else { - head = GetTail()->Next(aList); + Message *head = GetTail()->Next(aList); aMessage.Next(aList) = head; aMessage.Prev(aList) = GetTail(); head->Prev(aList) = &aMessage; GetTail()->Next(aList) = &aMessage; - } - SetTail(&aMessage); + if (aPosition == kQueuePositionTail) + { + SetTail(&aMessage); + } + } } void MessageQueue::RemoveFromList(uint8_t aList, Message &aMessage) @@ -862,7 +865,7 @@ Message *MessageQueue::GetHead(void) const return (GetTail() == NULL) ? NULL : GetTail()->Next(MessageInfo::kListInterface); } -otError MessageQueue::Enqueue(Message &aMessage) +otError MessageQueue::Enqueue(Message &aMessage, QueuePosition aPosition) { otError error = OT_ERROR_NONE; @@ -870,7 +873,9 @@ otError MessageQueue::Enqueue(Message &aMessage) aMessage.SetMessageQueue(this); - AddToList(MessageInfo::kListInterface, aMessage); + AddToList(MessageInfo::kListInterface, aMessage, aPosition); + + // Any new message is always added to the end of the `AllMessageQueue` list. aMessage.GetMessagePool()->GetAllMessagesQueue()->AddToList(MessageInfo::kListAll, aMessage); exit: diff --git a/src/core/common/message.hpp b/src/core/common/message.hpp index ec7020648..d6b56265d 100644 --- a/src/core/common/message.hpp +++ b/src/core/common/message.hpp @@ -810,6 +810,18 @@ class MessageQueue : public otMessageQueue friend class PriorityQueue; public: + + /** + * This enumeration represents a position (head or tail) in the queue. This is used to specify where a new message + * should be added in the queue. + * + */ + enum QueuePosition + { + kQueuePositionHead, ///< Indicates the head (front) of the list. + kQueuePositionTail, ///< Indicates the tail (end) of the list. + }; + /** * This constructor initializes the message queue. * @@ -833,7 +845,19 @@ public: * @retval OT_ERROR_ALREADY The message is already enqueued in a list. * */ - otError Enqueue(Message &aMessage); + otError Enqueue(Message &aMessage) { return Enqueue(aMessage, kQueuePositionTail); } + + /** + * This method adds a message at a given position (head/tail) of the list. + * + * @param[in] aMessage The message to add. + * @param[in] aPosition The position (head or tail) where to add the message. + * + * @retval OT_ERROR_NONE Successfully added the message to the list. + * @retval OT_ERROR_ALREADY The message is already enqueued in a list. + * + */ + otError Enqueue(Message &aMessage, QueuePosition aPosition); /** * This method removes a message from the list. @@ -874,13 +898,23 @@ private: void SetTail(Message *aMessage) { mData = aMessage; } /** - * This method adds a message to a list. + * This method adds a message to the end of the list. * * @param[in] aListId The list to add @p aMessage to. * @param[in] aMessage The message to add to @p aListId. * */ - void AddToList(uint8_t aListId, Message &aMessage); + void AddToList(uint8_t aListId, Message &aMessage) { AddToList(aListId, aMessage, kQueuePositionTail); } + + /** + * This method adds a message at a give position (head or tail) of the list. + * + * @param[in] aListId The list to add @p aMessage to. + * @param[in] aMessage The message to add to @p aListId. + * @param[in] aPosition The position where to add the message. + * + */ + void AddToList(uint8_t aListId, Message &aMessage, QueuePosition aPosition); /** * This method removes a message from a list. diff --git a/tests/unit/test_message_queue.cpp b/tests/unit/test_message_queue.cpp index 102dd7641..7aa06deff 100644 --- a/tests/unit/test_message_queue.cpp +++ b/tests/unit/test_message_queue.cpp @@ -103,6 +103,13 @@ void TestMessageQueue(void) SuccessOrQuit(messageQueue.Dequeue(*msg[0]), "MessageQueue::Dequeue() failed.\n"); VerifyMessageQueueContent(messageQueue, 0); + // Enqueue 1 message at head and remove it + SuccessOrQuit(messageQueue.Enqueue(*msg[0], ot::MessageQueue::kQueuePositionHead), + "MessageQueue::Enqueue() failed.\n"); + VerifyMessageQueueContent(messageQueue, 1, msg[0]); + SuccessOrQuit(messageQueue.Dequeue(*msg[0]), "MessageQueue::Dequeue() failed.\n"); + VerifyMessageQueueContent(messageQueue, 0); + // Enqueue 5 messages SuccessOrQuit(messageQueue.Enqueue(*msg[0]), "MessageQueue::Enqueue() failed.\n"); VerifyMessageQueueContent(messageQueue, 1, msg[0]); @@ -131,18 +138,45 @@ void TestMessageQueue(void) SuccessOrQuit(messageQueue.Dequeue(*msg[4]), "MessageQueue::Dequeue() failed.\n"); VerifyMessageQueueContent(messageQueue, 2, msg[1], msg[2]); - // Add after removes + // Add after remove SuccessOrQuit(messageQueue.Enqueue(*msg[0]), "MessageQueue::Enqueue() failed.\n"); VerifyMessageQueueContent(messageQueue, 3, msg[1], msg[2], msg[0]); SuccessOrQuit(messageQueue.Enqueue(*msg[3]), "MessageQueue::Enqueue() failed.\n"); VerifyMessageQueueContent(messageQueue, 4, msg[1], msg[2], msg[0], msg[3]); - // Remove all messages + // Remove from middle SuccessOrQuit(messageQueue.Dequeue(*msg[2]), "MessageQueue::Dequeue() failed.\n"); VerifyMessageQueueContent(messageQueue, 3, msg[1], msg[0], msg[3]); + + // Add to head + SuccessOrQuit(messageQueue.Enqueue(*msg[2], ot::MessageQueue::kQueuePositionHead), + "MessageQueue::Enqueue() failed.\n"); + VerifyMessageQueueContent(messageQueue, 4, msg[2], msg[1], msg[0], msg[3]); + + // Remove from head + SuccessOrQuit(messageQueue.Dequeue(*msg[2]), "MessageQueue::Dequeue() failed.\n"); + VerifyMessageQueueContent(messageQueue, 3, msg[1], msg[0], msg[3]); + + // Remove from head SuccessOrQuit(messageQueue.Dequeue(*msg[1]), "MessageQueue::Dequeue() failed.\n"); VerifyMessageQueueContent(messageQueue, 2, msg[0], msg[3]); + + // Add to head + SuccessOrQuit(messageQueue.Enqueue(*msg[1], ot::MessageQueue::kQueuePositionHead), + "MessageQueue::Enqueue() failed.\n"); + VerifyMessageQueueContent(messageQueue, 3, msg[1], msg[0], msg[3]); + + // Add to tail + SuccessOrQuit(messageQueue.Enqueue(*msg[2], ot::MessageQueue::kQueuePositionTail), + "MessageQueue::Enqueue() failed.\n"); + VerifyMessageQueueContent(messageQueue, 4, msg[1], msg[0], msg[3], msg[2]); + + // Remove all messages. SuccessOrQuit(messageQueue.Dequeue(*msg[3]), "MessageQueue::Dequeue() failed.\n"); + VerifyMessageQueueContent(messageQueue, 3, msg[1], msg[0], msg[2]); + SuccessOrQuit(messageQueue.Dequeue(*msg[1]), "MessageQueue::Dequeue() failed.\n"); + VerifyMessageQueueContent(messageQueue, 2, msg[0], msg[2]); + SuccessOrQuit(messageQueue.Dequeue(*msg[2]), "MessageQueue::Dequeue() failed.\n"); VerifyMessageQueueContent(messageQueue, 1, msg[0]); SuccessOrQuit(messageQueue.Dequeue(*msg[0]), "MessageQueue::Dequeue() failed.\n"); VerifyMessageQueueContent(messageQueue, 0); @@ -222,14 +256,14 @@ void TestMessageQueueOtApis(void) VerifyMessageQueueContentUsingOtApi(&queue, 1, msg[0]); SuccessOrQuit(otMessageQueueEnqueue(&queue, msg[1]), "Failed to enqueue a message to otMessageQueue.\n"); VerifyMessageQueueContentUsingOtApi(&queue, 2, msg[0], msg[1]); - SuccessOrQuit(otMessageQueueEnqueue(&queue, msg[2]), "Failed to enqueue a message to otMessageQueue.\n"); - VerifyMessageQueueContentUsingOtApi(&queue, 3, msg[0], msg[1], msg[2]); + SuccessOrQuit(otMessageQueueEnqueueAtHead(&queue, msg[2]), "Failed to enqueue a message to otMessageQueue.\n"); + VerifyMessageQueueContentUsingOtApi(&queue, 3, msg[2], msg[0], msg[1]); SuccessOrQuit(otMessageQueueEnqueue(&queue, msg[3]), "Failed to enqueue a message to otMessageQueue.\n"); - VerifyMessageQueueContentUsingOtApi(&queue, 4, msg[0], msg[1], msg[2], msg[3]); + VerifyMessageQueueContentUsingOtApi(&queue, 4, msg[2], msg[0], msg[1], msg[3]); // Remove elements and check the content SuccessOrQuit(otMessageQueueDequeue(&queue, msg[1]), "Failed to dequeue a message from otMessageQueue.\n"); - VerifyMessageQueueContentUsingOtApi(&queue, 3, msg[0], msg[2], msg[3]); + VerifyMessageQueueContentUsingOtApi(&queue, 3, msg[2], msg[0], msg[3]); SuccessOrQuit(otMessageQueueDequeue(&queue, msg[0]), "Failed to dequeue a message from otMessageQueue.\n"); VerifyMessageQueueContentUsingOtApi(&queue, 2, msg[2], msg[3]); SuccessOrQuit(otMessageQueueDequeue(&queue, msg[3]), "Failed to dequeue a message from otMessageQueue.\n");