| /* |
| * |
| * Copyright (c) 2016-2017 Nest Labs, Inc. |
| * All rights reserved. |
| * |
| * 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 nl::Weave::System::Object |
| * - template<typename ALIGN, size_t SIZE> union nl::Weave::System::ObjectArena |
| * - template<class T, unsigned int N> class nl::Weave::System::ObjectPool |
| */ |
| |
| #ifndef SYSTEMOBJECT_H |
| #define SYSTEMOBJECT_H |
| |
| // Include configuration headers |
| #include <SystemLayer/SystemConfig.h> |
| |
| // Include dependent headers |
| #include <stddef.h> |
| #include <stdint.h> |
| |
| #include <Weave/Support/NLDLLUtil.h> |
| |
| #include <SystemLayer/SystemError.h> |
| #include <SystemLayer/SystemStats.h> |
| |
| namespace nl { |
| namespace Weave { |
| 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, in conformance with Nest C++ style, it should be regarded as abstract. |
| */ |
| class NL_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 WEAVE_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 // WEAVE_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 Weave 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 Weave 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(nl::Weave::System::Stats::count_t& aNumInUse); |
| |
| private: |
| ObjectArena<void*, N * sizeof(T)> mArena; |
| }; |
| |
| /** |
| * @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; |
| |
| for (unsigned int lIndex = 0; lIndex < N; ++lIndex) |
| { |
| T& lObject = reinterpret_cast<T*>(mArena.uMemory)[lIndex]; |
| |
| if (lObject.TryCreate(aLayer, sizeof(T))) |
| { |
| lReturn = &lObject; |
| break; |
| } |
| } |
| |
| return lReturn; |
| } |
| |
| template<class T, unsigned int N> |
| inline void ObjectPool<T, N>::GetStatistics(nl::Weave::System::Stats::count_t& aNumInUse) |
| { |
| aNumInUse = 0; |
| |
| for (size_t lIndex = 0; lIndex < N; ++lIndex) |
| { |
| T& lObject = reinterpret_cast<T*>(mArena.uMemory)[lIndex]; |
| |
| if (lObject.mSystemLayer != NULL) |
| aNumInUse++; |
| } |
| } |
| |
| } // namespace System |
| } // namespace Weave |
| } // namespace nl |
| |
| #endif // defined(SYSTEMOBJECT_H) |