1 // Copyright (C) 2000, 2001 Stephen Cleary 2 // 3 // Distributed under the Boost Software License, Version 1.0. (See 4 // accompanying file LICENSE_1_0.txt or copy at 5 // http://www.boost.org/LICENSE_1_0.txt) 6 // 7 // See http://www.boost.org for updates, documentation, and revision history. 8 9 #ifndef BOOST_SINGLETON_POOL_HPP 10 #define BOOST_SINGLETON_POOL_HPP 11 12 /*! 13 \file 14 \brief The <tt>singleton_pool</tt> class allows other pool interfaces 15 for types of the same size to share the same underlying pool. 16 17 \details Header singleton_pool.hpp provides a template class <tt>singleton_pool</tt>, 18 which provides access to a pool as a singleton object. 19 20 */ 21 22 #include <boost/pool/poolfwd.hpp> 23 24 // boost::pool 25 #include <boost/pool/pool.hpp> 26 // boost::details::pool::guard 27 #include <boost/pool/detail/guard.hpp> 28 29 #include <boost/type_traits/aligned_storage.hpp> 30 31 namespace boost { 32 33 /*! 34 The singleton_pool class allows other pool interfaces 35 for types of the same size to share the same pool. Template 36 parameters are as follows: 37 38 <b>Tag</b> User-specified type to uniquely identify this pool: allows different unbounded sets of singleton pools to exist. 39 40 <b>RequestedSize</b> The size of each chunk returned by member function <tt>malloc()</tt>. 41 42 <B>UserAllocator</b> User allocator, default = default_user_allocator_new_delete. 43 44 <b>Mutex</B> This class is the type of mutex to use to protect simultaneous access to the underlying Pool. 45 Can be any Boost.Thread Mutex type or <tt>boost::details::pool::null_mutex</tt>. 46 It is exposed so that users may declare some singleton pools normally (i.e., with synchronization), but 47 some singleton pools without synchronization (by specifying <tt>boost::details::pool::null_mutex</tt>) for efficiency reasons. 48 The member typedef <tt>mutex</tt> exposes the value of this template parameter. The default for this 49 parameter is boost::details::pool::default_mutex which is a synonym for either <tt>boost::details::pool::null_mutex</tt> 50 (when threading support is turned off in the compiler (so BOOST_HAS_THREADS is not set), or threading support 51 has ben explicitly disabled with BOOST_DISABLE_THREADS (Boost-wide disabling of threads) or BOOST_POOL_NO_MT (this library only)) 52 or for <tt>boost::mutex</tt> (when threading support is enabled in the compiler). 53 54 <B>NextSize</b> The value of this parameter is passed to the underlying Pool when it is created and 55 specifies the number of chunks to allocate in the first allocation request (defaults to 32). 56 The member typedef <tt>static const value next_size</tt> exposes the value of this template parameter. 57 58 <b>MaxSize</B>The value of this parameter is passed to the underlying Pool when it is created and 59 specifies the maximum number of chunks to allocate in any single allocation request (defaults to 0). 60 61 <b>Notes:</b> 62 63 The underlying pool <i>p</i> referenced by the static functions 64 in singleton_pool is actually declared in a way that is: 65 66 1 Thread-safe if there is only one thread running before main() begins and after main() ends 67 -- all of the static functions of singleton_pool synchronize their access to p. 68 69 2 Guaranteed to be constructed before it is used -- 70 thus, the simple static object in the synopsis above would actually be an incorrect implementation. 71 The actual implementation to guarantee this is considerably more complicated. 72 73 3 Note too that a different underlying pool p exists 74 for each different set of template parameters, 75 including implementation-specific ones. 76 77 4 The underlying pool is constructed "as if" by: 78 79 pool<UserAllocator> p(RequestedSize, NextSize, MaxSize); 80 81 \attention 82 The underlying pool constructed by the singleton 83 <b>is never freed</b>. This means that memory allocated 84 by a singleton_pool can be still used after main() has 85 completed, but may mean that some memory checking programs 86 will complain about leaks from singleton_pool. 87 88 */ 89 90 template <typename Tag, 91 unsigned RequestedSize, 92 typename UserAllocator, 93 typename Mutex, 94 unsigned NextSize, 95 unsigned MaxSize > 96 class singleton_pool 97 { 98 public: 99 typedef Tag tag; /*!< The Tag template parameter uniquely 100 identifies this pool and allows 101 different unbounded sets of singleton pools to exist. 102 For example, the pool allocators use two tag classes to ensure that the 103 two different allocator types never share the same underlying singleton pool. 104 Tag is never actually used by singleton_pool. 105 */ 106 typedef Mutex mutex; //!< The type of mutex used to synchonise access to this pool (default <tt>details::pool::default_mutex</tt>). 107 typedef UserAllocator user_allocator; //!< The user-allocator used by this pool, default = <tt>default_user_allocator_new_delete</tt>. 108 typedef typename pool<UserAllocator>::size_type size_type; //!< size_type of user allocator. 109 typedef typename pool<UserAllocator>::difference_type difference_type; //!< difference_type of user allocator. 110 111 BOOST_STATIC_CONSTANT(unsigned, requested_size = RequestedSize); //!< The size of each chunk allocated by this pool. 112 BOOST_STATIC_CONSTANT(unsigned, next_size = NextSize); //!< The number of chunks to allocate on the first allocation. 113 114 private: 115 singleton_pool(); 116 117 #ifndef BOOST_DOXYGEN 118 struct pool_type: public Mutex, public pool<UserAllocator> 119 { pool_typeboost::singleton_pool::pool_type120 pool_type() : pool<UserAllocator>(RequestedSize, NextSize, MaxSize) {} 121 }; // struct pool_type: Mutex 122 123 #else 124 // 125 // This is invoked when we build with Doxygen only: 126 // 127 public: 128 static pool<UserAllocator> p; //!< For exposition only! 129 #endif 130 131 132 public: BOOST_PREVENT_MACRO_SUBSTITUTION()133 static void * malloc BOOST_PREVENT_MACRO_SUBSTITUTION() 134 { //! Equivalent to SingletonPool::p.malloc(); synchronized. 135 pool_type & p = get_pool(); 136 details::pool::guard<Mutex> g(p); 137 return (p.malloc)(); 138 } ordered_malloc()139 static void * ordered_malloc() 140 { //! Equivalent to SingletonPool::p.ordered_malloc(); synchronized. 141 pool_type & p = get_pool(); 142 details::pool::guard<Mutex> g(p); 143 return p.ordered_malloc(); 144 } ordered_malloc(const size_type n)145 static void * ordered_malloc(const size_type n) 146 { //! Equivalent to SingletonPool::p.ordered_malloc(n); synchronized. 147 pool_type & p = get_pool(); 148 details::pool::guard<Mutex> g(p); 149 return p.ordered_malloc(n); 150 } is_from(void * const ptr)151 static bool is_from(void * const ptr) 152 { //! Equivalent to SingletonPool::p.is_from(chunk); synchronized. 153 //! \returns true if chunk is from SingletonPool::is_from(chunk) 154 pool_type & p = get_pool(); 155 details::pool::guard<Mutex> g(p); 156 return p.is_from(ptr); 157 } BOOST_PREVENT_MACRO_SUBSTITUTION(void * const ptr)158 static void free BOOST_PREVENT_MACRO_SUBSTITUTION(void * const ptr) 159 { //! Equivalent to SingletonPool::p.free(chunk); synchronized. 160 pool_type & p = get_pool(); 161 details::pool::guard<Mutex> g(p); 162 (p.free)(ptr); 163 } ordered_free(void * const ptr)164 static void ordered_free(void * const ptr) 165 { //! Equivalent to SingletonPool::p.ordered_free(chunk); synchronized. 166 pool_type & p = get_pool(); 167 details::pool::guard<Mutex> g(p); 168 p.ordered_free(ptr); 169 } BOOST_PREVENT_MACRO_SUBSTITUTION(void * const ptr,const size_type n)170 static void free BOOST_PREVENT_MACRO_SUBSTITUTION(void * const ptr, const size_type n) 171 { //! Equivalent to SingletonPool::p.free(chunk, n); synchronized. 172 pool_type & p = get_pool(); 173 details::pool::guard<Mutex> g(p); 174 (p.free)(ptr, n); 175 } ordered_free(void * const ptr,const size_type n)176 static void ordered_free(void * const ptr, const size_type n) 177 { //! Equivalent to SingletonPool::p.ordered_free(chunk, n); synchronized. 178 pool_type & p = get_pool(); 179 details::pool::guard<Mutex> g(p); 180 p.ordered_free(ptr, n); 181 } release_memory()182 static bool release_memory() 183 { //! Equivalent to SingletonPool::p.release_memory(); synchronized. 184 pool_type & p = get_pool(); 185 details::pool::guard<Mutex> g(p); 186 return p.release_memory(); 187 } purge_memory()188 static bool purge_memory() 189 { //! Equivalent to SingletonPool::p.purge_memory(); synchronized. 190 pool_type & p = get_pool(); 191 details::pool::guard<Mutex> g(p); 192 return p.purge_memory(); 193 } 194 195 private: 196 typedef boost::aligned_storage<sizeof(pool_type), boost::alignment_of<pool_type>::value> storage_type; 197 static storage_type storage; 198 get_pool()199 static pool_type& get_pool() 200 { 201 static bool f = false; 202 if(!f) 203 { 204 // This code *must* be called before main() starts, 205 // and when only one thread is executing. 206 f = true; 207 new (&storage) pool_type; 208 } 209 210 // The following line does nothing else than force the instantiation 211 // of singleton<T>::create_object, whose constructor is 212 // called before main() begins. 213 create_object.do_nothing(); 214 215 return *static_cast<pool_type*>(static_cast<void*>(&storage)); 216 } 217 218 struct object_creator 219 { object_creatorboost::singleton_pool::object_creator220 object_creator() 221 { // This constructor does nothing more than ensure that instance() 222 // is called before main() begins, thus creating the static 223 // T object before multithreading race issues can come up. 224 singleton_pool<Tag, RequestedSize, UserAllocator, Mutex, NextSize, MaxSize>::get_pool(); 225 } do_nothingboost::singleton_pool::object_creator226 inline void do_nothing() const 227 { 228 } 229 }; 230 static object_creator create_object; 231 }; // struct singleton_pool 232 233 template <typename Tag, 234 unsigned RequestedSize, 235 typename UserAllocator, 236 typename Mutex, 237 unsigned NextSize, 238 unsigned MaxSize > 239 typename singleton_pool<Tag, RequestedSize, UserAllocator, Mutex, NextSize, MaxSize>::storage_type singleton_pool<Tag, RequestedSize, UserAllocator, Mutex, NextSize, MaxSize>::storage; 240 241 template <typename Tag, 242 unsigned RequestedSize, 243 typename UserAllocator, 244 typename Mutex, 245 unsigned NextSize, 246 unsigned MaxSize > 247 typename singleton_pool<Tag, RequestedSize, UserAllocator, Mutex, NextSize, MaxSize>::object_creator singleton_pool<Tag, RequestedSize, UserAllocator, Mutex, NextSize, MaxSize>::create_object; 248 249 } // namespace boost 250 251 #endif 252