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