mirror of
https://github.com/espressif/openthread.git
synced 2026-06-05 21:14:49 +00:00
[message] change queues to use non-circular linked list (#11630)
This commit updates the `MessageQueue` and `PriorityQueue` implementations to use non-circular doubly linked lists instead of the previous circular ones. Using a non-circular list requires the queue to track the head element, but it simplifies common operations like getting the head and iterating over the messages. Particularly, `Message::GetNext()` now simply returns the `mNext` pointer. Previously, `Message` had to store a pointer to its `mQueue` within its `Metadata` to identify the tail of the queue and stop the iteration correctly. This commit also updates the unit tests. In particular, `test_priority_queue` is significantly enhanced to cover many scenarios, such as multiple messages with the same priority, and messages with different priorities being added and removed in various orders.
This commit is contained in:
committed by
GitHub
parent
5d1d380012
commit
c55098af5e
@@ -52,7 +52,7 @@ extern "C" {
|
||||
*
|
||||
* @note This number versions both OpenThread platform and user APIs.
|
||||
*/
|
||||
#define OPENTHREAD_API_VERSION (514)
|
||||
#define OPENTHREAD_API_VERSION (515)
|
||||
|
||||
/**
|
||||
* @addtogroup api-instance
|
||||
|
||||
@@ -400,7 +400,8 @@ int otMessageWrite(otMessage *aMessage, uint16_t aOffset, const void *aBuf, uint
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
void *mData; ///< Opaque data used by the implementation.
|
||||
void *mData; ///< Opaque data used by the implementation.
|
||||
void *mData2; ///< Opaque data used by the implementation.
|
||||
} otMessageQueue;
|
||||
|
||||
/**
|
||||
|
||||
@@ -122,12 +122,7 @@ int otMessageWrite(otMessage *aMessage, uint16_t aOffset, const void *aBuf, uint
|
||||
return aLength;
|
||||
}
|
||||
|
||||
void otMessageQueueInit(otMessageQueue *aQueue)
|
||||
{
|
||||
AssertPointerIsNotNull(aQueue);
|
||||
|
||||
aQueue->mData = nullptr;
|
||||
}
|
||||
void otMessageQueueInit(otMessageQueue *aQueue) { AsCoreType(aQueue).Clear(); }
|
||||
|
||||
void otMessageQueueEnqueue(otMessageQueue *aQueue, otMessage *aMessage)
|
||||
{
|
||||
@@ -148,11 +143,11 @@ otMessage *otMessageQueueGetHead(otMessageQueue *aQueue) { return AsCoreType(aQu
|
||||
|
||||
otMessage *otMessageQueueGetNext(otMessageQueue *aQueue, const otMessage *aMessage)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aQueue);
|
||||
|
||||
Message *next;
|
||||
|
||||
VerifyOrExit(aMessage != nullptr, next = nullptr);
|
||||
|
||||
VerifyOrExit(AsCoreType(aMessage).GetMessageQueue() == aQueue, next = nullptr);
|
||||
next = AsCoreType(aMessage).GetNext();
|
||||
|
||||
exit:
|
||||
|
||||
+135
-116
@@ -75,6 +75,7 @@ Message *MessagePool::Allocate(Message::Type aType, uint16_t aReserveHeader, con
|
||||
message->SetLinkSecurityEnabled(aSettings.IsLinkSecurityEnabled());
|
||||
message->SetLoopbackToHostAllowed(OPENTHREAD_CONFIG_IP6_ALLOW_LOOP_BACK_HOST_DATAGRAMS);
|
||||
message->SetOrigin(Message::kOriginHostTrusted);
|
||||
message->MarkAsNotInAQueue();
|
||||
|
||||
SuccessOrExit(error = message->SetPriority(aSettings.GetPriority()));
|
||||
SuccessOrExit(error = message->SetLength(0));
|
||||
@@ -98,7 +99,7 @@ Message *MessagePool::Allocate(Message::Type aType, uint16_t aReserveHeader)
|
||||
|
||||
void MessagePool::Free(Message *aMessage)
|
||||
{
|
||||
OT_ASSERT(aMessage->Next() == nullptr && aMessage->Prev() == nullptr);
|
||||
OT_ASSERT(!aMessage->IsInAQueue());
|
||||
|
||||
FreeBuffers(static_cast<Buffer *>(aMessage));
|
||||
}
|
||||
@@ -260,30 +261,6 @@ void Message::Free(void)
|
||||
Get<MessagePool>().Free(this);
|
||||
}
|
||||
|
||||
Message *Message::GetNext(void) const
|
||||
{
|
||||
Message *next;
|
||||
Message *tail;
|
||||
|
||||
if (GetMetadata().mInPriorityQ)
|
||||
{
|
||||
PriorityQueue *priorityQueue = GetPriorityQueue();
|
||||
VerifyOrExit(priorityQueue != nullptr, next = nullptr);
|
||||
tail = priorityQueue->GetTail();
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageQueue *messageQueue = GetMessageQueue();
|
||||
VerifyOrExit(messageQueue != nullptr, next = nullptr);
|
||||
tail = messageQueue->GetTail();
|
||||
}
|
||||
|
||||
next = (this == tail) ? nullptr : Next();
|
||||
|
||||
exit:
|
||||
return next;
|
||||
}
|
||||
|
||||
Error Message::SetLength(uint16_t aLength)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
@@ -871,16 +848,18 @@ bool Message::IsTimeSync(void) const
|
||||
#endif
|
||||
}
|
||||
|
||||
void Message::SetMessageQueue(MessageQueue *aMessageQueue)
|
||||
void Message::MarkAsNotInAQueue(void)
|
||||
{
|
||||
GetMetadata().mQueue = aMessageQueue;
|
||||
GetMetadata().mInPriorityQ = false;
|
||||
}
|
||||
// To indicate that a message is no longer in a queue, we set
|
||||
// its 'mPrev' pointer to point back to itself. This state is
|
||||
// unique and won't occur if the message is part of a queue. We
|
||||
// also set 'mNext' to 'nullptr' so that 'GetNext()' correctly
|
||||
// returns 'nullptr' for a dequeued message.
|
||||
|
||||
void Message::SetPriorityQueue(PriorityQueue *aPriorityQueue)
|
||||
{
|
||||
GetMetadata().mQueue = aPriorityQueue;
|
||||
GetMetadata().mInPriorityQ = aPriorityQueue != nullptr;
|
||||
Next() = nullptr;
|
||||
Prev() = this;
|
||||
|
||||
GetMetadata().mInPriorityQ = false;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
@@ -889,56 +868,61 @@ void Message::SetPriorityQueue(PriorityQueue *aPriorityQueue)
|
||||
void MessageQueue::Enqueue(Message &aMessage, QueuePosition aPosition)
|
||||
{
|
||||
OT_ASSERT(!aMessage.IsInAQueue());
|
||||
OT_ASSERT((aMessage.Next() == nullptr) && (aMessage.Prev() == nullptr));
|
||||
|
||||
aMessage.SetMessageQueue(this);
|
||||
aMessage.GetMetadata().mInPriorityQ = false;
|
||||
|
||||
if (GetTail() == nullptr)
|
||||
if (GetHead() == nullptr)
|
||||
{
|
||||
aMessage.Next() = &aMessage;
|
||||
aMessage.Prev() = &aMessage;
|
||||
aMessage.Next() = nullptr;
|
||||
aMessage.Prev() = nullptr;
|
||||
|
||||
SetHead(&aMessage);
|
||||
SetTail(&aMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
Message *head = GetTail()->Next();
|
||||
|
||||
aMessage.Next() = head;
|
||||
aMessage.Prev() = GetTail();
|
||||
|
||||
head->Prev() = &aMessage;
|
||||
GetTail()->Next() = &aMessage;
|
||||
|
||||
if (aPosition == kQueuePositionTail)
|
||||
switch (aPosition)
|
||||
{
|
||||
case kQueuePositionHead:
|
||||
aMessage.Next() = GetHead();
|
||||
aMessage.Prev() = nullptr;
|
||||
GetHead()->Prev() = &aMessage;
|
||||
SetHead(&aMessage);
|
||||
break;
|
||||
|
||||
case kQueuePositionTail:
|
||||
aMessage.Next() = nullptr;
|
||||
aMessage.Prev() = GetTail();
|
||||
GetTail()->Next() = &aMessage;
|
||||
SetTail(&aMessage);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MessageQueue::Dequeue(Message &aMessage)
|
||||
{
|
||||
OT_ASSERT(aMessage.GetMessageQueue() == this);
|
||||
OT_ASSERT((aMessage.Next() != nullptr) && (aMessage.Prev() != nullptr));
|
||||
if (&aMessage == GetHead())
|
||||
{
|
||||
SetHead(aMessage.Next());
|
||||
}
|
||||
|
||||
if (&aMessage == GetTail())
|
||||
{
|
||||
SetTail(GetTail()->Prev());
|
||||
|
||||
if (&aMessage == GetTail())
|
||||
{
|
||||
SetTail(nullptr);
|
||||
}
|
||||
SetTail(aMessage.Prev());
|
||||
}
|
||||
|
||||
aMessage.Prev()->Next() = aMessage.Next();
|
||||
aMessage.Next()->Prev() = aMessage.Prev();
|
||||
if (aMessage.Prev() != nullptr)
|
||||
{
|
||||
aMessage.Prev()->Next() = aMessage.Next();
|
||||
}
|
||||
|
||||
aMessage.Prev() = nullptr;
|
||||
aMessage.Next() = nullptr;
|
||||
if (aMessage.Next() != nullptr)
|
||||
{
|
||||
aMessage.Next()->Prev() = aMessage.Prev();
|
||||
}
|
||||
|
||||
aMessage.SetMessageQueue(nullptr);
|
||||
aMessage.MarkAsNotInAQueue();
|
||||
}
|
||||
|
||||
void MessageQueue::DequeueAndFree(Message &aMessage)
|
||||
@@ -983,86 +967,109 @@ void MessageQueue::AddQueueInfos(Info &aInfo, const Info &aOther)
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// PriorityQueue
|
||||
|
||||
const Message *PriorityQueue::FindFirstNonNullTail(Message::Priority aStartPriorityLevel) const
|
||||
const Message *PriorityQueue::FindTailForPriorityOrHigher(uint8_t aPriority) const
|
||||
{
|
||||
// Find the first non-`nullptr` tail starting from the given priority
|
||||
// level and moving forward (wrapping from priority value
|
||||
// `kNumPriorities` -1 back to 0).
|
||||
// This method finds the tail (last message entry in the list)
|
||||
// that has priority level that is greater than or equal to
|
||||
// `aPriority` and currently has messages in the queue.
|
||||
//
|
||||
// The `PriorityQueue` uses the `mTails` array to store pointers
|
||||
// to the last message for each priority level. If a specific
|
||||
// priority level has no messages, its corresponding `mTails`
|
||||
// entry will be `nullptr`.
|
||||
//
|
||||
// The method iterates from `aPriority` upwards through higher
|
||||
// priority levels, returning the first non-null tail pointer it
|
||||
// encounters.
|
||||
//
|
||||
// The returned `Message` pointer indicates where a new message
|
||||
// with `aPriority` should be inserted: it should be placed
|
||||
// immediately after this returned message. If `nullptr` is
|
||||
// returned, it means the new message will be the first of its
|
||||
// priority level (or any higher priority) in the queue, and
|
||||
// should be placed at the head.
|
||||
|
||||
const Message *tail = nullptr;
|
||||
uint8_t priority;
|
||||
|
||||
priority = static_cast<uint8_t>(aStartPriorityLevel);
|
||||
|
||||
do
|
||||
for (uint8_t priority = aPriority; priority < Message::kNumPriorities; priority++)
|
||||
{
|
||||
if (mTails[priority] != nullptr)
|
||||
tail = mTails[priority];
|
||||
|
||||
if (tail != nullptr)
|
||||
{
|
||||
tail = mTails[priority];
|
||||
break;
|
||||
}
|
||||
|
||||
priority = PrevPriority(priority);
|
||||
} while (priority != aStartPriorityLevel);
|
||||
}
|
||||
|
||||
return tail;
|
||||
}
|
||||
|
||||
const Message *PriorityQueue::GetHead(void) const
|
||||
{
|
||||
return Message::NextOf(FindFirstNonNullTail(Message::kPriorityLow));
|
||||
}
|
||||
|
||||
const Message *PriorityQueue::GetHeadForPriority(Message::Priority aPriority) const
|
||||
{
|
||||
const Message *head;
|
||||
const Message *previousTail;
|
||||
const Message *head = nullptr;
|
||||
uint8_t priority = static_cast<uint8_t>(aPriority);
|
||||
|
||||
if (mTails[aPriority] != nullptr)
|
||||
if (mTails[priority] == nullptr)
|
||||
{
|
||||
previousTail = FindFirstNonNullTail(static_cast<Message::Priority>(PrevPriority(aPriority)));
|
||||
|
||||
OT_ASSERT(previousTail != nullptr);
|
||||
|
||||
head = previousTail->Next();
|
||||
head = nullptr;
|
||||
}
|
||||
else if (mHead->GetPriority() == aPriority)
|
||||
{
|
||||
head = mHead;
|
||||
}
|
||||
else
|
||||
{
|
||||
head = nullptr;
|
||||
const Message *previousTail = FindTailForPriorityOrHigher(priority + 1);
|
||||
|
||||
OT_ASSERT(previousTail != nullptr);
|
||||
head = previousTail->Next();
|
||||
}
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
const Message *PriorityQueue::GetTail(void) const { return FindFirstNonNullTail(Message::kPriorityLow); }
|
||||
const Message *PriorityQueue::GetTail(void) const { return FindTailForPriorityOrHigher(Message::kPriorityLow); }
|
||||
|
||||
void PriorityQueue::Enqueue(Message &aMessage)
|
||||
{
|
||||
Message::Priority priority;
|
||||
Message *tail;
|
||||
Message *next;
|
||||
uint8_t priority;
|
||||
|
||||
OT_ASSERT(!aMessage.IsInAQueue());
|
||||
|
||||
aMessage.SetPriorityQueue(this);
|
||||
aMessage.GetMetadata().mInPriorityQ = true;
|
||||
|
||||
priority = aMessage.GetPriority();
|
||||
|
||||
tail = FindFirstNonNullTail(priority);
|
||||
// We insert the new `aMessage` immediately after the message
|
||||
// returned by `FindTailForPriorityOrHigher()`.
|
||||
//
|
||||
// If `FindTailForPriorityOrHigher()` returns `nullptr`, it means
|
||||
// `aMessage` has the highest priority of all existing messages
|
||||
// or is the first message in the queue, so we add it at the head
|
||||
// and update `mHead` accordingly.
|
||||
//
|
||||
// We first set the `Prev` and `Next` pointers within `aMessage`
|
||||
// itself. Afterward, we update the `Next()` pointer of the
|
||||
// preceding message (if any) and the `Prev()` pointer of the
|
||||
// succeeding message (if any) to point back to the newly
|
||||
// inserted `aMessage`, maintaining the linked list.
|
||||
|
||||
if (tail != nullptr)
|
||||
aMessage.Prev() = FindTailForPriorityOrHigher(priority);
|
||||
|
||||
if (aMessage.Prev() == nullptr)
|
||||
{
|
||||
next = tail->Next();
|
||||
|
||||
aMessage.Next() = next;
|
||||
aMessage.Prev() = tail;
|
||||
next->Prev() = &aMessage;
|
||||
tail->Next() = &aMessage;
|
||||
aMessage.Next() = mHead;
|
||||
mHead = &aMessage;
|
||||
}
|
||||
else
|
||||
{
|
||||
aMessage.Next() = &aMessage;
|
||||
aMessage.Prev() = &aMessage;
|
||||
aMessage.Next() = aMessage.Prev()->Next();
|
||||
aMessage.Prev()->Next() = &aMessage;
|
||||
}
|
||||
|
||||
if (aMessage.Next() != nullptr)
|
||||
{
|
||||
aMessage.Next()->Prev() = &aMessage;
|
||||
}
|
||||
|
||||
mTails[priority] = &aMessage;
|
||||
@@ -1071,32 +1078,44 @@ void PriorityQueue::Enqueue(Message &aMessage)
|
||||
void PriorityQueue::Dequeue(Message &aMessage)
|
||||
{
|
||||
Message::Priority priority;
|
||||
Message *tail;
|
||||
|
||||
OT_ASSERT(aMessage.GetPriorityQueue() == this);
|
||||
OT_ASSERT(aMessage.IsInAPriorityQueue());
|
||||
|
||||
priority = aMessage.GetPriority();
|
||||
|
||||
tail = mTails[priority];
|
||||
// If `aMessage` is the current tail for its priority, update
|
||||
// `mTails[priority]`. The new tail becomes the preceding
|
||||
// message entry. If the preceding message has a different
|
||||
// (higher) priority, or if there's no preceding message, it
|
||||
// means `aMessage` was the last of its priority, and the
|
||||
// `mTails[priority]` is set to `nullptr`.
|
||||
|
||||
if (&aMessage == tail)
|
||||
if (&aMessage == mTails[priority])
|
||||
{
|
||||
tail = tail->Prev();
|
||||
mTails[priority] = aMessage.Prev();
|
||||
|
||||
if ((&aMessage == tail) || (tail->GetPriority() != priority))
|
||||
if ((mTails[priority] != nullptr) && (mTails[priority]->GetPriority() != priority))
|
||||
{
|
||||
tail = nullptr;
|
||||
mTails[priority] = nullptr;
|
||||
}
|
||||
|
||||
mTails[priority] = tail;
|
||||
}
|
||||
|
||||
aMessage.Next()->Prev() = aMessage.Prev();
|
||||
aMessage.Prev()->Next() = aMessage.Next();
|
||||
aMessage.Next() = nullptr;
|
||||
aMessage.Prev() = nullptr;
|
||||
if (&aMessage == mHead)
|
||||
{
|
||||
mHead = aMessage.Next();
|
||||
}
|
||||
|
||||
aMessage.SetPriorityQueue(nullptr);
|
||||
if (aMessage.Next() != nullptr)
|
||||
{
|
||||
aMessage.Next()->Prev() = aMessage.Prev();
|
||||
}
|
||||
|
||||
if (aMessage.Prev() != nullptr)
|
||||
{
|
||||
aMessage.Prev()->Next() = aMessage.Next();
|
||||
}
|
||||
|
||||
aMessage.MarkAsNotInAQueue();
|
||||
}
|
||||
|
||||
void PriorityQueue::DequeueAndFree(Message &aMessage)
|
||||
|
||||
+19
-44
@@ -235,7 +235,6 @@ protected:
|
||||
TimeMilli mTimestamp; // The message timestamp.
|
||||
Message *mNext; // Next message in a doubly linked list.
|
||||
Message *mPrev; // Previous message in a doubly linked list.
|
||||
void *mQueue; // The queue where message is queued (if any). Queue type from `mInPriorityQ`.
|
||||
TxCallback mTxCallback; // The callback to inform message TX success or failure.
|
||||
void *mTxContext; // The arbitrary context associated with `mTxCallback`.
|
||||
RssAverager mRssAverager; // The averager maintaining the received signal strength (RSS) average.
|
||||
@@ -501,7 +500,7 @@ public:
|
||||
*
|
||||
* @returns A pointer to the next message in the list or `nullptr` if at the end of the list.
|
||||
*/
|
||||
Message *GetNext(void) const;
|
||||
Message *GetNext(void) const { return Next(); }
|
||||
|
||||
/**
|
||||
* Returns the number of bytes in the message.
|
||||
@@ -1425,26 +1424,6 @@ public:
|
||||
*/
|
||||
void UpdateLinkInfoFrom(const ThreadLinkInfo &aLinkInfo);
|
||||
|
||||
/**
|
||||
* Returns a pointer to the message queue (if any) where this message is queued.
|
||||
*
|
||||
* @returns A pointer to the message queue or `nullptr` if not in any message queue.
|
||||
*/
|
||||
MessageQueue *GetMessageQueue(void) const
|
||||
{
|
||||
return !GetMetadata().mInPriorityQ ? static_cast<MessageQueue *>(GetMetadata().mQueue) : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a pointer to the priority message queue (if any) where this message is queued.
|
||||
*
|
||||
* @returns A pointer to the priority queue or `nullptr` if not in any priority queue.
|
||||
*/
|
||||
PriorityQueue *GetPriorityQueue(void) const
|
||||
{
|
||||
return GetMetadata().mInPriorityQ ? static_cast<PriorityQueue *>(GetMetadata().mQueue) : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether or not the message is also used for time sync purpose.
|
||||
*
|
||||
@@ -1603,18 +1582,17 @@ private:
|
||||
AsConst(this)->GetNextChunk(aLength, static_cast<Chunk &>(aChunk));
|
||||
}
|
||||
|
||||
bool IsInAQueue(void) const { return (GetMetadata().mQueue != nullptr); }
|
||||
void MarkAsNotInAQueue(void);
|
||||
bool IsInAQueue(void) const { return (Prev() != this); }
|
||||
bool IsInAPriorityQueue(void) const { return GetMetadata().mInPriorityQ; }
|
||||
|
||||
void SetMessageQueue(MessageQueue *aMessageQueue);
|
||||
void SetPriorityQueue(PriorityQueue *aPriorityQueue);
|
||||
|
||||
void SetRssAverager(const RssAverager &aRssAverager) { GetMetadata().mRssAverager = aRssAverager; }
|
||||
void SetLqiAverager(const LqiAverager &aLqiAverager) { GetMetadata().mLqiAverager = aLqiAverager; }
|
||||
|
||||
Message *&Next(void) { return GetMetadata().mNext; }
|
||||
Message *const &Next(void) const { return GetMetadata().mNext; }
|
||||
Message *&Prev(void) { return GetMetadata().mPrev; }
|
||||
Message *const &Prev(void) const { return GetMetadata().mPrev; }
|
||||
|
||||
static Message *NextOf(Message *aMessage) { return (aMessage != nullptr) ? aMessage->Next() : nullptr; }
|
||||
static const Message *NextOf(const Message *aMessage) { return (aMessage != nullptr) ? aMessage->Next() : nullptr; }
|
||||
@@ -1625,7 +1603,7 @@ private:
|
||||
/**
|
||||
* Implements a message queue.
|
||||
*/
|
||||
class MessageQueue : public otMessageQueue, private NonCopyable
|
||||
class MessageQueue : public otMessageQueue, public Clearable<MessageQueue>, private NonCopyable
|
||||
{
|
||||
friend class Message;
|
||||
friend class PriorityQueue;
|
||||
@@ -1646,7 +1624,7 @@ public:
|
||||
/**
|
||||
* Initializes the message queue.
|
||||
*/
|
||||
MessageQueue(void) { SetTail(nullptr); }
|
||||
MessageQueue(void) { Clear(); }
|
||||
|
||||
#if OPENTHREAD_PLATFORM_NEXUS
|
||||
/**
|
||||
@@ -1660,14 +1638,14 @@ public:
|
||||
*
|
||||
* @returns A pointer to the first message.
|
||||
*/
|
||||
Message *GetHead(void) { return Message::NextOf(GetTail()); }
|
||||
Message *GetHead(void) { return static_cast<Message *>(mData); }
|
||||
|
||||
/**
|
||||
* Returns a pointer to the first message.
|
||||
*
|
||||
* @returns A pointer to the first message.
|
||||
*/
|
||||
const Message *GetHead(void) const { return Message::NextOf(GetTail()); }
|
||||
const Message *GetHead(void) const { return static_cast<const Message *>(mData); }
|
||||
|
||||
/**
|
||||
* Adds a message to the end of the list.
|
||||
@@ -1733,9 +1711,10 @@ public:
|
||||
Message::ConstIterator end(void) const { return Message::ConstIterator(); }
|
||||
|
||||
private:
|
||||
Message *GetTail(void) { return static_cast<Message *>(mData); }
|
||||
const Message *GetTail(void) const { return static_cast<const Message *>(mData); }
|
||||
void SetTail(Message *aMessage) { mData = aMessage; }
|
||||
void SetHead(Message *aMessage) { mData = aMessage; }
|
||||
Message *GetTail(void) { return static_cast<Message *>(mData2); }
|
||||
const Message *GetTail(void) const { return static_cast<const Message *>(mData2); }
|
||||
void SetTail(Message *aMessage) { mData2 = aMessage; }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1768,14 +1747,14 @@ public:
|
||||
*
|
||||
* @returns A pointer to the first message.
|
||||
*/
|
||||
Message *GetHead(void) { return AsNonConst(AsConst(this)->GetHead()); }
|
||||
Message *GetHead(void) { return mHead; }
|
||||
|
||||
/**
|
||||
* Returns a pointer to the first message.
|
||||
*
|
||||
* @returns A pointer to the first message.
|
||||
*/
|
||||
const Message *GetHead(void) const;
|
||||
const Message *GetHead(void) const { return mHead; }
|
||||
|
||||
/**
|
||||
* Returns a pointer to the first message for a given priority level.
|
||||
@@ -1864,18 +1843,14 @@ public:
|
||||
Message::ConstIterator end(void) const { return Message::ConstIterator(); }
|
||||
|
||||
private:
|
||||
uint8_t PrevPriority(uint8_t aPriority) const
|
||||
const Message *FindTailForPriorityOrHigher(uint8_t aPriority) const;
|
||||
|
||||
Message *FindTailForPriorityOrHigher(uint8_t aPriority)
|
||||
{
|
||||
return (aPriority == Message::kNumPriorities - 1) ? 0 : (aPriority + 1);
|
||||
}
|
||||
|
||||
const Message *FindFirstNonNullTail(Message::Priority aStartPriorityLevel) const;
|
||||
|
||||
Message *FindFirstNonNullTail(Message::Priority aStartPriorityLevel)
|
||||
{
|
||||
return AsNonConst(AsConst(this)->FindFirstNonNullTail(aStartPriorityLevel));
|
||||
return AsNonConst(AsConst(this)->FindTailForPriorityOrHigher(aPriority));
|
||||
}
|
||||
|
||||
Message *mHead;
|
||||
Message *mTails[Message::kNumPriorities]; // Tail pointers associated with different priority levels.
|
||||
};
|
||||
|
||||
|
||||
@@ -133,6 +133,46 @@ void TestMessageQueue(void)
|
||||
messageQueue.Dequeue(*messages[0]);
|
||||
VerifyMessageQueueContent(messageQueue, 0);
|
||||
|
||||
// Enqueue 2 messages and remove them in the same order added.
|
||||
messageQueue.Enqueue(*messages[0]);
|
||||
VerifyMessageQueueContent(messageQueue, 1, messages[0]);
|
||||
messageQueue.Enqueue(*messages[1]);
|
||||
VerifyMessageQueueContent(messageQueue, 2, messages[0], messages[1]);
|
||||
messageQueue.Dequeue(*messages[0]);
|
||||
VerifyMessageQueueContent(messageQueue, 1, messages[1]);
|
||||
messageQueue.Dequeue(*messages[1]);
|
||||
VerifyMessageQueueContent(messageQueue, 0);
|
||||
|
||||
// Enqueue 2 messages and remove them in reverse order added.
|
||||
messageQueue.Enqueue(*messages[0]);
|
||||
VerifyMessageQueueContent(messageQueue, 1, messages[0]);
|
||||
messageQueue.Enqueue(*messages[1]);
|
||||
VerifyMessageQueueContent(messageQueue, 2, messages[0], messages[1]);
|
||||
messageQueue.Dequeue(*messages[1]);
|
||||
VerifyMessageQueueContent(messageQueue, 1, messages[0]);
|
||||
messageQueue.Dequeue(*messages[0]);
|
||||
VerifyMessageQueueContent(messageQueue, 0);
|
||||
|
||||
// Enqueue 2 messages at the head and remove them in the same order added.
|
||||
messageQueue.Enqueue(*messages[0], MessageQueue::kQueuePositionHead);
|
||||
VerifyMessageQueueContent(messageQueue, 1, messages[0]);
|
||||
messageQueue.Enqueue(*messages[1], MessageQueue::kQueuePositionHead);
|
||||
VerifyMessageQueueContent(messageQueue, 2, messages[1], messages[0]);
|
||||
messageQueue.Dequeue(*messages[0]);
|
||||
VerifyMessageQueueContent(messageQueue, 1, messages[1]);
|
||||
messageQueue.Dequeue(*messages[1]);
|
||||
VerifyMessageQueueContent(messageQueue, 0);
|
||||
|
||||
// Enqueue 2 messages at the head and remove them in the reverse order added.
|
||||
messageQueue.Enqueue(*messages[0], MessageQueue::kQueuePositionHead);
|
||||
VerifyMessageQueueContent(messageQueue, 1, messages[0]);
|
||||
messageQueue.Enqueue(*messages[1], MessageQueue::kQueuePositionHead);
|
||||
VerifyMessageQueueContent(messageQueue, 2, messages[1], messages[0]);
|
||||
messageQueue.Dequeue(*messages[1]);
|
||||
VerifyMessageQueueContent(messageQueue, 1, messages[0]);
|
||||
messageQueue.Dequeue(*messages[0]);
|
||||
VerifyMessageQueueContent(messageQueue, 0);
|
||||
|
||||
// Enqueue 5 messages
|
||||
messageQueue.Enqueue(*messages[0]);
|
||||
VerifyMessageQueueContent(messageQueue, 1, messages[0]);
|
||||
@@ -333,8 +373,6 @@ void TestMessageQueueOtApis(void)
|
||||
|
||||
message = otMessageQueueGetNext(&queue2, messages[0]);
|
||||
VerifyOrQuit(message == messages[1], "otMessageQueueGetNext() failed");
|
||||
message = otMessageQueueGetNext(&queue, messages[0]);
|
||||
VerifyOrQuit(message == nullptr, "otMessageQueueGetNext() did not return nullptr for message not in the queue.");
|
||||
|
||||
// Remove all element and make sure queue is empty
|
||||
otMessageQueueDequeue(&queue, messages[2]);
|
||||
|
||||
@@ -37,10 +37,6 @@
|
||||
|
||||
namespace ot {
|
||||
|
||||
#define kNumNewPriorityTestMessages 2
|
||||
#define kNumSetPriorityTestMessages 2
|
||||
#define kNumTestMessages (kNumNewPriorityTestMessages + kNumSetPriorityTestMessages)
|
||||
|
||||
// This function verifies the content of the priority queue to match the passed in messages
|
||||
void VerifyPriorityQueueContent(PriorityQueue &aPriorityQueue, int aExpectedLength, ...)
|
||||
{
|
||||
@@ -135,140 +131,541 @@ void VerifyPriorityQueueContent(PriorityQueue &aPriorityQueue, int aExpectedLeng
|
||||
VerifyOrQuit(message == nullptr, "`for` loop iteration resulted in fewer entries than expected");
|
||||
}
|
||||
|
||||
// NOLINTBEGIN(modernize-loop-convert)
|
||||
void TestPriorityQueue(void)
|
||||
{
|
||||
static constexpr uint16_t kNumNewPriorityTestMessages = 2;
|
||||
static constexpr uint16_t kNumSetPriorityTestMessages = 2;
|
||||
static constexpr uint16_t kNumTestMessages = (kNumNewPriorityTestMessages + kNumSetPriorityTestMessages);
|
||||
|
||||
// Use two char abbreviated names for different priority levels;
|
||||
static constexpr uint8_t kNw = Message::kPriorityNet; // Network level (highest priority)
|
||||
static constexpr uint8_t kHi = Message::kPriorityHigh; // High priority
|
||||
static constexpr uint8_t kMd = Message::kPriorityNormal; // Middle (or Normal) priority
|
||||
static constexpr uint8_t kLo = Message::kPriorityLow; // Low priority.
|
||||
static constexpr uint8_t kNumPriorities = Message::kNumPriorities;
|
||||
|
||||
Instance *instance;
|
||||
MessagePool *messagePool;
|
||||
PriorityQueue queue;
|
||||
Message *msgNet[kNumTestMessages];
|
||||
Message *msgHigh[kNumTestMessages];
|
||||
Message *msgNor[kNumTestMessages];
|
||||
Message *msgLow[kNumTestMessages];
|
||||
Message *msg[kNumPriorities][kNumTestMessages];
|
||||
|
||||
instance = testInitInstance();
|
||||
VerifyOrQuit(instance != nullptr, "Null OpenThread instance");
|
||||
|
||||
messagePool = &instance->Get<MessagePool>();
|
||||
|
||||
// Use the function "Allocate()" to allocate messages with different priorities
|
||||
for (int i = 0; i < kNumNewPriorityTestMessages; i++)
|
||||
for (uint8_t prio = 0; prio < kNumPriorities; prio++)
|
||||
{
|
||||
msgNet[i] = messagePool->Allocate(Message::kTypeIp6, 0, Message::Settings(Message::kPriorityNet));
|
||||
VerifyOrQuit(msgNet[i] != nullptr);
|
||||
msgHigh[i] = messagePool->Allocate(Message::kTypeIp6, 0, Message::Settings(Message::kPriorityHigh));
|
||||
VerifyOrQuit(msgHigh[i] != nullptr);
|
||||
msgNor[i] = messagePool->Allocate(Message::kTypeIp6, 0, Message::Settings(Message::kPriorityNormal));
|
||||
VerifyOrQuit(msgNor[i] != nullptr);
|
||||
msgLow[i] = messagePool->Allocate(Message::kTypeIp6, 0, Message::Settings(Message::kPriorityLow));
|
||||
VerifyOrQuit(msgLow[i] != nullptr);
|
||||
}
|
||||
Message::Priority priority = static_cast<Message::Priority>(prio);
|
||||
|
||||
// Use the function "SetPriority()" to allocate messages with different priorities
|
||||
for (int i = kNumNewPriorityTestMessages; i < kNumTestMessages; i++)
|
||||
{
|
||||
msgNet[i] = messagePool->Allocate(Message::kTypeIp6);
|
||||
VerifyOrQuit(msgNet[i] != nullptr);
|
||||
SuccessOrQuit(msgNet[i]->SetPriority(Message::kPriorityNet));
|
||||
msgHigh[i] = messagePool->Allocate(Message::kTypeIp6);
|
||||
VerifyOrQuit(msgHigh[i] != nullptr);
|
||||
SuccessOrQuit(msgHigh[i]->SetPriority(Message::kPriorityHigh));
|
||||
msgNor[i] = messagePool->Allocate(Message::kTypeIp6);
|
||||
VerifyOrQuit(msgNor[i] != nullptr);
|
||||
SuccessOrQuit(msgNor[i]->SetPriority(Message::kPriorityNormal));
|
||||
msgLow[i] = messagePool->Allocate(Message::kTypeIp6);
|
||||
VerifyOrQuit(msgLow[i] != nullptr);
|
||||
SuccessOrQuit(msgLow[i]->SetPriority(Message::kPriorityLow));
|
||||
// Use the function "Allocate()" to allocate messages with different priorities
|
||||
for (int i = 0; i < kNumNewPriorityTestMessages; i++)
|
||||
{
|
||||
msg[prio][i] = messagePool->Allocate(Message::kTypeIp6, 0, Message::Settings(priority));
|
||||
VerifyOrQuit(msg[prio][i] != nullptr);
|
||||
}
|
||||
|
||||
// Use the function "SetPriority()" to allocate messages with different priorities
|
||||
for (int i = kNumNewPriorityTestMessages; i < kNumTestMessages; i++)
|
||||
{
|
||||
msg[prio][i] = messagePool->Allocate(Message::kTypeIp6);
|
||||
VerifyOrQuit(msg[prio][i] != nullptr);
|
||||
SuccessOrQuit(msg[prio][i]->SetPriority(priority));
|
||||
}
|
||||
}
|
||||
|
||||
// Check the `GetPriority()`
|
||||
for (int i = 0; i < kNumTestMessages; i++)
|
||||
{
|
||||
VerifyOrQuit(msgLow[i]->GetPriority() == Message::kPriorityLow);
|
||||
VerifyOrQuit(msgNor[i]->GetPriority() == Message::kPriorityNormal);
|
||||
VerifyOrQuit(msgHigh[i]->GetPriority() == Message::kPriorityHigh);
|
||||
VerifyOrQuit(msgNet[i]->GetPriority() == Message::kPriorityNet);
|
||||
VerifyOrQuit(msg[kLo][i]->GetPriority() == Message::kPriorityLow);
|
||||
VerifyOrQuit(msg[kMd][i]->GetPriority() == Message::kPriorityNormal);
|
||||
VerifyOrQuit(msg[kHi][i]->GetPriority() == Message::kPriorityHigh);
|
||||
VerifyOrQuit(msg[kNw][i]->GetPriority() == Message::kPriorityNet);
|
||||
}
|
||||
|
||||
// Verify case of an empty queue.
|
||||
VerifyPriorityQueueContent(queue, 0);
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Messages with the same priority only.
|
||||
|
||||
for (uint8_t prio = 0; prio < kNumPriorities; prio++)
|
||||
{
|
||||
// Add and remove one message only
|
||||
queue.Enqueue(*msg[prio][0]);
|
||||
VerifyPriorityQueueContent(queue, 1, msg[prio][0]);
|
||||
queue.Dequeue(*msg[prio][0]);
|
||||
VerifyPriorityQueueContent(queue, 0);
|
||||
|
||||
// Add three messages and then dequeue them in different orders.
|
||||
|
||||
for (uint8_t test = 0; test < 3; test++)
|
||||
{
|
||||
queue.Enqueue(*msg[prio][0]);
|
||||
VerifyPriorityQueueContent(queue, 1, msg[prio][0]);
|
||||
queue.Enqueue(*msg[prio][1]);
|
||||
VerifyPriorityQueueContent(queue, 2, msg[prio][0], msg[prio][1]);
|
||||
queue.Enqueue(*msg[prio][2]);
|
||||
VerifyPriorityQueueContent(queue, 3, msg[prio][0], msg[prio][1], msg[prio][2]);
|
||||
|
||||
switch (test)
|
||||
{
|
||||
case 0:
|
||||
// Remove the messages in the same order added.
|
||||
queue.Dequeue(*msg[prio][0]);
|
||||
VerifyPriorityQueueContent(queue, 2, msg[prio][1], msg[prio][2]);
|
||||
queue.Dequeue(*msg[prio][1]);
|
||||
VerifyPriorityQueueContent(queue, 1, msg[prio][2]);
|
||||
queue.Dequeue(*msg[prio][2]);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
// Remove the message in the reverse order added
|
||||
queue.Dequeue(*msg[prio][2]);
|
||||
VerifyPriorityQueueContent(queue, 2, msg[prio][0], msg[prio][1]);
|
||||
queue.Dequeue(*msg[prio][1]);
|
||||
VerifyPriorityQueueContent(queue, 1, msg[prio][0]);
|
||||
queue.Dequeue(*msg[prio][0]);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// Remove the message in random order added.
|
||||
queue.Dequeue(*msg[prio][1]);
|
||||
VerifyPriorityQueueContent(queue, 2, msg[prio][0], msg[prio][2]);
|
||||
queue.Dequeue(*msg[prio][0]);
|
||||
VerifyPriorityQueueContent(queue, 1, msg[prio][2]);
|
||||
queue.Dequeue(*msg[prio][2]);
|
||||
break;
|
||||
}
|
||||
|
||||
VerifyPriorityQueueContent(queue, 0);
|
||||
}
|
||||
}
|
||||
|
||||
VerifyPriorityQueueContent(queue, 0);
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Messages with the two different priorities (`prio1` lower than `prio2`)
|
||||
|
||||
for (uint8_t prio1 = 0; prio1 < kNumPriorities - 1; prio1++)
|
||||
{
|
||||
for (uint8_t prio2 = prio1 + 1; prio2 < kNumPriorities; prio2++)
|
||||
{
|
||||
// Add one message with `prio1` and one with `prio2` and
|
||||
// then remove them. Cover all possible combinations
|
||||
// (order to add and remove).
|
||||
|
||||
for (uint8_t test = 0; test < 4; test++)
|
||||
{
|
||||
switch (test)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
// Add lower priority first, then higher priority
|
||||
queue.Enqueue(*msg[prio1][0]);
|
||||
VerifyPriorityQueueContent(queue, 1, msg[prio1][0]);
|
||||
queue.Enqueue(*msg[prio2][0]);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
case 3:
|
||||
// Add higher priority first, then lower priority
|
||||
queue.Enqueue(*msg[prio2][0]);
|
||||
VerifyPriorityQueueContent(queue, 1, msg[prio2][0]);
|
||||
queue.Enqueue(*msg[prio1][0]);
|
||||
break;
|
||||
}
|
||||
|
||||
VerifyPriorityQueueContent(queue, 2, msg[prio2][0], msg[prio1][0]);
|
||||
|
||||
switch (test)
|
||||
{
|
||||
case 0:
|
||||
case 2:
|
||||
// Remove lower priority first, then higher priority.
|
||||
queue.Dequeue(*msg[prio1][0]);
|
||||
VerifyPriorityQueueContent(queue, 1, msg[prio2][0]);
|
||||
queue.Dequeue(*msg[prio2][0]);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
case 3:
|
||||
// Remove higher priority first, then lower priority
|
||||
queue.Dequeue(*msg[prio2][0]);
|
||||
VerifyPriorityQueueContent(queue, 1, msg[prio1][0]);
|
||||
queue.Dequeue(*msg[prio1][0]);
|
||||
break;
|
||||
}
|
||||
|
||||
VerifyPriorityQueueContent(queue, 0);
|
||||
}
|
||||
|
||||
// Add two messages with `prio1` (lower) and one with
|
||||
// `prio2` (higher) and then remove them. Cover all
|
||||
// possible combinations to add and remove.
|
||||
|
||||
for (uint8_t test = 0; test < 6; test++)
|
||||
{
|
||||
switch (test)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
// Add two lower priority messages first, then one higher priority
|
||||
queue.Enqueue(*msg[prio1][0]);
|
||||
VerifyPriorityQueueContent(queue, 1, msg[prio1][0]);
|
||||
queue.Enqueue(*msg[prio1][1]);
|
||||
VerifyPriorityQueueContent(queue, 2, msg[prio1][0], msg[prio1][1]);
|
||||
queue.Enqueue(*msg[prio2][0]);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
case 3:
|
||||
// Add one higher priority first, then two lower priority messages.
|
||||
queue.Enqueue(*msg[prio2][0]);
|
||||
VerifyPriorityQueueContent(queue, 1, msg[prio2][0]);
|
||||
queue.Enqueue(*msg[prio1][0]);
|
||||
VerifyPriorityQueueContent(queue, 2, msg[prio2][0], msg[prio1][0]);
|
||||
queue.Enqueue(*msg[prio1][1]);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
case 5:
|
||||
// Add one lower priority first, then a higher priority, finally one lower priority.
|
||||
queue.Enqueue(*msg[prio1][0]);
|
||||
VerifyPriorityQueueContent(queue, 1, msg[prio1][0]);
|
||||
queue.Enqueue(*msg[prio2][0]);
|
||||
VerifyPriorityQueueContent(queue, 2, msg[prio2][0], msg[prio1][0]);
|
||||
queue.Enqueue(*msg[prio1][1]);
|
||||
break;
|
||||
}
|
||||
|
||||
VerifyPriorityQueueContent(queue, 3, msg[prio2][0], msg[prio1][0], msg[prio1][1]);
|
||||
|
||||
switch (test)
|
||||
{
|
||||
case 0:
|
||||
queue.Dequeue(*msg[prio1][0]);
|
||||
VerifyPriorityQueueContent(queue, 2, msg[prio2][0], msg[prio1][1]);
|
||||
queue.Dequeue(*msg[prio1][1]);
|
||||
VerifyPriorityQueueContent(queue, 1, msg[prio2][0]);
|
||||
queue.Dequeue(*msg[prio2][0]);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
queue.Dequeue(*msg[prio1][0]);
|
||||
VerifyPriorityQueueContent(queue, 2, msg[prio2][0], msg[prio1][1]);
|
||||
queue.Dequeue(*msg[prio2][0]);
|
||||
VerifyPriorityQueueContent(queue, 1, msg[prio1][1]);
|
||||
queue.Dequeue(*msg[prio1][1]);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
queue.Dequeue(*msg[prio1][1]);
|
||||
VerifyPriorityQueueContent(queue, 2, msg[prio2][0], msg[prio1][0]);
|
||||
queue.Dequeue(*msg[prio1][0]);
|
||||
VerifyPriorityQueueContent(queue, 1, msg[prio2][0]);
|
||||
queue.Dequeue(*msg[prio2][0]);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
queue.Dequeue(*msg[prio1][1]);
|
||||
VerifyPriorityQueueContent(queue, 2, msg[prio2][0], msg[prio1][0]);
|
||||
queue.Dequeue(*msg[prio2][0]);
|
||||
VerifyPriorityQueueContent(queue, 1, msg[prio1][0]);
|
||||
queue.Dequeue(*msg[prio1][0]);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
queue.Dequeue(*msg[prio2][0]);
|
||||
VerifyPriorityQueueContent(queue, 2, msg[prio1][0], msg[prio1][1]);
|
||||
queue.Dequeue(*msg[prio1][0]);
|
||||
VerifyPriorityQueueContent(queue, 1, msg[prio1][1]);
|
||||
queue.Dequeue(*msg[prio1][1]);
|
||||
break;
|
||||
|
||||
case 5:
|
||||
queue.Dequeue(*msg[prio2][0]);
|
||||
VerifyPriorityQueueContent(queue, 2, msg[prio1][0], msg[prio1][1]);
|
||||
queue.Dequeue(*msg[prio1][1]);
|
||||
VerifyPriorityQueueContent(queue, 1, msg[prio1][0]);
|
||||
queue.Dequeue(*msg[prio1][0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
VerifyPriorityQueueContent(queue, 0);
|
||||
|
||||
// Add two messages with `prio2` (higher) and one with
|
||||
// `prio1` (lower) and then remove them. Cover all
|
||||
// possible combinations to add and remove.
|
||||
|
||||
for (uint8_t test = 0; test < 6; test++)
|
||||
{
|
||||
switch (test)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
// Add two higher priority messages first, then one lower priority
|
||||
queue.Enqueue(*msg[prio2][0]);
|
||||
VerifyPriorityQueueContent(queue, 1, msg[prio2][0]);
|
||||
queue.Enqueue(*msg[prio2][1]);
|
||||
VerifyPriorityQueueContent(queue, 2, msg[prio2][0], msg[prio2][1]);
|
||||
queue.Enqueue(*msg[prio1][0]);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
case 3:
|
||||
// Add one lower priority first, then two higher priority messages.
|
||||
queue.Enqueue(*msg[prio1][0]);
|
||||
VerifyPriorityQueueContent(queue, 1, msg[prio1][0]);
|
||||
queue.Enqueue(*msg[prio2][0]);
|
||||
VerifyPriorityQueueContent(queue, 2, msg[prio2][0], msg[prio1][0]);
|
||||
queue.Enqueue(*msg[prio2][1]);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
case 5:
|
||||
// Add one higher priority first, then a lower priority, finally one higher priority.
|
||||
queue.Enqueue(*msg[prio2][0]);
|
||||
VerifyPriorityQueueContent(queue, 1, msg[prio2][0]);
|
||||
queue.Enqueue(*msg[prio1][0]);
|
||||
VerifyPriorityQueueContent(queue, 2, msg[prio2][0], msg[prio1][0]);
|
||||
queue.Enqueue(*msg[prio2][1]);
|
||||
break;
|
||||
}
|
||||
|
||||
VerifyPriorityQueueContent(queue, 3, msg[prio2][0], msg[prio2][1], msg[prio1][0]);
|
||||
|
||||
switch (test)
|
||||
{
|
||||
case 0:
|
||||
queue.Dequeue(*msg[prio2][0]);
|
||||
VerifyPriorityQueueContent(queue, 2, msg[prio2][1], msg[prio1][0]);
|
||||
queue.Dequeue(*msg[prio2][1]);
|
||||
VerifyPriorityQueueContent(queue, 1, msg[prio1][0]);
|
||||
queue.Dequeue(*msg[prio1][0]);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
queue.Dequeue(*msg[prio2][0]);
|
||||
VerifyPriorityQueueContent(queue, 2, msg[prio2][1], msg[prio1][0]);
|
||||
queue.Dequeue(*msg[prio1][0]);
|
||||
VerifyPriorityQueueContent(queue, 1, msg[prio2][1]);
|
||||
queue.Dequeue(*msg[prio2][1]);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
queue.Dequeue(*msg[prio2][1]);
|
||||
VerifyPriorityQueueContent(queue, 2, msg[prio2][0], msg[prio1][0]);
|
||||
queue.Dequeue(*msg[prio2][0]);
|
||||
VerifyPriorityQueueContent(queue, 1, msg[prio1][0]);
|
||||
queue.Dequeue(*msg[prio1][0]);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
queue.Dequeue(*msg[prio2][1]);
|
||||
VerifyPriorityQueueContent(queue, 2, msg[prio2][0], msg[prio1][0]);
|
||||
queue.Dequeue(*msg[prio1][0]);
|
||||
VerifyPriorityQueueContent(queue, 1, msg[prio2][0]);
|
||||
queue.Dequeue(*msg[prio2][0]);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
queue.Dequeue(*msg[prio1][0]);
|
||||
VerifyPriorityQueueContent(queue, 2, msg[prio2][0], msg[prio2][1]);
|
||||
queue.Dequeue(*msg[prio2][0]);
|
||||
VerifyPriorityQueueContent(queue, 1, msg[prio2][1]);
|
||||
queue.Dequeue(*msg[prio2][1]);
|
||||
break;
|
||||
|
||||
case 5:
|
||||
queue.Dequeue(*msg[prio1][0]);
|
||||
VerifyPriorityQueueContent(queue, 2, msg[prio2][0], msg[prio2][1]);
|
||||
queue.Dequeue(*msg[prio2][1]);
|
||||
VerifyPriorityQueueContent(queue, 1, msg[prio2][0]);
|
||||
queue.Dequeue(*msg[prio2][0]);
|
||||
break;
|
||||
}
|
||||
|
||||
VerifyPriorityQueueContent(queue, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Messages with the three different priorities (prio1 < prio2 < prio3)
|
||||
|
||||
for (uint8_t prio1 = 0; prio1 < kNumPriorities - 2; prio1++)
|
||||
{
|
||||
for (uint8_t prio2 = prio1 + 1; prio2 < kNumPriorities - 1; prio2++)
|
||||
{
|
||||
for (uint8_t prio3 = prio2 + 1; prio3 < kNumPriorities; prio3++)
|
||||
{
|
||||
for (uint8_t test = 0; test < 6; test++)
|
||||
{
|
||||
switch (test)
|
||||
{
|
||||
case 0:
|
||||
queue.Enqueue(*msg[prio1][0]);
|
||||
VerifyPriorityQueueContent(queue, 1, msg[prio1][0]);
|
||||
queue.Enqueue(*msg[prio2][0]);
|
||||
VerifyPriorityQueueContent(queue, 2, msg[prio2][0], msg[prio1][0]);
|
||||
queue.Enqueue(*msg[prio3][0]);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
queue.Enqueue(*msg[prio1][0]);
|
||||
VerifyPriorityQueueContent(queue, 1, msg[prio1][0]);
|
||||
queue.Enqueue(*msg[prio3][0]);
|
||||
VerifyPriorityQueueContent(queue, 2, msg[prio3][0], msg[prio1][0]);
|
||||
queue.Enqueue(*msg[prio2][0]);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
queue.Enqueue(*msg[prio2][0]);
|
||||
VerifyPriorityQueueContent(queue, 1, msg[prio2][0]);
|
||||
queue.Enqueue(*msg[prio1][0]);
|
||||
VerifyPriorityQueueContent(queue, 2, msg[prio2][0], msg[prio1][0]);
|
||||
queue.Enqueue(*msg[prio3][0]);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
queue.Enqueue(*msg[prio2][0]);
|
||||
VerifyPriorityQueueContent(queue, 1, msg[prio2][0]);
|
||||
queue.Enqueue(*msg[prio3][0]);
|
||||
VerifyPriorityQueueContent(queue, 2, msg[prio3][0], msg[prio2][0]);
|
||||
queue.Enqueue(*msg[prio1][0]);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
queue.Enqueue(*msg[prio3][0]);
|
||||
VerifyPriorityQueueContent(queue, 1, msg[prio3][0]);
|
||||
queue.Enqueue(*msg[prio1][0]);
|
||||
VerifyPriorityQueueContent(queue, 2, msg[prio3][0], msg[prio1][0]);
|
||||
queue.Enqueue(*msg[prio2][0]);
|
||||
break;
|
||||
|
||||
case 5:
|
||||
queue.Enqueue(*msg[prio3][0]);
|
||||
VerifyPriorityQueueContent(queue, 1, msg[prio3][0]);
|
||||
queue.Enqueue(*msg[prio2][0]);
|
||||
VerifyPriorityQueueContent(queue, 2, msg[prio3][0], msg[prio2][0]);
|
||||
queue.Enqueue(*msg[prio1][0]);
|
||||
break;
|
||||
}
|
||||
|
||||
VerifyPriorityQueueContent(queue, 3, msg[prio3][0], msg[prio2][0], msg[prio1][0]);
|
||||
|
||||
switch (test)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
queue.Dequeue(*msg[prio1][0]);
|
||||
VerifyPriorityQueueContent(queue, 2, msg[prio3][0], msg[prio2][0]);
|
||||
queue.Dequeue(*msg[prio2][0]);
|
||||
VerifyPriorityQueueContent(queue, 1, msg[prio3][0]);
|
||||
queue.Dequeue(*msg[prio3][0]);
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
queue.Dequeue(*msg[prio3][0]);
|
||||
VerifyPriorityQueueContent(queue, 2, msg[prio2][0], msg[prio1][0]);
|
||||
queue.Dequeue(*msg[prio1][0]);
|
||||
VerifyPriorityQueueContent(queue, 1, msg[prio2][0]);
|
||||
queue.Dequeue(*msg[prio2][0]);
|
||||
break;
|
||||
}
|
||||
|
||||
VerifyPriorityQueueContent(queue, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Add msgs in different orders and check the content of queue.
|
||||
queue.Enqueue(*msgHigh[0]);
|
||||
VerifyPriorityQueueContent(queue, 1, msgHigh[0]);
|
||||
queue.Enqueue(*msgHigh[1]);
|
||||
VerifyPriorityQueueContent(queue, 2, msgHigh[0], msgHigh[1]);
|
||||
queue.Enqueue(*msgNet[0]);
|
||||
VerifyPriorityQueueContent(queue, 3, msgNet[0], msgHigh[0], msgHigh[1]);
|
||||
queue.Enqueue(*msgNet[1]);
|
||||
VerifyPriorityQueueContent(queue, 4, msgNet[0], msgNet[1], msgHigh[0], msgHigh[1]);
|
||||
queue.Enqueue(*msgHigh[2]);
|
||||
VerifyPriorityQueueContent(queue, 5, msgNet[0], msgNet[1], msgHigh[0], msgHigh[1], msgHigh[2]);
|
||||
queue.Enqueue(*msgLow[0]);
|
||||
VerifyPriorityQueueContent(queue, 6, msgNet[0], msgNet[1], msgHigh[0], msgHigh[1], msgHigh[2], msgLow[0]);
|
||||
queue.Enqueue(*msgNor[0]);
|
||||
VerifyPriorityQueueContent(queue, 7, msgNet[0], msgNet[1], msgHigh[0], msgHigh[1], msgHigh[2], msgNor[0],
|
||||
msgLow[0]);
|
||||
queue.Enqueue(*msgHigh[3]);
|
||||
VerifyPriorityQueueContent(queue, 8, msgNet[0], msgNet[1], msgHigh[0], msgHigh[1], msgHigh[2], msgHigh[3],
|
||||
msgNor[0], msgLow[0]);
|
||||
|
||||
queue.Enqueue(*msg[kHi][0]);
|
||||
VerifyPriorityQueueContent(queue, 1, msg[kHi][0]);
|
||||
queue.Enqueue(*msg[kHi][1]);
|
||||
VerifyPriorityQueueContent(queue, 2, msg[kHi][0], msg[kHi][1]);
|
||||
queue.Enqueue(*msg[kNw][0]);
|
||||
VerifyPriorityQueueContent(queue, 3, msg[kNw][0], msg[kHi][0], msg[kHi][1]);
|
||||
queue.Enqueue(*msg[kNw][1]);
|
||||
VerifyPriorityQueueContent(queue, 4, msg[kNw][0], msg[kNw][1], msg[kHi][0], msg[kHi][1]);
|
||||
queue.Enqueue(*msg[kHi][2]);
|
||||
VerifyPriorityQueueContent(queue, 5, msg[kNw][0], msg[kNw][1], msg[kHi][0], msg[kHi][1], msg[kHi][2]);
|
||||
queue.Enqueue(*msg[kLo][0]);
|
||||
VerifyPriorityQueueContent(queue, 6, msg[kNw][0], msg[kNw][1], msg[kHi][0], msg[kHi][1], msg[kHi][2], msg[kLo][0]);
|
||||
queue.Enqueue(*msg[kMd][0]);
|
||||
VerifyPriorityQueueContent(queue, 7, msg[kNw][0], msg[kNw][1], msg[kHi][0], msg[kHi][1], msg[kHi][2], msg[kMd][0],
|
||||
msg[kLo][0]);
|
||||
queue.Enqueue(*msg[kHi][3]);
|
||||
VerifyPriorityQueueContent(queue, 8, msg[kNw][0], msg[kNw][1], msg[kHi][0], msg[kHi][1], msg[kHi][2], msg[kHi][3],
|
||||
msg[kMd][0], msg[kLo][0]);
|
||||
|
||||
// Remove messages in different order and check the content of queue in each step.
|
||||
queue.Dequeue(*msgNet[0]);
|
||||
VerifyPriorityQueueContent(queue, 7, msgNet[1], msgHigh[0], msgHigh[1], msgHigh[2], msgHigh[3], msgNor[0],
|
||||
msgLow[0]);
|
||||
queue.Dequeue(*msgHigh[2]);
|
||||
VerifyPriorityQueueContent(queue, 6, msgNet[1], msgHigh[0], msgHigh[1], msgHigh[3], msgNor[0], msgLow[0]);
|
||||
queue.Dequeue(*msgNor[0]);
|
||||
VerifyPriorityQueueContent(queue, 5, msgNet[1], msgHigh[0], msgHigh[1], msgHigh[3], msgLow[0]);
|
||||
queue.Dequeue(*msgHigh[1]);
|
||||
VerifyPriorityQueueContent(queue, 4, msgNet[1], msgHigh[0], msgHigh[3], msgLow[0]);
|
||||
queue.Dequeue(*msgLow[0]);
|
||||
VerifyPriorityQueueContent(queue, 3, msgNet[1], msgHigh[0], msgHigh[3]);
|
||||
queue.Dequeue(*msgNet[1]);
|
||||
VerifyPriorityQueueContent(queue, 2, msgHigh[0], msgHigh[3]);
|
||||
queue.Dequeue(*msgHigh[0]);
|
||||
VerifyPriorityQueueContent(queue, 1, msgHigh[3]);
|
||||
queue.Dequeue(*msgHigh[3]);
|
||||
queue.Dequeue(*msg[kNw][0]);
|
||||
VerifyPriorityQueueContent(queue, 7, msg[kNw][1], msg[kHi][0], msg[kHi][1], msg[kHi][2], msg[kHi][3], msg[kMd][0],
|
||||
msg[kLo][0]);
|
||||
queue.Dequeue(*msg[kHi][2]);
|
||||
VerifyPriorityQueueContent(queue, 6, msg[kNw][1], msg[kHi][0], msg[kHi][1], msg[kHi][3], msg[kMd][0], msg[kLo][0]);
|
||||
queue.Dequeue(*msg[kMd][0]);
|
||||
VerifyPriorityQueueContent(queue, 5, msg[kNw][1], msg[kHi][0], msg[kHi][1], msg[kHi][3], msg[kLo][0]);
|
||||
queue.Dequeue(*msg[kHi][1]);
|
||||
VerifyPriorityQueueContent(queue, 4, msg[kNw][1], msg[kHi][0], msg[kHi][3], msg[kLo][0]);
|
||||
queue.Dequeue(*msg[kLo][0]);
|
||||
VerifyPriorityQueueContent(queue, 3, msg[kNw][1], msg[kHi][0], msg[kHi][3]);
|
||||
queue.Dequeue(*msg[kNw][1]);
|
||||
VerifyPriorityQueueContent(queue, 2, msg[kHi][0], msg[kHi][3]);
|
||||
queue.Dequeue(*msg[kHi][0]);
|
||||
VerifyPriorityQueueContent(queue, 1, msg[kHi][3]);
|
||||
queue.Dequeue(*msg[kHi][3]);
|
||||
VerifyPriorityQueueContent(queue, 0);
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Validate that priority of an already queued message in a priority queue cannot change
|
||||
queue.Enqueue(*msgNor[0]);
|
||||
VerifyPriorityQueueContent(queue, 1, msgNor[0]);
|
||||
queue.Enqueue(*msgHigh[0]);
|
||||
VerifyPriorityQueueContent(queue, 2, msgHigh[0], msgNor[0]);
|
||||
queue.Enqueue(*msgLow[0]);
|
||||
VerifyPriorityQueueContent(queue, 3, msgHigh[0], msgNor[0], msgLow[0]);
|
||||
queue.Enqueue(*msg[kMd][0]);
|
||||
VerifyPriorityQueueContent(queue, 1, msg[kMd][0]);
|
||||
queue.Enqueue(*msg[kHi][0]);
|
||||
VerifyPriorityQueueContent(queue, 2, msg[kHi][0], msg[kMd][0]);
|
||||
queue.Enqueue(*msg[kLo][0]);
|
||||
VerifyPriorityQueueContent(queue, 3, msg[kHi][0], msg[kMd][0], msg[kLo][0]);
|
||||
|
||||
VerifyOrQuit(msgNor[0]->SetPriority(Message::kPriorityNet) == kErrorInvalidState);
|
||||
VerifyOrQuit(msgLow[0]->SetPriority(Message::kPriorityLow) == kErrorInvalidState);
|
||||
VerifyOrQuit(msgLow[0]->SetPriority(Message::kPriorityNormal) == kErrorInvalidState);
|
||||
VerifyOrQuit(msgHigh[0]->SetPriority(Message::kPriorityNormal) == kErrorInvalidState);
|
||||
VerifyPriorityQueueContent(queue, 3, msgHigh[0], msgNor[0], msgLow[0]);
|
||||
VerifyOrQuit(msg[kMd][0]->SetPriority(Message::kPriorityNet) == kErrorInvalidState);
|
||||
VerifyOrQuit(msg[kLo][0]->SetPriority(Message::kPriorityLow) == kErrorInvalidState);
|
||||
VerifyOrQuit(msg[kLo][0]->SetPriority(Message::kPriorityNormal) == kErrorInvalidState);
|
||||
VerifyOrQuit(msg[kHi][0]->SetPriority(Message::kPriorityNormal) == kErrorInvalidState);
|
||||
VerifyPriorityQueueContent(queue, 3, msg[kHi][0], msg[kMd][0], msg[kLo][0]);
|
||||
|
||||
// Remove messages from the queue
|
||||
queue.Dequeue(*msgHigh[0]);
|
||||
VerifyPriorityQueueContent(queue, 2, msgNor[0], msgLow[0]);
|
||||
queue.Dequeue(*msgLow[0]);
|
||||
VerifyPriorityQueueContent(queue, 1, msgNor[0]);
|
||||
queue.Dequeue(*msgNor[0]);
|
||||
queue.Dequeue(*msg[kHi][0]);
|
||||
VerifyPriorityQueueContent(queue, 2, msg[kMd][0], msg[kLo][0]);
|
||||
queue.Dequeue(*msg[kLo][0]);
|
||||
VerifyPriorityQueueContent(queue, 1, msg[kMd][0]);
|
||||
queue.Dequeue(*msg[kMd][0]);
|
||||
VerifyPriorityQueueContent(queue, 0);
|
||||
|
||||
for (Message *message : msgNor)
|
||||
for (Message *message : msg[kMd])
|
||||
{
|
||||
SuccessOrQuit(message->SetPriority(Message::kPriorityNormal));
|
||||
}
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Range-based `for` and dequeue during iteration
|
||||
|
||||
for (uint16_t removeIndex = 0; removeIndex < 4; removeIndex++)
|
||||
{
|
||||
uint16_t index = 0;
|
||||
|
||||
queue.Enqueue(*msgNor[0]);
|
||||
queue.Enqueue(*msgNor[1]);
|
||||
queue.Enqueue(*msgNor[2]);
|
||||
queue.Enqueue(*msgNor[3]);
|
||||
VerifyPriorityQueueContent(queue, 4, msgNor[0], msgNor[1], msgNor[2], msgNor[3]);
|
||||
queue.Enqueue(*msg[kMd][0]);
|
||||
queue.Enqueue(*msg[kMd][1]);
|
||||
queue.Enqueue(*msg[kMd][2]);
|
||||
queue.Enqueue(*msg[kMd][3]);
|
||||
VerifyPriorityQueueContent(queue, 4, msg[kMd][0], msg[kMd][1], msg[kMd][2], msg[kMd][3]);
|
||||
|
||||
// While iterating over the queue remove the entry at `removeIndex`
|
||||
for (Message &message : queue)
|
||||
@@ -278,7 +675,7 @@ void TestPriorityQueue(void)
|
||||
queue.Dequeue(message);
|
||||
}
|
||||
|
||||
VerifyOrQuit(&message == msgNor[index++]);
|
||||
VerifyOrQuit(&message == msg[kMd][index++]);
|
||||
}
|
||||
|
||||
index = 0;
|
||||
@@ -291,7 +688,7 @@ void TestPriorityQueue(void)
|
||||
index++;
|
||||
}
|
||||
|
||||
VerifyOrQuit(&message == msgNor[index++]);
|
||||
VerifyOrQuit(&message == msg[kMd][index++]);
|
||||
queue.Dequeue(message);
|
||||
}
|
||||
|
||||
@@ -300,6 +697,7 @@ void TestPriorityQueue(void)
|
||||
|
||||
testFreeInstance(instance);
|
||||
}
|
||||
// NOLINTEND(modernize-loop-convert)
|
||||
|
||||
} // namespace ot
|
||||
|
||||
|
||||
Reference in New Issue
Block a user