]>
Commit | Line | Data |
---|---|---|
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 |