1 // static pooled class 2 // Copyright (C) 2009 Tim Blechmann 3 // 4 // This program is free software; you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation; either version 2 of the License, or 7 // (at your option) any later version. 8 // 9 // This program is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with this program; see the file COPYING. If not, write to 16 // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 17 // Boston, MA 02111-1307, USA. 18 19 #pragma once 20 21 #include <cstddef> 22 23 #include <boost/mpl/if.hpp> 24 25 #include "freelist.hpp" 26 #include "static_pool.hpp" 27 28 namespace nova { 29 30 /** 31 * base class for a class, which uses a static memory pool for 32 * memory allocation. 33 * 34 * memory is allocated from a static pool and freed to a lock-free 35 * freelist, which is freed during the memory allocation routine. 36 * this way, the derived class can be allocated and freed from 37 * different threads, while all the access to the pool is done from 38 * the allocating thread. 39 * 40 * \tparam pool_locking specifies the locking policy for the object 41 * pool (default: nonblocking) 42 * 43 * \tparam recover_count limits the number of objects to be disposed 44 * from the freelist to avoid (default: dispose all objects 45 * of freelist) 46 * 47 * \todo we could allocate one word more and store the size of the 48 * chunk just before the object. if a disposed object is large 49 * enough for a request, it wouldn't need to be added to the 50 * memory pool. 51 * 52 * */ 53 template <typename tag, std::size_t pool_size, bool pool_locking = false, unsigned int recover_count = 0> 54 class static_pooled_class { 55 protected: 56 static_pooled_class(void) = default; 57 static_pooled_class(static_pooled_class const& rhs) = default; 58 ~static_pooled_class(void) = default; 59 60 private: 61 /** free one object from freelist 62 * 63 * \return true if freelist is empty 64 * 65 * */ free_one_disposed_object(void)66 static inline bool free_one_disposed_object(void) { 67 void* chunk = disposed_objects.pop(); 68 if (chunk == nullptr) 69 return true; 70 object_pool.free(chunk); 71 return false; 72 } 73 74 struct disposing_allocator { allocatenova::static_pooled_class::disposing_allocator75 static void* allocate(std::size_t size) { 76 free_disposed_objects(); 77 return object_pool.malloc(size); 78 } 79 }; 80 81 struct dispose_n_object_allocator { allocatenova::static_pooled_class::dispose_n_object_allocator82 static void* allocate(std::size_t size) { 83 for (unsigned int i = 0; i != recover_count; ++i) { 84 bool freelist_empty = free_one_disposed_object(); 85 if (freelist_empty) 86 break; 87 } 88 89 for (;;) { 90 void* ret = object_pool.malloc(size); 91 92 if (ret) 93 return ret; 94 if (free_one_disposed_object()) 95 return nullptr; /* no object in freelist, we */ 96 } 97 } 98 }; 99 100 typedef 101 typename boost::mpl::if_c<(recover_count > 0), dispose_n_object_allocator, disposing_allocator>::type allocator; 102 103 public: allocate(std::size_t size)104 static inline void* allocate(std::size_t size) { 105 #ifndef NOVA_MEMORY_DEBUGGING 106 size = std::max(2 * sizeof(void*), size); /* size requirement for lockfree freelist */ 107 return allocator::allocate(size); 108 #else 109 return malloc(size); 110 #endif 111 } 112 operator new(std::size_t size)113 inline void* operator new(std::size_t size) { return allocate(size); } 114 free_disposed_objects(void)115 static inline void free_disposed_objects(void) { 116 for (;;) { 117 if (free_one_disposed_object()) 118 return; 119 } 120 } 121 deallocate(void * p)122 static inline void deallocate(void* p) { 123 #ifndef NOVA_MEMORY_DEBUGGING 124 disposed_objects.push(p); 125 #else 126 free(p); 127 #endif 128 } 129 operator delete(void * p)130 inline void operator delete(void* p) { deallocate(p); } 131 132 typedef static_pool<pool_size, pool_locking> object_pool_type; 133 134 static object_pool_type object_pool; 135 static freelist disposed_objects; 136 }; 137 138 template <typename tag, std::size_t pool_size, bool pool_locking, unsigned int recover_count> 139 typename static_pooled_class<tag, pool_size, pool_locking, recover_count>::object_pool_type 140 static_pooled_class<tag, pool_size, pool_locking, recover_count>::object_pool(true); 141 142 template <typename tag, std::size_t pool_size, bool pool_locking, unsigned int recover_count> 143 freelist static_pooled_class<tag, pool_size, pool_locking, recover_count>::disposed_objects; 144 145 146 } /* namespace nova */ 147