Adding otMessageQueue OpenThread C APIs and their unit test (#1115)

This commit is contained in:
Abtin Keshavarzian
2017-01-09 08:33:26 -08:00
committed by Jonathan Hui
parent 23396a30f8
commit 3fbba0eced
6 changed files with 258 additions and 25 deletions
+60 -1
View File
@@ -29,7 +29,7 @@
/**
* @file
* @brief
* This file defines the top-level ip6 functions for the OpenThread library.
* This file defines the top-level OpenThread APIs related to message buffer and queues.
*/
#ifndef OPENTHREAD_MESSAGE_H_
@@ -229,6 +229,65 @@ int otReadMessage(otMessage aMessage, uint16_t aOffset, void *aBuf, uint16_t aLe
*/
int otWriteMessage(otMessage aMessage, uint16_t aOffset, const void *aBuf, uint16_t aLength);
/**
*
* Initialize the message queue.
*
* This function MUST be called once and only once for a `otMessageQueue` instance before any other `otMessageQueue`
* functions. The behavior is undefined if other queue APIs are used with an `otMessageQueue` before it being
* initialized or if it is initialized more than once.
*
* @param[in] aQueue A pointer to a message queue.
*
*/
void otMessageQueueInit(otMessageQueue *aQueue);
/**
* This function adds a message to the end of the given message queue.
*
* @param[in] aQueue A pointer to the message queue.
* @param[in] aMessage The message to add.
*
* @retval kThreadError_None Successfully added the message to the queue.
* @retval kThreadError_Already The message is already enqueued in a queue.
*
*/
ThreadError otMessageQueueEnqueue(otMessageQueue *aQueue, otMessage aMessage);
/**
* This function removes a message from the given message queue.
*
* @param[in] aQueue A pointer to the message queue.
* @param[in] aMessage The message to remove.
*
* @retval kThreadError_None Successfully removed the message from the queue.
* @retval kThreadError_NotFound The message is not enqueued in this queue.
*
*/
ThreadError otMessageQueueDequeue(otMessageQueue *aQueue, otMessage aMessage);
/**
* This function returns a pointer to the message at the head of the queue.
*
* @param[in] aQueue A pointer to a message queue.
*
* @returns A pointer to the message at the head of queue or NULL if queue is empty.
*
*/
otMessage otMessageQueueGetHead(otMessageQueue *aQueue);
/**
* This function returns a pointer to the next message in the queue by iterating forward (from head to tail).
*
* @param[in] aQueue A pointer to a message queue.
* @param[in] aMessage A pointer to current message buffer.
*
* @returns A pointer to the next message in the queue after `aMessage` or NULL if `aMessage is the tail of queue.
* NULL is returned if `aMessage` is not in the queue `aQueue`.
*
*/
otMessage otMessageQueueGetNext(otMessageQueue *aQueue, const otMessage aMessage);
/**
* @}
*
+8
View File
@@ -959,6 +959,14 @@ typedef struct
*/
typedef void *otMessage;
/**
* This structure represents an OpenThread message queue.
*/
typedef struct
{
void *mData; ///< Opaque data used by the implementation.
} otMessageQueue;
/**
* @}
*
+12 -12
View File
@@ -874,9 +874,9 @@ void Message::SetPriorityQueue(PriorityQueue *aPriorityQueue)
mInfo.mInPriorityQ = true;
}
MessageQueue::MessageQueue(void) :
mTail(NULL)
MessageQueue::MessageQueue(void)
{
SetTail(NULL);
}
void MessageQueue::AddToList(uint8_t aList, Message &aMessage)
@@ -885,36 +885,36 @@ void MessageQueue::AddToList(uint8_t aList, Message &aMessage)
assert((aMessage.Next(aList) == NULL) && (aMessage.Prev(aList) == NULL));
if (mTail == NULL)
if (GetTail() == NULL)
{
aMessage.Next(aList) = &aMessage;
aMessage.Prev(aList) = &aMessage;
}
else
{
head = mTail->Next(aList);
head = GetTail()->Next(aList);
aMessage.Next(aList) = head;
aMessage.Prev(aList) = mTail;
aMessage.Prev(aList) = GetTail();
head->Prev(aList) = &aMessage;
mTail->Next(aList) = &aMessage;
GetTail()->Next(aList) = &aMessage;
}
mTail = &aMessage;
SetTail(&aMessage);
}
void MessageQueue::RemoveFromList(uint8_t aList, Message &aMessage)
{
assert((aMessage.Next(aList) != NULL) && (aMessage.Prev(aList) != NULL));
if (&aMessage == mTail)
if (&aMessage == GetTail())
{
mTail = mTail->Prev(aList);
SetTail(GetTail()->Prev(aList));
if (&aMessage == mTail)
if (&aMessage == GetTail())
{
mTail = NULL;
SetTail(NULL);
}
}
@@ -927,7 +927,7 @@ void MessageQueue::RemoveFromList(uint8_t aList, Message &aMessage)
Message *MessageQueue::GetHead(void) const
{
return (mTail == NULL) ? NULL : mTail->Next(MessageInfo::kListInterface);
return (GetTail() == NULL) ? NULL : GetTail()->Next(MessageInfo::kListInterface);
}
ThreadError MessageQueue::Enqueue(Message &aMessage)
+18 -12
View File
@@ -610,6 +610,14 @@ public:
*/
uint16_t UpdateChecksum(uint16_t aChecksum, uint16_t aOffset, uint16_t aLength) const;
/**
* This method returns a pointer to the message queue (if any) where this message is queued.
*
* @returns A pointer to the message queue or NULL if not in any message queue.
*
*/
MessageQueue *GetMessageQueue(void) const { return (!mInfo.mInPriorityQ) ? mInfo.mMessageQueue : NULL; }
private:
/**
@@ -636,14 +644,6 @@ private:
*/
bool IsInAQueue(void) const { return (mInfo.mMessageQueue != NULL); }
/**
* This method returns a pointer to the message queue (if any) where this message is queued.
*
* @returns A pointer to the message queue or NULL if not in any message queue.
*
*/
MessageQueue *GetMessageQueue(void) const { return (!mInfo.mInPriorityQ) ? mInfo.mMessageQueue : NULL; }
/**
* This method sets the message queue information for the message.
*
@@ -738,7 +738,7 @@ private:
* This class implements a message queue.
*
*/
class MessageQueue
class MessageQueue : public otMessageQueue
{
friend class Message;
friend class PriorityQueue;
@@ -797,7 +797,15 @@ private:
* @returns A pointer to the tail of the list.
*
*/
Message *GetTail(void) const { return mTail; }
Message *GetTail(void) const { return static_cast<Message *>(mData); }
/**
* This method set the tail of the list.
*
* @param[in] aMessage A pointer to the message to set as new tail.
*
*/
void SetTail(Message *aMessage) { mData = aMessage; }
/**
* This method adds a message to a list.
@@ -816,8 +824,6 @@ private:
*
*/
void RemoveFromList(uint8_t aListId, Message &aMessage);
Message *mTail; ///< A pointer to the last Message in the list.
};
/**
+39
View File
@@ -1489,6 +1489,45 @@ int otWriteMessage(otMessage aMessage, uint16_t aOffset, const void *aBuf, uint1
return message->Write(aOffset, aLength, aBuf);
}
void otMessageQueueInit(otMessageQueue *aQueue)
{
aQueue->mData = NULL;
}
ThreadError otMessageQueueEnqueue(otMessageQueue *aQueue, otMessage aMessage)
{
Message *message = static_cast<Message *>(aMessage);
MessageQueue *queue = static_cast<MessageQueue *>(aQueue);
return queue->Enqueue(*message);
}
ThreadError otMessageQueueDequeue(otMessageQueue *aQueue, otMessage aMessage)
{
Message *message = static_cast<Message *>(aMessage);
MessageQueue *queue = static_cast<MessageQueue *>(aQueue);
return queue->Dequeue(*message);
}
otMessage otMessageQueueGetHead(otMessageQueue *aQueue)
{
MessageQueue *queue = static_cast<MessageQueue *>(aQueue);
return queue->GetHead();
}
otMessage otMessageQueueGetNext(otMessageQueue *aQueue, otMessage aMessage)
{
Message *next;
Message *message = static_cast<Message *>(aMessage);
MessageQueue *queue = static_cast<MessageQueue *>(aQueue);
VerifyOrExit(message != NULL, next = NULL);
VerifyOrExit(message->GetMessageQueue() == queue, next = NULL);
next = message->GetNext();
exit:
return next;
}
ThreadError otOpenUdpSocket(otInstance *aInstance, otUdpSocket *aSocket, otUdpReceive aCallback, void *aCallbackContext)
{
ThreadError error = kThreadError_InvalidArgs;
+121
View File
@@ -27,9 +27,14 @@
*/
#include "test_util.h"
#include <openthread.h>
#include <openthread-message.h>
#include <openthread-ip6.h>
#include <common/debug.hpp>
#include <common/message.hpp>
#include <string.h>
#include <stdarg.h>
@@ -72,6 +77,7 @@ void TestMessageQueue(void)
Thread::MessagePool messagePool;
Thread::MessageQueue messageQueue;
Thread::Message *msg[kNumTestMessages];
ThreadError error;
uint16_t msgCount, bufferCount;
for (int i = 0; i < kNumTestMessages; i++)
@@ -131,12 +137,127 @@ void TestMessageQueue(void)
VerifyMessageQueueContent(messageQueue, 1, msg[0]);
SuccessOrQuit(messageQueue.Dequeue(*msg[0]), "MessageQueue::Dequeue() failed.\n");
VerifyMessageQueueContent(messageQueue, 0);
// Check the failure cases: Enqueue an already queued message or dequeue a message not in the queue.
SuccessOrQuit(messageQueue.Enqueue(*msg[0]), "MessageQueue::Enqueue() failed.\n");
VerifyMessageQueueContent(messageQueue, 1, msg[0]);
error = messageQueue.Enqueue(*msg[0]);
VerifyOrQuit(error == kThreadError_Already, "Enqueuing an already queued message did not fail as expected.\n");
error = messageQueue.Dequeue(*msg[1]);
VerifyOrQuit(error == kThreadError_NotFound, "Dequeuing a message not in the queue did not fail as expected.\n");
}
// This function verifies the content of the message queue to match the passed in messages
void VerifyMessageQueueContentUsingOtApi(otMessageQueue *aQueue, int aExpectedLength, ...)
{
va_list args;
otMessage message;
otMessage msgArg;
va_start(args, aExpectedLength);
if (aExpectedLength == 0)
{
message = otMessageQueueGetHead(aQueue);
VerifyOrQuit(message == NULL, "MessageQueue is not empty when expected len is zero.\n");
}
else
{
for (message = otMessageQueueGetHead(aQueue);
message != NULL;
message = otMessageQueueGetNext(aQueue, message)
)
{
VerifyOrQuit(aExpectedLength != 0, "MessageQueue contains more entries than expected\n");
msgArg = va_arg(args, otMessage);
VerifyOrQuit(msgArg == message, "MessageQueue content does not match what is expected.\n");
aExpectedLength--;
}
VerifyOrQuit(aExpectedLength == 0, "MessageQueue contains less entries than expected\n");
}
va_end(args);
}
// This test checks all the OpenThread C APIs for `otMessageQueue`
void TestMessageQueueOtApis(void)
{
otInstance *instance;
otMessageQueue queue, queue2;
otMessage msg[kNumTestMessages];
ThreadError error;
otMessage message;
instance = otInstanceInit();
VerifyOrQuit(instance != NULL, "Failed to get and init an otInstance.\n");
for (int i = 0; i < kNumTestMessages; i++)
{
msg[i] = otNewIp6Message(instance, true);
VerifyOrQuit(msg[i] != NULL, "otNewIp6Message() failed.\n");
}
otMessageQueueInit(&queue);
otMessageQueueInit(&queue2);
// Check an empty queue.
VerifyMessageQueueContentUsingOtApi(&queue, 0);
// Add message to the queue and check the content
SuccessOrQuit(otMessageQueueEnqueue(&queue, msg[0]), "Failed to enqueue a message to otMessageQueue.\n");
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(otMessageQueueEnqueue(&queue, msg[3]), "Failed to enqueue a message to otMessageQueue.\n");
VerifyMessageQueueContentUsingOtApi(&queue, 4, msg[0], msg[1], msg[2], 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]);
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");
VerifyMessageQueueContentUsingOtApi(&queue, 1, msg[2]);
// Check the expected failure cases for the enqueue and dequeue:
error = otMessageQueueEnqueue(&queue, msg[2]);
VerifyOrQuit(error == kThreadError_Already, "Enqueuing an already queued message did not fail as expected.\n");
error = otMessageQueueDequeue(&queue, msg[0]);
VerifyOrQuit(error == kThreadError_NotFound, "Dequeuing a message not in the queue did not fail as expected.\n");
// Check the failure cases for otMessageQueueGetNext()
message = otMessageQueueGetNext(&queue, NULL);
VerifyOrQuit(message == NULL, "otMessageQueueGetNext(queue, NULL) did not return NULL.\n");
message = otMessageQueueGetNext(&queue, msg[1]);
VerifyOrQuit(message == NULL, "otMessageQueueGetNext() did not return NULL for a message not in the queue.\n");
// Check the failure case when attempting to do otMessageQueueGetNext() but passing in a wrong queue pointer.
SuccessOrQuit(otMessageQueueEnqueue(&queue2, msg[0]), "Failed to enqueue a message to otMessageQueue.\n");
VerifyMessageQueueContentUsingOtApi(&queue2, 1, msg[0]);
SuccessOrQuit(otMessageQueueEnqueue(&queue2, msg[1]), "Failed to enqueue a message to otMessageQueue.\n");
VerifyMessageQueueContentUsingOtApi(&queue2, 2, msg[0], msg[1]);
message = otMessageQueueGetNext(&queue2, msg[0]);
VerifyOrQuit(message == msg[1], "otMessageQueueGetNext() failed\n");
message = otMessageQueueGetNext(&queue, msg[0]);
VerifyOrQuit(message == NULL, "otMessageQueueGetNext() did not return NULL for message not in the queue.\n");
// Remove all element and make sure queue is empty
SuccessOrQuit(otMessageQueueDequeue(&queue, msg[2]), "Failed to dequeue a message from otMessageQueue.\n");
VerifyMessageQueueContentUsingOtApi(&queue, 0);
}
#ifdef ENABLE_TEST_MAIN
int main(void)
{
TestMessageQueue();
TestMessageQueueOtApis();
printf("All tests passed\n");
return 0;
}