[message-pool] evict indirect message buffers if no available buffers (#2188)

Message buffer allocation can fail if there are no available message
buffers.  Without a way to evict messages, critical messages (i.e. MLE
Advertisements) needed to maintain the Thread network cannot be generated.

This commit takes a first step towards evicting queued message buffers. In
particular, this commit evicts indirect messages from the head of queue
until there are enough available buffers.

Future commits will seek to implement fairness and priority mechanisms to
better select which messages are evicted from the send queue.
This commit is contained in:
Jonathan Hui
2017-09-14 18:33:24 -07:00
committed by GitHub
parent 782328a6c2
commit 643eed78bd
3 changed files with 72 additions and 10 deletions
+13 -10
View File
@@ -37,6 +37,7 @@
#include "message.hpp"
#include "openthread-instance.h"
#include "common/code_utils.hpp"
#include "common/debug.hpp"
#include "common/logging.hpp"
@@ -70,6 +71,8 @@ Message *MessagePool::New(uint8_t aType, uint16_t aReserved)
{
Message *message = NULL;
SuccessOrExit(ReclaimBuffers(1));
VerifyOrExit((message = static_cast<Message *>(NewBuffer())) != NULL);
memset(message, 0, sizeof(*message));
@@ -146,18 +149,18 @@ void MessagePool::FreeBuffers(Buffer *aBuffer)
otError MessagePool::ReclaimBuffers(int aNumBuffers)
{
uint16_t numFreeBuffers;
while (aNumBuffers > GetFreeBufferCount())
{
MeshForwarder &meshForwarder = GetInstance().mThreadNetif.GetMeshForwarder();
SuccessOrExit(meshForwarder.EvictIndirectMessage());
}
#if OPENTHREAD_CONFIG_PLATFORM_MESSAGE_MANAGEMENT
numFreeBuffers = otPlatMessagePoolNumFreeBuffers(&GetInstance());
#else
numFreeBuffers = mNumFreeBuffers;
#endif
exit:
//First comparison is to get around issues with comparing
//signed and unsigned numbers, if aNumBuffers is negative then
//the second comparison wont be attempted.
if (aNumBuffers < 0 || aNumBuffers <= numFreeBuffers)
// First comparison is to get around issues with comparing
// signed and unsigned numbers, if aNumBuffers is negative then
// the second comparison wont be attempted.
if (aNumBuffers < 0 || aNumBuffers <= GetFreeBufferCount())
{
return OT_ERROR_NONE;
}
+49
View File
@@ -237,6 +237,55 @@ void MeshForwarder::UpdateIndirectMessages(void)
}
}
otError MeshForwarder::EvictIndirectMessage(void)
{
otError error = OT_ERROR_NOT_FOUND;
for (Message *message = mSendQueue.GetHead(); message; message = message->GetNext())
{
if (!message->IsChildPending())
{
continue;
}
RemoveMessage(*message);
ExitNow(error = OT_ERROR_NONE);
}
exit:
return error;
}
void MeshForwarder::RemoveMessage(Message &aMessage)
{
Child *children;
uint8_t numChildren;
children = GetNetif().GetMle().GetChildren(&numChildren);
for (uint8_t i = 0; i < numChildren; i++)
{
if (aMessage.GetChildMask(i))
{
aMessage.ClearChildMask(i);
mSourceMatchController.DecrementMessageCount(children[i]);
if (children[i].GetIndirectMessage() == &aMessage)
{
children[i].SetIndirectMessage(NULL);
}
}
}
if (mSendMessage == &aMessage)
{
mSendMessage = NULL;
}
mSendQueue.Dequeue(aMessage);
aMessage.Free();
}
void MeshForwarder::RemoveMessages(Child &aChild, uint8_t aSubType)
{
ThreadNetif &netif = GetNetif();
+10
View File
@@ -173,6 +173,15 @@ public:
*/
void RemoveMessages(Child &aChild, uint8_t aSubType);
/**
* This method evicts the first indirect message in the indirect send queue.
*
* @retval OT_ERROR_NONE Successfully evicted an indirect message.
* @retval OT_ERROR_NOT_FOUND No indirect messages available to evict.
*
*/
otError EvictIndirectMessage(void);
/**
* This method returns a reference to the send queue.
*
@@ -281,6 +290,7 @@ private:
otError HandleDatagram(Message &aMessage, const otThreadLinkInfo &aLinkInfo,
const Mac::Address &aMacSource);
void ClearReassemblyList(void);
void RemoveMessage(Message &aMessage);
static void HandleReceivedFrame(Mac::Receiver &aReceiver, Mac::Frame &aFrame);
void HandleReceivedFrame(Mac::Frame &aFrame);