00001
00002
00003
00004
00005
00006
00007
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 {
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
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
00082 FreeListPtr old_free_ptr(pool_ptr->m_free_ptr);
00083 if (! old_free_ptr)
00084 break;
00085
00086
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
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
00113 FreeListPtr old_free_ptr(pool_ptr->m_free_ptr);
00114
00115
00116
00117 FreeListNode *node_ptr = reinterpret_cast<FreeListNode*>(ptr);
00118 node_ptr->next.set_ptr(old_free_ptr.get_ptr());
00119
00120
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 }
00226
00227 #endif