• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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