| 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 | { |
| 120 | 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: |
| 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 | } |
| 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 | } |
| 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 | } |
| 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 | } |
| 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 | } |
| 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 | } |
| 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 | } |
| 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 | } |
| 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 | } |
| 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 | |
| 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 | { |
| 220 | 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 | } |
| 226 | 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 | |