pion-net
4.0.9
|
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 00023 #if defined(PION_HAVE_MALLOC_TRIM) 00024 #include <malloc.h> 00025 #endif 00026 00028 #if defined(PION_HAVE_LOCKFREE) 00029 #ifdef _MSC_VER 00030 #pragma warning(push) 00031 #pragma warning(disable: 4800) // forcing value to bool 'true' or 'false' (performance warning) 00032 #endif 00033 #include <boost/lockfree/detail/tagged_ptr.hpp> 00034 #ifdef _MSC_VER 00035 #pragma warning(pop) 00036 #endif 00037 #include <boost/lockfree/atomic_int.hpp> 00038 #endif 00039 00040 00041 namespace pion { // begin namespace pion 00042 00043 00051 template <std::size_t MinSize = 16, std::size_t MaxSize = 256> 00052 class PionPoolAllocator 00053 : private boost::noncopyable 00054 { 00055 public: 00056 00058 virtual ~PionPoolAllocator() 00059 {} 00060 00062 PionPoolAllocator(void) 00063 { 00064 for (std::size_t n = 0; n < NumberOfAllocs; ++n) { 00065 m_pools[n].reset(new FixedSizeAlloc((n+1) * MinSize)); 00066 } 00067 } 00068 00076 inline void *malloc(std::size_t n) 00077 { 00078 // check for size greater than MaxSize 00079 if (n > MaxSize) 00080 return ::malloc(n); 00081 FixedSizeAlloc *pool_ptr = getPool(n); 00082 00083 #if defined(PION_HAVE_LOCKFREE) 00084 while (true) { 00085 // get copy of free list pointer 00086 FreeListPtr old_free_ptr(pool_ptr->m_free_ptr); 00087 if (! old_free_ptr) 00088 break; // use pool alloc if free list is empty 00089 00090 // use CAS operation to swap the free list pointer 00091 if (pool_ptr->m_free_ptr.cas(old_free_ptr, old_free_ptr->next.get_ptr())) 00092 return reinterpret_cast<void*>(old_free_ptr.get_ptr()); 00093 } 00094 #endif 00095 00096 boost::unique_lock<boost::mutex> pool_lock(pool_ptr->m_mutex); 00097 return pool_ptr->m_pool.malloc(); 00098 } 00099 00106 inline void free(void *ptr, std::size_t n) 00107 { 00108 // check for size greater than MaxSize 00109 if (n > MaxSize) { 00110 ::free(ptr); 00111 return; 00112 } 00113 FixedSizeAlloc *pool_ptr = getPool(n); 00114 #if defined(PION_HAVE_LOCKFREE) 00115 while (true) { 00116 // get copy of free list pointer 00117 FreeListPtr old_free_ptr(pool_ptr->m_free_ptr); 00118 00119 // cast memory being released to a free list node 00120 // and point its next pointer to the current free list 00121 FreeListNode *node_ptr = reinterpret_cast<FreeListNode*>(ptr); 00122 node_ptr->next.set_ptr(old_free_ptr.get_ptr()); 00123 00124 // use CAS operation to swap the free list pointer 00125 if (pool_ptr->m_free_ptr.cas(old_free_ptr, node_ptr)) 00126 break; 00127 } 00128 #else 00129 boost::unique_lock<boost::mutex> pool_lock(pool_ptr->m_mutex); 00130 return pool_ptr->m_pool.free(ptr); 00131 #endif 00132 } 00133 00141 inline bool release_memory(size_t pad = 10240000UL) 00142 { 00143 bool result = false; 00144 /* 00145 for (std::size_t n = 0; n < NumberOfAllocs; ++n) { 00146 FixedSizeAlloc *pool_ptr = m_pools[n].get(); 00147 // need to lock before releasing free list because of calls 00148 // to pool::free() 00149 boost::unique_lock<boost::mutex> pool_lock(pool_ptr->m_mutex); 00150 #if defined(PION_HAVE_LOCKFREE) 00151 while (true) { 00152 // get copy of free list pointer 00153 FreeListPtr old_free_ptr(pool_ptr->m_free_ptr); 00154 if (! old_free_ptr) 00155 break; // all done: free list is empty 00156 00157 // use CAS operation to swap the free list pointer 00158 if (pool_ptr->m_free_ptr.cas(old_free_ptr, old_free_ptr->next.get_ptr())) 00159 pool_ptr->m_pool.free(old_free_ptr.get_ptr()); // release memory from pool 00160 } 00161 #endif 00162 if (pool_ptr->m_pool.release_memory()) 00163 result = true; 00164 } 00165 #if defined(PION_HAVE_MALLOC_TRIM) 00166 ::malloc_trim(pad); 00167 #endif 00168 */ 00169 return result; 00170 } 00171 00172 00173 protected: 00174 00175 #if defined(PION_HAVE_LOCKFREE) 00176 00177 struct FreeListNode { 00178 boost::lockfree::tagged_ptr<struct FreeListNode> next; 00179 }; 00180 00182 typedef boost::lockfree::tagged_ptr<struct FreeListNode> FreeListPtr; 00183 #else 00184 typedef void * FreeListPtr; 00185 #endif 00186 00191 BOOST_STATIC_ASSERT(MaxSize >= MinSize); 00192 BOOST_STATIC_ASSERT(MaxSize % MinSize == 0); 00193 #if defined(PION_HAVE_LOCKFREE) 00194 BOOST_STATIC_ASSERT(MinSize >= sizeof(FreeListNode)); 00195 #endif 00196 00198 enum { NumberOfAllocs = ((MaxSize-1) / MinSize) + 1 }; 00199 00204 struct FixedSizeAlloc 00205 { 00211 FixedSizeAlloc(std::size_t size) 00212 : m_size(size), m_pool(size), m_free_ptr(NULL) 00213 {} 00214 00216 boost::mutex m_mutex; 00217 00219 std::size_t m_size; 00220 00222 boost::pool<> m_pool; 00223 00225 FreeListPtr m_free_ptr; 00226 }; 00227 00228 00236 inline FixedSizeAlloc* getPool(const std::size_t n) 00237 { 00238 PION_ASSERT(n > 0); 00239 PION_ASSERT(n <= MaxSize); 00240 return m_pools[ (n-1) / MinSize ].get(); 00241 } 00242 00243 00244 private: 00245 00247 boost::array<boost::scoped_ptr<FixedSizeAlloc>, NumberOfAllocs> m_pools; 00248 }; 00249 00250 00251 } // end namespace pion 00252 00253 #endif