mirror of
https://github.com/espressif/openthread.git
synced 2026-08-04 01:47:47 +00:00
[pool] introducing a generic object pool class (#5193)
This commit adds a template `Pool<Type, kPoolSize>` class representing an object pool. `Message`, `Netif`, and `AddressResolver` classes are respectively updated to use `Pool` for managing their buffer pool, external unicast/multicast address pool, and address cache entry pool. This commit also adds a unit test for the `Pool` class.
This commit is contained in:
@@ -336,6 +336,7 @@ HEADERS_COMMON = \
|
||||
common/new.hpp \
|
||||
common/non_copyable.hpp \
|
||||
common/notifier.hpp \
|
||||
common/pool.hpp \
|
||||
common/random.hpp \
|
||||
common/random_manager.hpp \
|
||||
common/settings.hpp \
|
||||
|
||||
@@ -46,17 +46,10 @@ MessagePool::MessagePool(Instance &aInstance)
|
||||
: InstanceLocator(aInstance)
|
||||
#if !OPENTHREAD_CONFIG_PLATFORM_MESSAGE_MANAGEMENT
|
||||
, mNumFreeBuffers(kNumBuffers)
|
||||
, mFreeBuffers()
|
||||
, mBufferPool()
|
||||
#endif
|
||||
{
|
||||
#if !OPENTHREAD_CONFIG_PLATFORM_MESSAGE_MANAGEMENT
|
||||
memset(mBuffers, 0, sizeof(mBuffers));
|
||||
|
||||
for (Buffer *cur = &mBuffers[0]; cur < OT_ARRAY_END(mBuffers); cur++)
|
||||
{
|
||||
mFreeBuffers.Push(*cur);
|
||||
}
|
||||
#else
|
||||
#if OPENTHREAD_CONFIG_PLATFORM_MESSAGE_MANAGEMENT
|
||||
otPlatMessagePoolInit(&GetInstance(), kNumBuffers, sizeof(Buffer));
|
||||
#endif
|
||||
}
|
||||
@@ -118,22 +111,20 @@ Buffer *MessagePool::NewBuffer(Message::Priority aPriority)
|
||||
|
||||
#else
|
||||
|
||||
buffer = mFreeBuffers.Pop();
|
||||
buffer = mBufferPool.Allocate();
|
||||
VerifyOrExit(buffer != nullptr, OT_NOOP);
|
||||
|
||||
if (buffer != nullptr)
|
||||
{
|
||||
buffer->SetNextBuffer(nullptr);
|
||||
mNumFreeBuffers--;
|
||||
}
|
||||
mNumFreeBuffers--;
|
||||
buffer->SetNextBuffer(nullptr);
|
||||
|
||||
#endif
|
||||
|
||||
exit:
|
||||
if (buffer == nullptr)
|
||||
{
|
||||
otLogInfoMem("No available message buffer");
|
||||
}
|
||||
|
||||
exit:
|
||||
return buffer;
|
||||
}
|
||||
|
||||
@@ -145,7 +136,7 @@ void MessagePool::FreeBuffers(Buffer *aBuffer)
|
||||
#if OPENTHREAD_CONFIG_PLATFORM_MESSAGE_MANAGEMENT
|
||||
otPlatMessagePoolFree(&GetInstance(), aBuffer);
|
||||
#else
|
||||
mFreeBuffers.Push(*aBuffer);
|
||||
mBufferPool.Free(*aBuffer);
|
||||
mNumFreeBuffers++;
|
||||
#endif
|
||||
aBuffer = next;
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
#include "common/linked_list.hpp"
|
||||
#include "common/locator.hpp"
|
||||
#include "common/non_copyable.hpp"
|
||||
#include "common/pool.hpp"
|
||||
#include "mac/mac_types.hpp"
|
||||
#include "thread/link_quality.hpp"
|
||||
|
||||
@@ -1254,9 +1255,8 @@ private:
|
||||
otError ReclaimBuffers(int aNumBuffers, Message::Priority aPriority);
|
||||
|
||||
#if OPENTHREAD_CONFIG_PLATFORM_MESSAGE_MANAGEMENT == 0
|
||||
uint16_t mNumFreeBuffers;
|
||||
Buffer mBuffers[kNumBuffers];
|
||||
LinkedList<Buffer> mFreeBuffers;
|
||||
uint16_t mNumFreeBuffers;
|
||||
Pool<Buffer, kNumBuffers> mBufferPool;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* Copyright (c) 2020, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file includes definitions for a generic object pool.
|
||||
*/
|
||||
|
||||
#ifndef POOL_HPP_
|
||||
#define POOL_HPP_
|
||||
|
||||
#include "openthread-core-config.h"
|
||||
|
||||
#include "common/linked_list.hpp"
|
||||
#include "common/non_copyable.hpp"
|
||||
|
||||
namespace ot {
|
||||
|
||||
class Instance;
|
||||
|
||||
/**
|
||||
* @addtogroup core-pool
|
||||
*
|
||||
* @brief
|
||||
* This module includes definitions for OpenThread object pool.
|
||||
*
|
||||
* @{
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* This template class represents an object pool.
|
||||
*
|
||||
* @tparam Type The object type. Type should provide `GetNext() and `SetNext()` so that it can be added to a
|
||||
* linked list.
|
||||
* @tparam kPoolSize Specifies the pool size (maximum number of objects in the pool).
|
||||
*
|
||||
*/
|
||||
template <class Type, uint16_t kPoolSize> class Pool : private NonCopyable
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* This constructor initializes the pool.
|
||||
*
|
||||
*/
|
||||
Pool(void)
|
||||
: mFreeList()
|
||||
{
|
||||
for (Type &entry : mPool)
|
||||
{
|
||||
mFreeList.Push(entry);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This constructor initializes the pool.
|
||||
*
|
||||
* This constructor version requires the `Type` class to provide method `void Init(Instance &)` to initialize
|
||||
* each `Type` entry object. This can be realized by the `Type` class inheriting from `InstaceLocatorInit()`.
|
||||
*
|
||||
* @param[in] aInstance A reference to the OpenThread instance.
|
||||
*
|
||||
*/
|
||||
Pool(Instance &aInstance)
|
||||
: mFreeList()
|
||||
{
|
||||
for (Type &entry : mPool)
|
||||
{
|
||||
entry.Init(aInstance);
|
||||
mFreeList.Push(entry);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method allocates a new object from the pool.
|
||||
*
|
||||
* @returns A pointer to the newly allocated object, or nullptr if all entries from the pool are already allocated.
|
||||
*
|
||||
*/
|
||||
Type *Allocate(void) { return mFreeList.Pop(); }
|
||||
|
||||
/**
|
||||
* This method frees a previously allocated object.
|
||||
*
|
||||
* The @p aEntry MUST be an entry from the pool previously allocated using `Allocate()` method and not yet freed.
|
||||
* An already freed entry MUST not be freed again.
|
||||
*
|
||||
* @param[in] aEntry The pool object entry to free.
|
||||
*
|
||||
*/
|
||||
void Free(Type &aEntry) { mFreeList.Push(aEntry); }
|
||||
|
||||
/**
|
||||
* This method returns the pool size.
|
||||
*
|
||||
* @returns The pool size (maximum number of objects in the pool).
|
||||
*
|
||||
*/
|
||||
uint16_t GetSize(void) const { return kPoolSize; }
|
||||
|
||||
/**
|
||||
* This method indicates whether or not a given `Type` object is from the pool.
|
||||
*
|
||||
* @param[in] aObject A reference to a `Type` object.
|
||||
*
|
||||
* @retval TRUE if @p aObject is from the pool.
|
||||
* @retval FALSE if @p aObject is not from the pool.
|
||||
*
|
||||
*/
|
||||
bool IsPoolEntry(const Type &aObject) const { return (&mPool[0] <= &aObject) && (&aObject < OT_ARRAY_END(mPool)); }
|
||||
|
||||
/**
|
||||
* This method returns the associated index of a given entry from the pool.
|
||||
*
|
||||
* The @p aEntry MUST be from the pool, otherwise the behavior of this method is undefined.
|
||||
*
|
||||
* @param[in] aEntry A reference to an entry from the pool.
|
||||
*
|
||||
* @returns The associated index of @p aEntry.
|
||||
*
|
||||
*/
|
||||
uint16_t GetIndexOf(const Type &aEntry) const { return static_cast<uint16_t>(&aEntry - mPool); }
|
||||
|
||||
/**
|
||||
* This method retrieves a pool entry at a given index.
|
||||
*
|
||||
* The @p aIndex MUST be from an earlier call to `GetIndexOf()`.
|
||||
*
|
||||
* @param[in] aIndex An index.
|
||||
*
|
||||
* @returns A reference to entry at index @p aIndex.
|
||||
*
|
||||
*/
|
||||
Type &GetEntryAt(uint16_t aIndex) { return mPool[aIndex]; }
|
||||
|
||||
/**
|
||||
* This method retrieves a pool entry at a given index.
|
||||
*
|
||||
* The @p aIndex MUST be from an earlier call to `GetIndexOf()`.
|
||||
*
|
||||
* @param[in] aIndex An index.
|
||||
*
|
||||
* @returns A reference to entry at index @p aIndex.
|
||||
*
|
||||
*/
|
||||
const Type &GetEntryAt(uint16_t aIndex) const { return mPool[aIndex]; }
|
||||
|
||||
private:
|
||||
LinkedList<Type> mFreeList;
|
||||
Type mPool[kPoolSize];
|
||||
};
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
*/
|
||||
|
||||
} // namespace ot
|
||||
|
||||
#endif // POOL_HPP_
|
||||
+47
-48
@@ -86,16 +86,9 @@ Netif::Netif(Instance &aInstance)
|
||||
, mMulticastPromiscuous(false)
|
||||
, mAddressCallback(nullptr)
|
||||
, mAddressCallbackContext(nullptr)
|
||||
, mExtUnicastAddressPool()
|
||||
, mExtMulticastAddressPool()
|
||||
{
|
||||
for (NetifUnicastAddress &entry : mExtUnicastAddresses)
|
||||
{
|
||||
entry.MarkAsNotInUse();
|
||||
}
|
||||
|
||||
for (NetifMulticastAddress &entry : mExtMulticastAddresses)
|
||||
{
|
||||
entry.MarkAsNotInUse();
|
||||
}
|
||||
}
|
||||
|
||||
bool Netif::IsMulticastSubscribed(const Address &aAddress) const
|
||||
@@ -290,6 +283,11 @@ exit:
|
||||
return;
|
||||
}
|
||||
|
||||
bool Netif::IsMulticastAddressExternal(const NetifMulticastAddress &aAddress) const
|
||||
{
|
||||
return mExtMulticastAddressPool.IsPoolEntry(aAddress);
|
||||
}
|
||||
|
||||
void Netif::SubscribeMulticast(NetifMulticastAddress &aAddress)
|
||||
{
|
||||
SuccessOrExit(mMulticastAddresses.Add(aAddress));
|
||||
@@ -321,6 +319,7 @@ otError Netif::SubscribeExternalMulticast(const Address &aAddress)
|
||||
otError error = OT_ERROR_NONE;
|
||||
NetifMulticastAddress &linkLocalAllRoutersAddress = static_cast<NetifMulticastAddress &>(
|
||||
const_cast<otNetifMulticastAddress &>(kLinkLocalAllRoutersMulticastAddress));
|
||||
NetifMulticastAddress *entry;
|
||||
|
||||
VerifyOrExit(!IsMulticastSubscribed(aAddress), error = OT_ERROR_ALREADY);
|
||||
|
||||
@@ -333,18 +332,12 @@ otError Netif::SubscribeExternalMulticast(const Address &aAddress)
|
||||
VerifyOrExit(cur->GetAddress() != aAddress, error = OT_ERROR_INVALID_ARGS);
|
||||
}
|
||||
|
||||
for (NetifMulticastAddress &entry : mExtMulticastAddresses)
|
||||
{
|
||||
if (!entry.IsInUse())
|
||||
{
|
||||
entry.mAddress = aAddress;
|
||||
mMulticastAddresses.Push(entry);
|
||||
Get<Notifier>().Signal(kEventIp6MulticastSubscribed);
|
||||
ExitNow();
|
||||
}
|
||||
}
|
||||
entry = mExtMulticastAddressPool.Allocate();
|
||||
VerifyOrExit(entry != nullptr, error = OT_ERROR_NO_BUFS);
|
||||
|
||||
error = OT_ERROR_NO_BUFS;
|
||||
entry->mAddress = aAddress;
|
||||
mMulticastAddresses.Push(*entry);
|
||||
Get<Notifier>().Signal(kEventIp6MulticastSubscribed);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
@@ -363,7 +356,7 @@ otError Netif::UnsubscribeExternalMulticast(const Address &aAddress)
|
||||
|
||||
mMulticastAddresses.PopAfter(prev);
|
||||
|
||||
entry->MarkAsNotInUse();
|
||||
mExtMulticastAddressPool.Free(*entry);
|
||||
|
||||
Get<Notifier>().Signal(kEventIp6MulticastUnsubscribed);
|
||||
|
||||
@@ -373,11 +366,15 @@ exit:
|
||||
|
||||
void Netif::UnsubscribeAllExternalMulticastAddresses(void)
|
||||
{
|
||||
for (NetifMulticastAddress &entry : mExtMulticastAddresses)
|
||||
NetifMulticastAddress *next;
|
||||
|
||||
for (NetifMulticastAddress *entry = mMulticastAddresses.GetHead(); entry != nullptr; entry = next)
|
||||
{
|
||||
if (entry.IsInUse())
|
||||
next = entry->GetNext();
|
||||
|
||||
if (IsMulticastAddressExternal(*entry))
|
||||
{
|
||||
IgnoreError(UnsubscribeExternalMulticast(entry.GetAddress()));
|
||||
IgnoreError(UnsubscribeExternalMulticast(entry->GetAddress()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -417,36 +414,30 @@ exit:
|
||||
otError Netif::AddExternalUnicastAddress(const NetifUnicastAddress &aAddress)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
NetifUnicastAddress *existingEntry;
|
||||
NetifUnicastAddress *entry;
|
||||
NetifUnicastAddress *prev;
|
||||
|
||||
existingEntry = mUnicastAddresses.FindMatching(aAddress.GetAddress(), prev);
|
||||
entry = mUnicastAddresses.FindMatching(aAddress.GetAddress(), prev);
|
||||
|
||||
if (existingEntry != nullptr)
|
||||
if (entry != nullptr)
|
||||
{
|
||||
VerifyOrExit(IsUnicastAddressExternal(*existingEntry), error = OT_ERROR_ALREADY);
|
||||
VerifyOrExit(IsUnicastAddressExternal(*entry), error = OT_ERROR_ALREADY);
|
||||
|
||||
existingEntry->mPrefixLength = aAddress.mPrefixLength;
|
||||
existingEntry->mAddressOrigin = aAddress.mAddressOrigin;
|
||||
existingEntry->mPreferred = aAddress.mPreferred;
|
||||
existingEntry->mValid = aAddress.mValid;
|
||||
entry->mPrefixLength = aAddress.mPrefixLength;
|
||||
entry->mAddressOrigin = aAddress.mAddressOrigin;
|
||||
entry->mPreferred = aAddress.mPreferred;
|
||||
entry->mValid = aAddress.mValid;
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
VerifyOrExit(!aAddress.GetAddress().IsLinkLocal(), error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
for (NetifUnicastAddress &entry : mExtUnicastAddresses)
|
||||
{
|
||||
if (!entry.IsInUse())
|
||||
{
|
||||
entry = aAddress;
|
||||
mUnicastAddresses.Push(entry);
|
||||
Get<Notifier>().Signal(kEventIp6AddressAdded);
|
||||
ExitNow();
|
||||
}
|
||||
}
|
||||
entry = mExtUnicastAddressPool.Allocate();
|
||||
VerifyOrExit(entry != nullptr, error = OT_ERROR_NO_BUFS);
|
||||
|
||||
error = OT_ERROR_NO_BUFS;
|
||||
*entry = aAddress;
|
||||
mUnicastAddresses.Push(*entry);
|
||||
Get<Notifier>().Signal(kEventIp6AddressAdded);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
@@ -464,8 +455,7 @@ otError Netif::RemoveExternalUnicastAddress(const Address &aAddress)
|
||||
VerifyOrExit(IsUnicastAddressExternal(*entry), error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
mUnicastAddresses.PopAfter(prev);
|
||||
|
||||
entry->MarkAsNotInUse();
|
||||
mExtUnicastAddressPool.Free(*entry);
|
||||
Get<Notifier>().Signal(kEventIp6AddressRemoved);
|
||||
|
||||
exit:
|
||||
@@ -474,11 +464,15 @@ exit:
|
||||
|
||||
void Netif::RemoveAllExternalUnicastAddresses(void)
|
||||
{
|
||||
for (NetifUnicastAddress &entry : mExtUnicastAddresses)
|
||||
NetifUnicastAddress *next;
|
||||
|
||||
for (NetifUnicastAddress *entry = mUnicastAddresses.GetHead(); entry != nullptr; entry = next)
|
||||
{
|
||||
if (entry.IsInUse())
|
||||
next = entry->GetNext();
|
||||
|
||||
if (IsUnicastAddressExternal(*entry))
|
||||
{
|
||||
IgnoreError(RemoveExternalUnicastAddress(entry.GetAddress()));
|
||||
IgnoreError(RemoveExternalUnicastAddress(entry->GetAddress()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -490,5 +484,10 @@ bool Netif::HasUnicastAddress(const Address &aAddress) const
|
||||
return mUnicastAddresses.FindMatching(aAddress, prev) != nullptr;
|
||||
}
|
||||
|
||||
bool Netif::IsUnicastAddressExternal(const NetifUnicastAddress &aAddress) const
|
||||
{
|
||||
return mExtUnicastAddressPool.IsPoolEntry(aAddress);
|
||||
}
|
||||
|
||||
} // namespace Ip6
|
||||
} // namespace ot
|
||||
|
||||
+4
-20
@@ -103,11 +103,6 @@ public:
|
||||
|
||||
private:
|
||||
bool Matches(const Address &aAddress) const { return GetAddress() == aAddress; }
|
||||
|
||||
// In an unused/available entry (i.e., entry not present in a linked
|
||||
// list), the next pointer is set to point back to the entry itself.
|
||||
bool IsInUse(void) const { return GetNext() != this; }
|
||||
void MarkAsNotInUse(void) { SetNext(this); }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -159,11 +154,6 @@ public:
|
||||
|
||||
private:
|
||||
bool Matches(const Address &aAddress) const { return GetAddress() == aAddress; }
|
||||
|
||||
// In an unused/available entry (i.e., entry not present in a linked
|
||||
// list), the next pointer is set to point back to the entry itself.
|
||||
bool IsInUse(void) const { return GetNext() != this; }
|
||||
void MarkAsNotInUse(void) { mNext = this; }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -254,10 +244,7 @@ public:
|
||||
* @retval FALSE The address is not an external address (it is an OpenThread internal address).
|
||||
*
|
||||
*/
|
||||
bool IsUnicastAddressExternal(const NetifUnicastAddress &aAddress) const
|
||||
{
|
||||
return (&mExtUnicastAddresses[0] <= &aAddress) && (&aAddress < OT_ARRAY_END(mExtUnicastAddresses));
|
||||
}
|
||||
bool IsUnicastAddressExternal(const NetifUnicastAddress &aAddress) const;
|
||||
|
||||
/**
|
||||
* This method adds an external (to OpenThread) unicast address to the network interface.
|
||||
@@ -336,10 +323,7 @@ public:
|
||||
* @retval FALSE The address is not an external address (it is an OpenThread internal address).
|
||||
*
|
||||
*/
|
||||
bool IsMulticastAddressExternal(const NetifMulticastAddress &aAddress) const
|
||||
{
|
||||
return (&mExtMulticastAddresses[0] <= &aAddress) && (&aAddress < OT_ARRAY_END(mExtMulticastAddresses));
|
||||
}
|
||||
bool IsMulticastAddressExternal(const NetifMulticastAddress &aAddress) const;
|
||||
|
||||
/**
|
||||
* This method subscribes the network interface to a multicast address.
|
||||
@@ -446,8 +430,8 @@ private:
|
||||
otIp6AddressCallback mAddressCallback;
|
||||
void * mAddressCallbackContext;
|
||||
|
||||
NetifUnicastAddress mExtUnicastAddresses[OPENTHREAD_CONFIG_IP6_MAX_EXT_UCAST_ADDRS];
|
||||
NetifMulticastAddress mExtMulticastAddresses[OPENTHREAD_CONFIG_IP6_MAX_EXT_MCAST_ADDRS];
|
||||
Pool<NetifUnicastAddress, OPENTHREAD_CONFIG_IP6_MAX_EXT_UCAST_ADDRS> mExtUnicastAddressPool;
|
||||
Pool<NetifMulticastAddress, OPENTHREAD_CONFIG_IP6_MAX_EXT_MCAST_ADDRS> mExtMulticastAddressPool;
|
||||
|
||||
static const otNetifMulticastAddress kRealmLocalAllMplForwardersMulticastAddress;
|
||||
static const otNetifMulticastAddress kLinkLocalAllNodesMulticastAddress;
|
||||
|
||||
@@ -57,20 +57,14 @@ AddressResolver::AddressResolver(Instance &aInstance)
|
||||
, mAddressError(OT_URI_PATH_ADDRESS_ERROR, &AddressResolver::HandleAddressError, this)
|
||||
, mAddressQuery(OT_URI_PATH_ADDRESS_QUERY, &AddressResolver::HandleAddressQuery, this)
|
||||
, mAddressNotification(OT_URI_PATH_ADDRESS_NOTIFY, &AddressResolver::HandleAddressNotification, this)
|
||||
, mCacheEntryPool(aInstance)
|
||||
, mCachedList()
|
||||
, mSnoopedList()
|
||||
, mQueryList()
|
||||
, mQueryRetryList()
|
||||
, mUnusedList()
|
||||
, mIcmpHandler(&AddressResolver::HandleIcmpReceive, this)
|
||||
, mTimer(aInstance, AddressResolver::HandleTimer, this)
|
||||
{
|
||||
for (CacheEntry *entry = &mCacheEntries[0]; entry < OT_ARRAY_END(mCacheEntries); entry++)
|
||||
{
|
||||
entry->Init(GetInstance());
|
||||
mUnusedList.Push(*entry);
|
||||
}
|
||||
|
||||
Get<Coap::Coap>().AddResource(mAddressError);
|
||||
Get<Coap::Coap>().AddResource(mAddressQuery);
|
||||
Get<Coap::Coap>().AddResource(mAddressNotification);
|
||||
@@ -94,7 +88,7 @@ void AddressResolver::Clear(void)
|
||||
Get<MeshForwarder>().HandleResolved(entry->GetTarget(), OT_ERROR_DROP);
|
||||
}
|
||||
|
||||
mUnusedList.Push(*entry);
|
||||
mCacheEntryPool.Free(*entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -210,7 +204,7 @@ void AddressResolver::Remove(Mac::ShortAddress aRloc16, bool aMatchRouterId)
|
||||
(!aMatchRouterId && (entry->GetRloc16() == aRloc16)))
|
||||
{
|
||||
RemoveCacheEntry(*entry, *list, prev, aMatchRouterId ? kReasonRemovingRouterId : kReasonRemovingRloc16);
|
||||
mUnusedList.Push(*entry);
|
||||
mCacheEntryPool.Free(*entry);
|
||||
|
||||
// If the entry is removed from list, we keep the same
|
||||
// `prev` pointer.
|
||||
@@ -256,7 +250,7 @@ void AddressResolver::Remove(const Ip6::Address &aEid, Reason aReason)
|
||||
VerifyOrExit(entry != nullptr, OT_NOOP);
|
||||
|
||||
RemoveCacheEntry(*entry, *list, prev, aReason);
|
||||
mUnusedList.Push(*entry);
|
||||
mCacheEntryPool.Free(*entry);
|
||||
|
||||
exit:
|
||||
return;
|
||||
@@ -269,7 +263,7 @@ AddressResolver::CacheEntry *AddressResolver::NewCacheEntry(bool aSnoopedEntry)
|
||||
CacheEntryList *lists[] = {&mSnoopedList, &mQueryRetryList, &mQueryList, &mCachedList};
|
||||
|
||||
// The following order is used when trying to allocate a new cache
|
||||
// entry: First the unused list is checked, followed by the list
|
||||
// entry: First the cache pool is checked, followed by the list
|
||||
// of snooped entries, then query-retry list (entries in delay
|
||||
// retry timeout wait due to a prior query failing to get a
|
||||
// response), then the query list (entries actively querying and
|
||||
@@ -279,7 +273,7 @@ AddressResolver::CacheEntry *AddressResolver::NewCacheEntry(bool aSnoopedEntry)
|
||||
// can be evicted (e.g., first time query entries can not be
|
||||
// evicted till timeout).
|
||||
|
||||
newEntry = mUnusedList.Pop();
|
||||
newEntry = mCacheEntryPool.Allocate();
|
||||
VerifyOrExit(newEntry == nullptr, OT_NOOP);
|
||||
|
||||
for (size_t index = 0; index < OT_ARRAY_LENGTH(lists); index++)
|
||||
@@ -515,7 +509,7 @@ otError AddressResolver::Resolve(const Ip6::Address &aEid, uint16_t &aRloc16)
|
||||
entry->SetTimeout(kAddressQueryTimeout);
|
||||
|
||||
error = SendAddressQuery(aEid);
|
||||
VerifyOrExit(error == OT_ERROR_NONE, mUnusedList.Push(*entry));
|
||||
VerifyOrExit(error == OT_ERROR_NONE, mCacheEntryPool.Free(*entry));
|
||||
|
||||
if (list == nullptr)
|
||||
{
|
||||
@@ -1059,18 +1053,18 @@ void AddressResolver::CacheEntry::Init(Instance &aInstance)
|
||||
|
||||
AddressResolver::CacheEntry *AddressResolver::CacheEntry::GetNext(void)
|
||||
{
|
||||
return (mNextIndex == kNoNextIndex) ? nullptr : &Get<AddressResolver>().mCacheEntries[mNextIndex];
|
||||
return (mNextIndex == kNoNextIndex) ? nullptr : &Get<AddressResolver>().GetCacheEntryPool().GetEntryAt(mNextIndex);
|
||||
}
|
||||
|
||||
const AddressResolver::CacheEntry *AddressResolver::CacheEntry::GetNext(void) const
|
||||
{
|
||||
return (mNextIndex == kNoNextIndex) ? nullptr : &Get<AddressResolver>().mCacheEntries[mNextIndex];
|
||||
return (mNextIndex == kNoNextIndex) ? nullptr : &Get<AddressResolver>().GetCacheEntryPool().GetEntryAt(mNextIndex);
|
||||
}
|
||||
|
||||
void AddressResolver::CacheEntry::SetNext(CacheEntry *aEntry)
|
||||
{
|
||||
VerifyOrExit(aEntry != nullptr, mNextIndex = kNoNextIndex);
|
||||
mNextIndex = static_cast<uint16_t>(aEntry - Get<AddressResolver>().mCacheEntries);
|
||||
mNextIndex = Get<AddressResolver>().GetCacheEntryPool().GetIndexOf(*aEntry);
|
||||
|
||||
exit:
|
||||
return;
|
||||
|
||||
@@ -250,7 +250,8 @@ private:
|
||||
} mInfo;
|
||||
};
|
||||
|
||||
typedef LinkedList<CacheEntry> CacheEntryList;
|
||||
typedef Pool<CacheEntry, kCacheEntries> CacheEntryPool;
|
||||
typedef LinkedList<CacheEntry> CacheEntryList;
|
||||
|
||||
enum EntryChange
|
||||
{
|
||||
@@ -271,6 +272,8 @@ private:
|
||||
kReasonRemovingEid,
|
||||
};
|
||||
|
||||
CacheEntryPool &GetCacheEntryPool(void) { return mCacheEntryPool; }
|
||||
|
||||
void Remove(Mac::ShortAddress aRloc16, bool aMatchRouterId);
|
||||
void Remove(const Ip6::Address &aEid, Reason aReason);
|
||||
CacheEntry *FindCacheEntry(const Ip6::Address &aEid, CacheEntryList *&aList, CacheEntry *&aPrevEntry);
|
||||
@@ -317,12 +320,11 @@ private:
|
||||
Coap::Resource mAddressQuery;
|
||||
Coap::Resource mAddressNotification;
|
||||
|
||||
CacheEntry mCacheEntries[kCacheEntries];
|
||||
CacheEntryPool mCacheEntryPool;
|
||||
CacheEntryList mCachedList;
|
||||
CacheEntryList mSnoopedList;
|
||||
CacheEntryList mQueryList;
|
||||
CacheEntryList mQueryRetryList;
|
||||
CacheEntryList mUnusedList;
|
||||
|
||||
Ip6::IcmpHandler mIcmpHandler;
|
||||
TimerMilli mTimer;
|
||||
|
||||
@@ -381,6 +381,28 @@ target_link_libraries(test-network-data
|
||||
|
||||
add_test(NAME test-network-data COMMAND test-network-data)
|
||||
|
||||
add_executable(test-pool
|
||||
${COMMON_SOURCES}
|
||||
test_pool.cpp
|
||||
)
|
||||
|
||||
target_include_directories(test-pool
|
||||
PRIVATE
|
||||
${COMMON_INCLUDES}
|
||||
)
|
||||
|
||||
target_compile_options(test-pool
|
||||
PRIVATE
|
||||
${COMMON_COMPILE_OPTIONS}
|
||||
)
|
||||
|
||||
target_link_libraries(test-pool
|
||||
PRIVATE
|
||||
${COMMON_LIBS}
|
||||
)
|
||||
|
||||
add_test(NAME test-pool COMMAND test-pool)
|
||||
|
||||
add_executable(test-priority-queue
|
||||
${COMMON_SOURCES}
|
||||
test_priority_queue.cpp
|
||||
@@ -492,7 +514,7 @@ target_link_libraries(test-timer
|
||||
add_test(NAME test-timer COMMAND test-timer)
|
||||
|
||||
set_target_properties(
|
||||
test-aes test-child test-child-table test-flash test-heap test-hmac-sha256 test-ip6-address test-link-quality test-linked-list test-lowpan test-mac-frame test-message test-message-queue test-netif test-network-data test-priority-queue test-pskc test-steering-data test-string test-timer
|
||||
test-aes test-child test-child-table test-flash test-heap test-hmac-sha256 test-ip6-address test-link-quality test-linked-list test-lowpan test-mac-frame test-message test-message-queue test-netif test-network-data test-pool test-priority-queue test-pskc test-steering-data test-string test-timer
|
||||
PROPERTIES
|
||||
C_STANDARD 99
|
||||
CXX_STANDARD 11
|
||||
|
||||
@@ -121,6 +121,7 @@ check_PROGRAMS += \
|
||||
test-message-queue \
|
||||
test-netif \
|
||||
test-network-data \
|
||||
test-pool \
|
||||
test-priority-queue \
|
||||
test-pskc \
|
||||
test-steering-data \
|
||||
@@ -217,6 +218,9 @@ test_netif_SOURCES = $(COMMON_SOURCES) test_netif.cpp
|
||||
test_network_data_LDADD = $(COMMON_LDADD)
|
||||
test_network_data_SOURCES = $(COMMON_SOURCES) test_network_data.cpp
|
||||
|
||||
test_pool_LDADD = $(COMMON_LDADD)
|
||||
test_pool_SOURCES = $(COMMON_SOURCES) test_pool.cpp
|
||||
|
||||
test_priority_queue_LDADD = $(COMMON_LDADD)
|
||||
test_priority_queue_SOURCES = $(COMMON_SOURCES) test_priority_queue.cpp
|
||||
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (c) 2020, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "test_platform.h"
|
||||
|
||||
#include <openthread/config.h>
|
||||
|
||||
#include "common/instance.hpp"
|
||||
#include "common/pool.hpp"
|
||||
|
||||
#include "test_util.h"
|
||||
|
||||
struct EntryBase
|
||||
{
|
||||
EntryBase *mNext;
|
||||
};
|
||||
|
||||
struct Entry : public EntryBase, ot::LinkedListEntry<Entry>
|
||||
{
|
||||
public:
|
||||
Entry(void)
|
||||
: mInitWithInstance(false)
|
||||
{
|
||||
}
|
||||
|
||||
void Init(ot::Instance &) { mInitWithInstance = true; }
|
||||
|
||||
bool IsInitializedWithInstance(void) const { return mInitWithInstance; }
|
||||
|
||||
private:
|
||||
bool mInitWithInstance;
|
||||
};
|
||||
|
||||
enum : uint16_t
|
||||
{
|
||||
kPoolSize = 11,
|
||||
};
|
||||
|
||||
typedef ot::Pool<Entry, kPoolSize> EntryPool;
|
||||
|
||||
static Entry sNonPoolEntry;
|
||||
|
||||
void VerifyEntry(EntryPool &aPool, const Entry &aEntry, bool aInitWithInstance)
|
||||
{
|
||||
uint16_t index;
|
||||
const EntryPool &constPool = const_cast<const EntryPool &>(aPool);
|
||||
|
||||
VerifyOrQuit(aPool.IsPoolEntry(aEntry), "Pool::IsPoolEntry() failed");
|
||||
VerifyOrQuit(!aPool.IsPoolEntry(sNonPoolEntry), "Pool::IsPoolEntry() succeeded for non-pool entry");
|
||||
|
||||
index = aPool.GetIndexOf(aEntry);
|
||||
VerifyOrQuit(&aPool.GetEntryAt(index) == &aEntry, "Pool::GetEntryAt() failed");
|
||||
VerifyOrQuit(&constPool.GetEntryAt(index) == &aEntry, "Pool::GetEntryAt() failed");
|
||||
|
||||
VerifyOrQuit(aEntry.IsInitializedWithInstance() == aInitWithInstance, "Pool did not correctly Init() entry");
|
||||
}
|
||||
|
||||
void TestPool(EntryPool &aPool, bool aInitWithInstance)
|
||||
{
|
||||
Entry *entries[kPoolSize];
|
||||
|
||||
VerifyOrQuit(aPool.GetSize() == kPoolSize, "Pool::GetSize() failed");
|
||||
|
||||
for (uint16_t i = 0; i < kPoolSize; i++)
|
||||
{
|
||||
entries[i] = aPool.Allocate();
|
||||
VerifyOrQuit(entries[i] != nullptr, "Pool::Allocate() failed");
|
||||
|
||||
VerifyEntry(aPool, *entries[i], aInitWithInstance);
|
||||
}
|
||||
|
||||
for (uint16_t numEntriesToFree = 1; numEntriesToFree <= kPoolSize; numEntriesToFree++)
|
||||
{
|
||||
VerifyOrQuit(aPool.Allocate() == nullptr, "Pool::Allocate() did not fail when all pool entries were allocated");
|
||||
|
||||
for (uint16_t i = 0; i < numEntriesToFree; i++)
|
||||
{
|
||||
VerifyEntry(aPool, *entries[i], aInitWithInstance);
|
||||
aPool.Free(*entries[i]);
|
||||
}
|
||||
|
||||
for (uint16_t i = 0; i < numEntriesToFree; i++)
|
||||
{
|
||||
entries[i] = aPool.Allocate();
|
||||
VerifyOrQuit(entries[i] != nullptr, "Pool::Allocate() failed");
|
||||
|
||||
VerifyEntry(aPool, *entries[i], aInitWithInstance);
|
||||
}
|
||||
}
|
||||
|
||||
VerifyOrQuit(aPool.Allocate() == nullptr, "Pool::Allocate() did not fail when all pool entries were allocated");
|
||||
}
|
||||
|
||||
void TestPool(void)
|
||||
{
|
||||
ot::Instance *instance = testInitInstance();
|
||||
EntryPool pool1;
|
||||
EntryPool pool2(*instance);
|
||||
|
||||
TestPool(pool1, /* aInitWithInstance */ false);
|
||||
TestPool(pool2, /* aInitWithInstance */ true);
|
||||
|
||||
testFreeInstance(instance);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
TestPool();
|
||||
printf("All tests passed\n");
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user