common/include/pion/PionPoolAllocator.hpp

00001 // -----------------------------------------------------------------------
00002 // pion-common: a collection of common libraries used by the Pion Platform
00003 // -----------------------------------------------------------------------
00004 // Copyright (C) 2007-2008 Atomic Labs, Inc.  (http://www.atomiclabs.com)
00005 //
00006 // Distributed under the Boost Software License, Version 1.0.
00007 // See http://www.boost.org/LICENSE_1_0.txt
00008 //
00009 
00010 #ifndef __PION_PIONPOOLALLOCATOR_HEADER__
00011 #define __PION_PIONPOOLALLOCATOR_HEADER__
00012 
00013 #include <cstdlib>
00014 #include <boost/array.hpp>
00015 #include <boost/scoped_ptr.hpp>
00016 #include <boost/static_assert.hpp>
00017 #include <boost/noncopyable.hpp>
00018 #include <boost/thread/mutex.hpp>
00019 #include <boost/pool/pool.hpp>
00020 #include <pion/PionConfig.hpp>
00021 #include <pion/PionException.hpp>
00022 
00024 #if defined(PION_HAVE_LOCKFREE)
00025 #ifdef _MSC_VER
00026     #pragma warning(push)
00027     #pragma warning(disable: 4800) // forcing value to bool 'true' or 'false' (performance warning)
00028 #endif
00029     #include <boost/lockfree/detail/tagged_ptr.hpp>
00030 #ifdef _MSC_VER
00031     #pragma warning(pop)
00032 #endif
00033     #include <boost/lockfree/atomic_int.hpp>
00034 #endif
00035 
00036 
00037 namespace pion {    // begin namespace pion
00038 
00039 
00047 template <std::size_t MinSize = 16, std::size_t MaxSize = 256>
00048 class PionPoolAllocator
00049     : private boost::noncopyable
00050 {
00051 public:
00052 
00054     virtual ~PionPoolAllocator()
00055     {}
00056     
00058     PionPoolAllocator(void)
00059     {
00060         for (std::size_t n = 0; n < NumberOfAllocs; ++n) {
00061             m_pools[n].reset(new FixedSizeAlloc((n+1) * MinSize));
00062         }
00063     }
00064 
00072     inline void *malloc(std::size_t n)
00073     {
00074         // check for size greater than MaxSize
00075         if (n > MaxSize)
00076             return ::malloc(n);
00077         FixedSizeAlloc *pool_ptr = getPool(n);
00078 
00079 #if defined(PION_HAVE_LOCKFREE)
00080         while (true) {
00081             // get copy of free list pointer
00082             FreeListPtr old_free_ptr(pool_ptr->m_free_ptr);
00083             if (! old_free_ptr)
00084                 break;  // use pool alloc if free list is empty
00085 
00086             // use CAS operation to swap the free list pointer
00087             if (pool_ptr->m_free_ptr.cas(old_free_ptr, old_free_ptr->next.get_ptr()))
00088                 return reinterpret_cast<void*>(old_free_ptr.get_ptr());
00089         }
00090 #endif
00091 
00092         boost::unique_lock<boost::mutex> pool_lock(pool_ptr->m_mutex);
00093         return pool_ptr->m_pool.malloc();
00094     }
00095 
00102     inline void free(void *ptr, std::size_t n)
00103     {
00104         // check for size greater than MaxSize
00105         if (n > MaxSize) {
00106 			::free(ptr);
00107             return;
00108         }
00109         FixedSizeAlloc *pool_ptr = getPool(n);
00110 #if defined(PION_HAVE_LOCKFREE)
00111         while (true) {
00112             // get copy of free list pointer
00113             FreeListPtr old_free_ptr(pool_ptr->m_free_ptr);
00114             
00115             // cast memory being released to a free list node
00116             // and point its next pointer to the current free list
00117             FreeListNode *node_ptr = reinterpret_cast<FreeListNode*>(ptr);
00118             node_ptr->next.set_ptr(old_free_ptr.get_ptr());
00119             
00120             // use CAS operation to swap the free list pointer
00121             if (pool_ptr->m_free_ptr.cas(old_free_ptr, node_ptr))
00122                 break;
00123         }
00124 #else
00125         boost::unique_lock<boost::mutex> pool_lock(pool_ptr->m_mutex);
00126         return pool_ptr->m_pool.free(ptr);
00127 #endif
00128     }
00129     
00135     inline bool release_memory(void)
00136     {
00137         bool result = false;
00138         for (std::size_t n = 0; n < NumberOfAllocs; ++n) {
00139             boost::unique_lock<boost::mutex> pool_lock(m_pools[n]->m_mutex);
00140             if (m_pools[n]->m_pool.release_memory())
00141                 result = true;
00142         }
00143         return result;
00144     }
00145     
00146 
00147 protected:
00148 
00149 #if defined(PION_HAVE_LOCKFREE)
00151     struct FreeListNode {
00152         boost::lockfree::tagged_ptr<struct FreeListNode>    next;
00153     };
00154     
00156     typedef boost::lockfree::tagged_ptr<struct FreeListNode>    FreeListPtr;
00157 #else
00158     typedef void *  FreeListPtr;
00159 #endif
00160     
00165     BOOST_STATIC_ASSERT(MaxSize >= MinSize);
00166     BOOST_STATIC_ASSERT(MaxSize % MinSize == 0);
00167 #if defined(PION_HAVE_LOCKFREE)
00168     BOOST_STATIC_ASSERT(MinSize >= sizeof(FreeListNode));
00169 #endif
00170     
00172     enum { NumberOfAllocs = ((MaxSize-1) / MinSize) + 1 };
00173 
00178     struct FixedSizeAlloc
00179     {
00185         FixedSizeAlloc(std::size_t size)
00186             : m_size(size), m_pool(size), m_free_ptr(NULL)
00187         {}
00188         
00190         boost::mutex        m_mutex;
00191 
00193         std::size_t         m_size;
00194         
00196         boost::pool<>       m_pool;
00197 
00199         FreeListPtr         m_free_ptr;     
00200     };
00201     
00202 
00210     inline FixedSizeAlloc* getPool(const std::size_t n)
00211     {
00212         PION_ASSERT(n > 0);
00213         PION_ASSERT(n <= MaxSize);
00214         return m_pools[ (n-1) / MinSize ].get();
00215     }
00216 
00217 
00218 private:
00219 
00221     boost::array<boost::scoped_ptr<FixedSizeAlloc>, NumberOfAllocs> m_pools;
00222 };
00223 
00224     
00225 }   // end namespace pion
00226 
00227 #endif

Generated on Fri Apr 30 14:48:53 2010 for pion-net by  doxygen 1.4.7