From 643eed78bd6164482b2a9eadd2fb29413b3d9b2e Mon Sep 17 00:00:00 2001 From: Jonathan Hui Date: Thu, 14 Sep 2017 18:33:24 -0700 Subject: [PATCH] [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. --- src/core/common/message.cpp | 23 ++++++++------ src/core/thread/mesh_forwarder.cpp | 49 ++++++++++++++++++++++++++++++ src/core/thread/mesh_forwarder.hpp | 10 ++++++ 3 files changed, 72 insertions(+), 10 deletions(-) diff --git a/src/core/common/message.cpp b/src/core/common/message.cpp index c191c1191..65cabe99d 100644 --- a/src/core/common/message.cpp +++ b/src/core/common/message.cpp @@ -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(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; } diff --git a/src/core/thread/mesh_forwarder.cpp b/src/core/thread/mesh_forwarder.cpp index 066f54a11..deafbc2bf 100644 --- a/src/core/thread/mesh_forwarder.cpp +++ b/src/core/thread/mesh_forwarder.cpp @@ -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(); diff --git a/src/core/thread/mesh_forwarder.hpp b/src/core/thread/mesh_forwarder.hpp index 76585a517..545fe4acc 100644 --- a/src/core/thread/mesh_forwarder.hpp +++ b/src/core/thread/mesh_forwarder.hpp @@ -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);