| /* |
| * |
| * Copyright (c) 2020 Project CHIP Authors |
| * Copyright (c) 2016-2017 Nest Labs, Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /** |
| * @file |
| * This file contains declarations of the following classes and |
| * templates: |
| * |
| * - class chip::System::Object |
| * - template<typename ALIGN, size_t SIZE> union chip::System::ObjectArena |
| * - template<class T, unsigned int N> class chip::System::ObjectPool |
| */ |
| |
| #ifndef SYSTEMOBJECT_H |
| #define SYSTEMOBJECT_H |
| |
| // Include configuration headers |
| #include <system/SystemConfig.h> |
| |
| // Include dependent headers |
| #include <stddef.h> |
| #include <stdint.h> |
| #include <unistd.h> |
| |
| #include <support/DLLUtil.h> |
| |
| #include <system/SystemError.h> |
| #include <system/SystemStats.h> |
| |
| #ifndef SYSTEM_OBJECT_HWM_TEST_HOOK |
| #define SYSTEM_OBJECT_HWM_TEST_HOOK() |
| #endif |
| |
| namespace chip { |
| namespace System { |
| |
| // Forward class and class template declarations |
| class Layer; |
| template <class T, unsigned int N> |
| class ObjectPool; |
| |
| /** |
| * @class Object |
| * |
| * @brief |
| * This represents a reference-counted object allocated from space contained in an ObjectPool<T, N> object. |
| * |
| * @note |
| * Instance of this class may only be constructed using the related ObjectPool class template. The copy constructor and the |
| * assignment operator are deleted. A reference counting system is used to track retentions of instances of this class. |
| * When an object is initially retained, its reference count is one. Additional retentions may increment the reference count. |
| * When the object is released, the reference count is decremented. When the reference count is zero, the object is recycled |
| * back to the pool for reallocation. There is no destructor available. Subclasses must be designed to ensure that all |
| * encapsulated resources are released when the final retention is released and the object is recycled. |
| * |
| * While this class is defined as concrete, it should be regarded as abstract. |
| */ |
| class DLL_EXPORT Object |
| { |
| template <class T, unsigned int N> |
| friend class ObjectPool; |
| |
| public: |
| /** Test whether this object is retained by \c aLayer. Concurrency safe. */ |
| bool IsRetained(const Layer & aLayer) const; |
| |
| void Retain(void); |
| void Release(void); |
| Layer & SystemLayer(void) const; |
| |
| protected: |
| #if CHIP_SYSTEM_CONFIG_USE_LWIP |
| /**< What to do when DeferredRelease fails to post a kEvent_ReleaseObj. */ |
| enum ReleaseDeferralErrorTactic |
| { |
| kReleaseDeferralErrorTactic_Ignore, /**< No action. */ |
| kReleaseDeferralErrorTactic_Release, /**< Release immediately. */ |
| kReleaseDeferralErrorTactic_Die, /**< Die with message. */ |
| }; |
| |
| void DeferredRelease(ReleaseDeferralErrorTactic aTactic); |
| #endif // CHIP_SYSTEM_CONFIG_USE_LWIP |
| |
| private: |
| Object(void); |
| ~Object(void); |
| Object(const Object &) /* = delete */; |
| Object & operator=(const Object &) /* = delete */; |
| |
| Layer * volatile mSystemLayer; /**< Pointer to the layer object that owns this object. */ |
| unsigned int mRefCount; /**< Count of remaining calls to Release before object is dead. */ |
| |
| /** If not already retained, attempt initial retention of this object for \c aLayer and zero up to \c aOctets. */ |
| bool TryCreate(Layer & aLayer, size_t aOctets); |
| |
| public: |
| void * AppState; /**< Generic pointer to app-specific data associated with the object. */ |
| }; |
| |
| /** |
| * @brief |
| * Tests whether this object is retained by \c aLayer. |
| * |
| * @note |
| * No memory barrier is applied. If this returns \c false in one thread context, then it does not imply that another thread |
| * cannot have previously retained the object for \c aLayer. If it returns \c true, then the logic using \c aLayer is |
| * responsible for ensuring concurrency safety for this object. |
| */ |
| inline bool Object::IsRetained(const Layer & aLayer) const |
| { |
| return this->mSystemLayer == &aLayer; |
| } |
| |
| /** |
| * @brief |
| * Increments the reference count for the CHIP System Layer object. The object is assumed to be live. |
| */ |
| inline void Object::Retain(void) |
| { |
| __sync_fetch_and_add(&this->mRefCount, 1); |
| } |
| |
| /** |
| * @brief |
| * Returns a reference to the CHIP System Layer object provided when the object was initially retained from its corresponding |
| * object pool instance. The object is assumed to be live. |
| */ |
| inline Layer & Object::SystemLayer(void) const |
| { |
| return *this->mSystemLayer; |
| } |
| |
| /** Deleted. */ |
| inline Object::Object(void) {} |
| |
| /** Deleted. */ |
| inline Object::~Object(void) {} |
| |
| /** |
| * @brief |
| * A union template used for representing a well-aligned block of memory. |
| * |
| * @tparam ALIGN a typename with the alignment properties for the block. |
| * @tparam SIZE a constant size of the block in bytes. |
| */ |
| template <typename ALIGN, size_t SIZE> |
| union ObjectArena |
| { |
| uint8_t uMemory[SIZE]; |
| ALIGN uAlign; |
| }; |
| |
| /** |
| * @brief |
| * A class template used for allocating Object subclass objects from an ObjectArena<> template union. |
| * |
| * @tparam T a subclass of Object to be allocated from the arena. |
| * @tparam N a positive integer number of objects of class T to allocate from the arena. |
| */ |
| template <class T, unsigned int N> |
| class ObjectPool |
| { |
| public: |
| static size_t Size(void); |
| |
| T * Get(const Layer & aLayer, size_t aIndex); |
| T * TryCreate(Layer & aLayer); |
| void GetStatistics(chip::System::Stats::count_t & aNumInUse, chip::System::Stats::count_t & aHighWatermark); |
| |
| private: |
| friend class TestObject; |
| |
| ObjectArena<void *, N * sizeof(T)> mArena; |
| |
| #if CHIP_SYSTEM_CONFIG_PROVIDE_STATISTICS |
| void GetNumObjectsInUse(unsigned int aStartIndex, unsigned int & aNumInUse); |
| void UpdateHighWatermark(const unsigned int & aCandidate); |
| volatile unsigned int mHighWatermark; |
| #endif |
| }; |
| |
| /** |
| * @brief |
| * Returns the number of objects that can be simultaneously retained from a pool. |
| */ |
| template <class T, unsigned int N> |
| inline size_t ObjectPool<T, N>::Size(void) |
| { |
| return N; |
| } |
| |
| /** |
| * @brief |
| * Returns a pointer the object at \c aIndex or \c NULL if the object is not retained by \c aLayer. |
| */ |
| template <class T, unsigned int N> |
| inline T * ObjectPool<T, N>::Get(const Layer & aLayer, size_t aIndex) |
| { |
| T * lReturn = NULL; |
| |
| if (aIndex < N) |
| lReturn = &reinterpret_cast<T *>(mArena.uMemory)[aIndex]; |
| |
| (void) static_cast<Object *>(lReturn); /* In C++-11, this would be a static_assert that T inherits Object. */ |
| |
| return (lReturn != NULL) && lReturn->IsRetained(aLayer) ? lReturn : NULL; |
| } |
| |
| /** |
| * @brief |
| * Tries to initially retain the first object in the pool that is not retained by any layer. |
| */ |
| template <class T, unsigned int N> |
| inline T * ObjectPool<T, N>::TryCreate(Layer & aLayer) |
| { |
| T * lReturn = NULL; |
| unsigned int lIndex; |
| #if CHIP_SYSTEM_CONFIG_PROVIDE_STATISTICS |
| unsigned int lNumInUse = 0; |
| #endif |
| |
| for (lIndex = 0; lIndex < N; ++lIndex) |
| { |
| T & lObject = reinterpret_cast<T *>(mArena.uMemory)[lIndex]; |
| |
| if (lObject.TryCreate(aLayer, sizeof(T))) |
| { |
| lReturn = &lObject; |
| break; |
| } |
| } |
| |
| #if CHIP_SYSTEM_CONFIG_PROVIDE_STATISTICS |
| if (lReturn != NULL) |
| { |
| lIndex++; |
| lNumInUse = lIndex; |
| GetNumObjectsInUse(lIndex, lNumInUse); |
| } |
| else |
| { |
| lNumInUse = N; |
| } |
| |
| UpdateHighWatermark(lNumInUse); |
| #endif |
| |
| return lReturn; |
| } |
| |
| #if CHIP_SYSTEM_CONFIG_PROVIDE_STATISTICS |
| template <class T, unsigned int N> |
| inline void ObjectPool<T, N>::UpdateHighWatermark(const unsigned int & aCandidate) |
| { |
| unsigned int lTmp; |
| |
| while (aCandidate > (lTmp = mHighWatermark)) |
| { |
| SYSTEM_OBJECT_HWM_TEST_HOOK(); |
| (void) __sync_bool_compare_and_swap(&mHighWatermark, lTmp, aCandidate); |
| } |
| } |
| |
| /** |
| * Return the number of objects in use starting at a given index |
| * |
| * @param[in] aStartIndex The index to start counting from; pass 0 to count over |
| * the whole pool. |
| * @param[in/out] aNumInUse The number of objects in use. If aStartIndex is not 0, |
| * the function adds to the counter without resetting it first. |
| */ |
| template <class T, unsigned int N> |
| inline void ObjectPool<T, N>::GetNumObjectsInUse(unsigned int aStartIndex, unsigned int & aNumInUse) |
| { |
| unsigned int count = 0; |
| |
| for (unsigned int lIndex = aStartIndex; lIndex < N; ++lIndex) |
| { |
| T & lObject = reinterpret_cast<T *>(mArena.uMemory)[lIndex]; |
| |
| if (lObject.mSystemLayer != NULL) |
| { |
| count++; |
| } |
| } |
| |
| if (aStartIndex == 0) |
| { |
| aNumInUse = 0; |
| } |
| |
| aNumInUse += count; |
| } |
| #endif // CHIP_SYSTEM_CONFIG_PROVIDE_STATISTICS |
| |
| template <class T, unsigned int N> |
| inline void ObjectPool<T, N>::GetStatistics(chip::System::Stats::count_t & aNumInUse, chip::System::Stats::count_t & aHighWatermark) |
| { |
| #if CHIP_SYSTEM_CONFIG_PROVIDE_STATISTICS |
| unsigned int lNumInUse; |
| unsigned int lHighWatermark; |
| |
| GetNumObjectsInUse(0, lNumInUse); |
| lHighWatermark = mHighWatermark; |
| |
| if (lNumInUse > CHIP_SYS_STATS_COUNT_MAX) |
| { |
| lNumInUse = CHIP_SYS_STATS_COUNT_MAX; |
| } |
| if (lHighWatermark > CHIP_SYS_STATS_COUNT_MAX) |
| { |
| lHighWatermark = CHIP_SYS_STATS_COUNT_MAX; |
| } |
| aNumInUse = static_cast<chip::System::Stats::count_t>(lNumInUse); |
| aHighWatermark = static_cast<chip::System::Stats::count_t>(lHighWatermark); |
| #endif |
| } |
| |
| } // namespace System |
| } // namespace chip |
| |
| #endif // defined(SYSTEMOBJECT_H) |