Line data Source code
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 0 : 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 0 : static void * malloc BOOST_PREVENT_MACRO_SUBSTITUTION()
134 : { //! Equivalent to SingletonPool::p.malloc(); synchronized.
135 0 : pool_type & p = get_pool();
136 0 : details::pool::guard<Mutex> g(p);
137 0 : 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 0 : static void * ordered_malloc(const size_type n)
146 : { //! Equivalent to SingletonPool::p.ordered_malloc(n); synchronized.
147 0 : pool_type & p = get_pool();
148 0 : details::pool::guard<Mutex> g(p);
149 0 : return p.ordered_malloc(n);
150 : }
151 712 : 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 712 : pool_type & p = get_pool();
155 2136 : details::pool::guard<Mutex> g(p);
156 1424 : return p.is_from(ptr);
157 : }
158 0 : static void free BOOST_PREVENT_MACRO_SUBSTITUTION(void * const ptr)
159 : { //! Equivalent to SingletonPool::p.free(chunk); synchronized.
160 0 : pool_type & p = get_pool();
161 0 : details::pool::guard<Mutex> g(p);
162 0 : (p.free)(ptr);
163 0 : }
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 712 : static pool_type& get_pool()
200 : {
201 : static bool f = false;
202 712 : if(!f)
203 : {
204 : // This code *must* be called before main() starts,
205 : // and when only one thread is executing.
206 0 : f = true;
207 0 : 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 712 : 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 712 : 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
|