/* * Copyright (c) 2014, Siemens AG. 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. * * 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. */ #ifndef EMBB_CONTAINERS_LOCK_FREE_STACK_H_ #define EMBB_CONTAINERS_LOCK_FREE_STACK_H_ #include #include #include #include #include /** * \defgroup CPP_CONCEPTS_STACK Stack Concept * Concept for thread-safe stacks * * \ingroup CPP_CONCEPT * \{ * \par Description * A stack is an abstract data type holding a collection of elements of some * predetermined type. A stack provides two operations: \c TryPush and * \c TryPop. \c TryPush tries to add an element to the collection, and * \c TryPop tries to remove an element from the collection. A stack has LIFO * (Last-In, First-out) semantics, i.e., the last element added to the * collection (\c TryPush) is removed first (\c TryPop). The capacity \c cap of * a stack defines the number of elements it can store (depending on the * implementation, a stack might store more than \c cap elements, since for * thread-safe memory management, more memory than necessary for holding \c cap * elements has to be provided). * * \par Requirements * - Let \c Stack be the stack class * - Let \c Type be the element type of the stack * - Let \c capacity be a value of type \c size_t * - Let \c element be a reference to an element of type \c Type * * \par Valid Expressions * * * * * * * * * * * * * * * * * * * * * *
ExpressionReturn typeDescription
\code{.cpp} Stack(capacity) \endcodeNothing * Constructs a stack with capacity \c capacity that holds elements of * type \c Type. *
\code{.cpp} TryPush(element) \endcode\code{.cpp} bool \endcode * Tries to push \c element onto the stack. Returns \c false if the stack * is full, otherwise \c true. *
\code{.cpp} TryPop(element) \endcode\code{.cpp} bool \endcode * Tries to pop an element from the stack. Returns \c false if the stack is * empty, otherwise \c true. In the latter case, the popped element is * stored in \c element which must be passed by reference. *
* * \} */ /** * \defgroup CPP_CONTAINERS_STACKS Stacks * Concurrent stacks * * \ingroup CPP_CONTAINERS * * \see CPP_CONCEPTS_STACK */ namespace embb { namespace containers { namespace internal { /** * Stack node * * Single linked list, contains the element (\c element) and a pointer to the * next node (\c next). * * \tparam T Element type */ template< typename T > class LockFreeStackNode { private: /** * Pointer to the next node */ LockFreeStackNode< T >* next; /** * The stored element */ T element; public: /** * Creates a stack node */ LockFreeStackNode( T const& element /**< [IN] The element of this stack node */ ); /** * Sets the next node */ void SetNext( LockFreeStackNode< T >* next /**< [IN] Pointer to the next node */ ); /** * Returns the next pointer * * \return The next pointer */ LockFreeStackNode< T >* GetNext(); /** * Returns the element held by this node */ T GetElement(); }; } // namespace internal /** * Lock-free stack * * \concept{CPP_CONCEPTS_STACK} * * \ingroup CPP_CONTAINERS_STACKS * * \tparam Type Type of the stack elements * \tparam ValuePool Type of the value pool used as basis for the ObjectPool * which stores the elements. */ template< typename Type, typename ValuePool = embb::containers::LockFreeTreeValuePool < bool, false > > class LockFreeStack { private: /** * The capacity of the stack. It is guaranteed that the stack can hold at * least as many elements, maybe more. */ size_t capacity; /** * Callback to the method that is called by hazard pointers if a pointer is * not hazardous anymore, i.e., can safely be reused. */ embb::base::Function*> delete_pointer_callback; /** * The hazard pointer object, used for memory management. */ internal::HazardPointer*> hazardPointer; /** * The callback function, used to cleanup non-hazardous pointers. * \see delete_pointer_callback */ void DeletePointerCallback(internal::LockFreeStackNode* to_delete); /** * The object pool, used for lock-free memory allocation. */ ObjectPool< internal::LockFreeStackNode, ValuePool > objectPool; /** * Atomic pointer to the top node of the stack (element that is popped next) */ embb::base::Atomic*> top; public: /** * Creates a stack with the specified capacity. * * \memory * Let \c t be the maximum number of threads and \c x be 1.25*t+1. * Then, x*(3*t+1) elements of size sizeof(void*), \c x * elements of size sizeof(Type), and \c capacity elements of size * sizeof(Type) are allocated. * * \notthreadsafe * * \see CPP_CONCEPTS_STACK */ LockFreeStack( size_t capacity /**< [IN] Capacity of the stack */ ); /** * Returns the capacity of the stack. * * \return Number of elements the stack can hold. * * \waitfree */ size_t GetCapacity(); /** * Destroys the stack. * * \notthreadsafe */ ~LockFreeStack(); /** * Tries to push an element onto the stack. * * \return \c true if the element could be pushed, \c false if the stack is * full. * * \lockfree * * \note It might be possible to push more elements onto the stack than its * capacity permits. * * \see CPP_CONCEPTS_STACK */ bool TryPush( Type const& element /**< [IN] Const reference to the element that shall be pushed */ ); /** * Tries to pop an element from the stack. * * \return \c true if an element could be popped, \c false if the stack is * empty. * * \lockfree * * \see CPP_CONCEPTS_STACK */ bool TryPop( Type & element /**< [IN,OUT] Reference to the popped element. Unchanged, if the operation was not successful. */ ); }; } // namespace containers } // namespace embb #include #endif // EMBB_CONTAINERS_LOCK_FREE_STACK_H_