]>
Commit | Line | Data |
---|---|---|
1ff9402d BK |
1 | // MT-optimized allocator -*- C++ -*- |
2 | ||
2a60a9f6 | 3 | // Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 |
ca0f8fd1 | 4 | // Free Software Foundation, Inc. |
1ff9402d BK |
5 | // |
6 | // This file is part of the GNU ISO C++ Library. This library is free | |
7 | // software; you can redistribute it and/or modify it under the | |
8 | // terms of the GNU General Public License as published by the | |
748086b7 | 9 | // Free Software Foundation; either version 3, or (at your option) |
1ff9402d BK |
10 | // any later version. |
11 | ||
12 | // This library is distributed in the hope that it will be useful, | |
13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | // GNU General Public License for more details. | |
16 | ||
748086b7 JJ |
17 | // Under Section 7 of GPL version 3, you are granted additional |
18 | // permissions described in the GCC Runtime Library Exception, version | |
19 | // 3.1, as published by the Free Software Foundation. | |
1ff9402d | 20 | |
748086b7 JJ |
21 | // You should have received a copy of the GNU General Public License and |
22 | // a copy of the GCC Runtime Library Exception along with this program; | |
23 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
24 | // <http://www.gnu.org/licenses/>. | |
1ff9402d BK |
25 | |
26 | /** @file ext/mt_allocator.h | |
fa30fe72 | 27 | * This file is a GNU extension to the Standard C++ Library. |
1ff9402d BK |
28 | */ |
29 | ||
30 | #ifndef _MT_ALLOCATOR_H | |
31 | #define _MT_ALLOCATOR_H 1 | |
32 | ||
d38d4e5d | 33 | #include <new> |
1ef00312 | 34 | #include <cstdlib> |
fa30fe72 | 35 | #include <bits/functexcept.h> |
2e362c74 | 36 | #include <ext/atomicity.h> |
ca0f8fd1 | 37 | #include <bits/move.h> |
1ff9402d | 38 | |
12ffa228 BK |
39 | namespace __gnu_cxx _GLIBCXX_VISIBILITY(default) |
40 | { | |
41 | _GLIBCXX_BEGIN_NAMESPACE_VERSION | |
3cbc7af0 | 42 | |
05a2763e MG |
43 | using std::size_t; |
44 | using std::ptrdiff_t; | |
45 | ||
8bfd0a46 | 46 | typedef void (*__destroy_handler)(void*); |
8bfd0a46 | 47 | |
939759fc | 48 | /// Base class for pool object. |
12cde21b | 49 | struct __pool_base |
8bfd0a46 | 50 | { |
12cde21b | 51 | // Using short int as type for the binmap implies we are never |
47de6f6d | 52 | // caching blocks larger than 32768 with this allocator. |
12cde21b BK |
53 | typedef unsigned short int _Binmap_type; |
54 | ||
8bfd0a46 BK |
55 | // Variables used to configure the behavior of the allocator, |
56 | // assigned and explained in detail below. | |
57 | struct _Tune | |
6571df13 | 58 | { |
12cde21b BK |
59 | // Compile time constants for the default _Tune values. |
60 | enum { _S_align = 8 }; | |
61 | enum { _S_max_bytes = 128 }; | |
62 | enum { _S_min_bin = 8 }; | |
63 | enum { _S_chunk_size = 4096 - 4 * sizeof(void*) }; | |
64 | enum { _S_max_threads = 4096 }; | |
65 | enum { _S_freelist_headroom = 10 }; | |
66 | ||
8bfd0a46 BK |
67 | // Alignment needed. |
68 | // NB: In any case must be >= sizeof(_Block_record), that | |
69 | // is 4 on 32 bit machines and 8 on 64 bit machines. | |
12cde21b | 70 | size_t _M_align; |
8bfd0a46 BK |
71 | |
72 | // Allocation requests (after round-up to power of 2) below | |
73 | // this value will be handled by the allocator. A raw new/ | |
74 | // call will be used for requests larger than this value. | |
47de6f6d PC |
75 | // NB: Must be much smaller than _M_chunk_size and in any |
76 | // case <= 32768. | |
8bfd0a46 | 77 | size_t _M_max_bytes; |
47de6f6d | 78 | |
8bfd0a46 | 79 | // Size in bytes of the smallest bin. |
47de6f6d PC |
80 | // NB: Must be a power of 2 and >= _M_align (and of course |
81 | // much smaller than _M_max_bytes). | |
12cde21b | 82 | size_t _M_min_bin; |
47de6f6d | 83 | |
8bfd0a46 BK |
84 | // In order to avoid fragmenting and minimize the number of |
85 | // new() calls we always request new memory using this | |
86 | // value. Based on previous discussions on the libstdc++ | |
28dac70a | 87 | // mailing list we have chosen the value below. |
8bfd0a46 | 88 | // See http://gcc.gnu.org/ml/libstdc++/2001-07/msg00077.html |
47de6f6d | 89 | // NB: At least one order of magnitude > _M_max_bytes. |
12cde21b | 90 | size_t _M_chunk_size; |
47de6f6d | 91 | |
8bfd0a46 BK |
92 | // The maximum number of supported threads. For |
93 | // single-threaded operation, use one. Maximum values will | |
94 | // vary depending on details of the underlying system. (For | |
95 | // instance, Linux 2.4.18 reports 4070 in | |
96 | // /proc/sys/kernel/threads-max, while Linux 2.6.6 reports | |
97 | // 65534) | |
98 | size_t _M_max_threads; | |
47de6f6d | 99 | |
8bfd0a46 BK |
100 | // Each time a deallocation occurs in a threaded application |
101 | // we make sure that there are no more than | |
102 | // _M_freelist_headroom % of used memory on the freelist. If | |
103 | // the number of additional records is more than | |
104 | // _M_freelist_headroom % of the freelist, we move these | |
105 | // records back to the global pool. | |
106 | size_t _M_freelist_headroom; | |
107 | ||
108 | // Set to true forces all allocations to use new(). | |
109 | bool _M_force_new; | |
110 | ||
111 | explicit | |
112 | _Tune() | |
12cde21b BK |
113 | : _M_align(_S_align), _M_max_bytes(_S_max_bytes), _M_min_bin(_S_min_bin), |
114 | _M_chunk_size(_S_chunk_size), _M_max_threads(_S_max_threads), | |
115 | _M_freelist_headroom(_S_freelist_headroom), | |
05a79eb6 | 116 | _M_force_new(std::getenv("GLIBCXX_FORCE_NEW") ? true : false) |
8bfd0a46 BK |
117 | { } |
118 | ||
119 | explicit | |
120 | _Tune(size_t __align, size_t __maxb, size_t __minbin, size_t __chunk, | |
121 | size_t __maxthreads, size_t __headroom, bool __force) | |
122 | : _M_align(__align), _M_max_bytes(__maxb), _M_min_bin(__minbin), | |
123 | _M_chunk_size(__chunk), _M_max_threads(__maxthreads), | |
124 | _M_freelist_headroom(__headroom), _M_force_new(__force) | |
125 | { } | |
12cde21b BK |
126 | }; |
127 | ||
128 | struct _Block_address | |
129 | { | |
130 | void* _M_initial; | |
131 | _Block_address* _M_next; | |
8bfd0a46 BK |
132 | }; |
133 | ||
134 | const _Tune& | |
135 | _M_get_options() const | |
136 | { return _M_options; } | |
f263b26e | 137 | |
8bfd0a46 BK |
138 | void |
139 | _M_set_options(_Tune __t) | |
140 | { | |
141 | if (!_M_init) | |
142 | _M_options = __t; | |
143 | } | |
f263b26e | 144 | |
8bfd0a46 BK |
145 | bool |
146 | _M_check_threshold(size_t __bytes) | |
147 | { return __bytes > _M_options._M_max_bytes || _M_options._M_force_new; } | |
f263b26e | 148 | |
8bfd0a46 BK |
149 | size_t |
150 | _M_get_binmap(size_t __bytes) | |
151 | { return _M_binmap[__bytes]; } | |
152 | ||
aba7b40d | 153 | size_t |
7befac71 BK |
154 | _M_get_align() |
155 | { return _M_options._M_align; } | |
156 | ||
6571df13 BK |
157 | explicit |
158 | __pool_base() | |
8fc81078 | 159 | : _M_options(_Tune()), _M_binmap(0), _M_init(false) { } |
8bfd0a46 | 160 | |
6571df13 BK |
161 | explicit |
162 | __pool_base(const _Tune& __options) | |
8fc81078 | 163 | : _M_options(__options), _M_binmap(0), _M_init(false) { } |
6571df13 BK |
164 | |
165 | private: | |
166 | explicit | |
167 | __pool_base(const __pool_base&); | |
168 | ||
169 | __pool_base& | |
170 | operator=(const __pool_base&); | |
61b26514 | 171 | |
8bfd0a46 | 172 | protected: |
8bfd0a46 BK |
173 | // Configuration options. |
174 | _Tune _M_options; | |
175 | ||
8bfd0a46 | 176 | _Binmap_type* _M_binmap; |
12cde21b | 177 | |
6571df13 BK |
178 | // Configuration of the pool object via _M_options can happen |
179 | // after construction but before initialization. After | |
180 | // initialization is complete, this variable is set to true. | |
12cde21b | 181 | bool _M_init; |
8bfd0a46 BK |
182 | }; |
183 | ||
6309eefc BK |
184 | |
185 | /** | |
186 | * @brief Data describing the underlying memory pool, parameterized on | |
187 | * threading support. | |
188 | */ | |
8bfd0a46 BK |
189 | template<bool _Thread> |
190 | class __pool; | |
191 | ||
6309eefc | 192 | /// Specialization for single thread. |
6571df13 BK |
193 | template<> |
194 | class __pool<false> : public __pool_base | |
195 | { | |
196 | public: | |
197 | union _Block_record | |
198 | { | |
199 | // Points to the block_record of the next free block. | |
e282a2bc | 200 | _Block_record* _M_next; |
6571df13 BK |
201 | }; |
202 | ||
203 | struct _Bin_record | |
204 | { | |
205 | // An "array" of pointers to the first free block. | |
e282a2bc | 206 | _Block_record** _M_first; |
780028b6 | 207 | |
6571df13 BK |
208 | // A list of the initial addresses of all allocated blocks. |
209 | _Block_address* _M_address; | |
210 | }; | |
211 | ||
212 | void | |
213 | _M_initialize_once() | |
214 | { | |
215 | if (__builtin_expect(_M_init == false, false)) | |
216 | _M_initialize(); | |
217 | } | |
218 | ||
219 | void | |
220 | _M_destroy() throw(); | |
221 | ||
222 | char* | |
223 | _M_reserve_block(size_t __bytes, const size_t __thread_id); | |
224 | ||
225 | void | |
5d51b87a | 226 | _M_reclaim_block(char* __p, size_t __bytes) throw (); |
6571df13 BK |
227 | |
228 | size_t | |
229 | _M_get_thread_id() { return 0; } | |
230 | ||
231 | const _Bin_record& | |
232 | _M_get_bin(size_t __which) | |
233 | { return _M_bin[__which]; } | |
234 | ||
235 | void | |
236 | _M_adjust_freelist(const _Bin_record&, _Block_record*, size_t) | |
237 | { } | |
238 | ||
239 | explicit __pool() | |
8fc81078 | 240 | : _M_bin(0), _M_bin_size(1) { } |
6571df13 BK |
241 | |
242 | explicit __pool(const __pool_base::_Tune& __tune) | |
8fc81078 | 243 | : __pool_base(__tune), _M_bin(0), _M_bin_size(1) { } |
6571df13 BK |
244 | |
245 | private: | |
246 | // An "array" of bin_records each of which represents a specific | |
247 | // power of 2 size. Memory to this "array" is allocated in | |
248 | // _M_initialize(). | |
e282a2bc | 249 | _Bin_record* _M_bin; |
6571df13 BK |
250 | |
251 | // Actual value calculated in _M_initialize(). | |
252 | size_t _M_bin_size; | |
253 | ||
254 | void | |
255 | _M_initialize(); | |
256 | }; | |
257 | ||
1ff9402d | 258 | #ifdef __GTHREADS |
6309eefc | 259 | /// Specialization for thread enabled, via gthreads.h. |
8bfd0a46 BK |
260 | template<> |
261 | class __pool<true> : public __pool_base | |
262 | { | |
263 | public: | |
f263b26e BK |
264 | // Each requesting thread is assigned an id ranging from 1 to |
265 | // _S_max_threads. Thread id 0 is used as a global memory pool. | |
266 | // In order to get constant performance on the thread assignment | |
267 | // routine, we keep a list of free ids. When a thread first | |
268 | // requests memory we remove the first record in this list and | |
269 | // stores the address in a __gthread_key. When initializing the | |
270 | // __gthread_key we specify a destructor. When this destructor | |
271 | // (i.e. the thread dies) is called, we return the thread id to | |
272 | // the front of this list. | |
6f52a889 | 273 | struct _Thread_record |
1ff9402d | 274 | { |
8bfd0a46 | 275 | // Points to next free thread id record. NULL if last record in list. |
e282a2bc | 276 | _Thread_record* _M_next; |
8bfd0a46 | 277 | |
f263b26e | 278 | // Thread id ranging from 1 to _S_max_threads. |
8bfd0a46 | 279 | size_t _M_id; |
1ff9402d | 280 | }; |
8bfd0a46 | 281 | |
6f52a889 | 282 | union _Block_record |
1ff9402d | 283 | { |
354d4c68 | 284 | // Points to the block_record of the next free block. |
e282a2bc | 285 | _Block_record* _M_next; |
8bfd0a46 | 286 | |
c8333c0f | 287 | // The thread id of the thread which has requested this block. |
8bfd0a46 | 288 | size_t _M_thread_id; |
1ff9402d | 289 | }; |
8bfd0a46 | 290 | |
6f52a889 | 291 | struct _Bin_record |
1ff9402d | 292 | { |
f263b26e | 293 | // An "array" of pointers to the first free block for each |
12cde21b BK |
294 | // thread id. Memory to this "array" is allocated in |
295 | // _S_initialize() for _S_max_threads + global pool 0. | |
e282a2bc | 296 | _Block_record** _M_first; |
8bfd0a46 | 297 | |
12cde21b BK |
298 | // A list of the initial addresses of all allocated blocks. |
299 | _Block_address* _M_address; | |
300 | ||
f263b26e BK |
301 | // An "array" of counters used to keep track of the amount of |
302 | // blocks that are on the freelist/used for each thread id. | |
1d3e6248 PC |
303 | // - Note that the second part of the allocated _M_used "array" |
304 | // actually hosts (atomic) counters of reclaimed blocks: in | |
305 | // _M_reserve_block and in _M_reclaim_block those numbers are | |
306 | // subtracted from the first ones to obtain the actual size | |
307 | // of the "working set" of the given thread. | |
308 | // - Memory to these "arrays" is allocated in _S_initialize() | |
309 | // for _S_max_threads + global pool 0. | |
e282a2bc RG |
310 | size_t* _M_free; |
311 | size_t* _M_used; | |
8bfd0a46 | 312 | |
f263b26e BK |
313 | // Each bin has its own mutex which is used to ensure data |
314 | // integrity while changing "ownership" on a block. The mutex | |
315 | // is initialized in _S_initialize(). | |
8bfd0a46 BK |
316 | __gthread_mutex_t* _M_mutex; |
317 | }; | |
318 | ||
2f9f6cef | 319 | // XXX GLIBCXX_ABI Deprecated |
8bfd0a46 | 320 | void |
2f9f6cef | 321 | _M_initialize(__destroy_handler); |
8bfd0a46 BK |
322 | |
323 | void | |
2f9f6cef | 324 | _M_initialize_once() |
8bfd0a46 | 325 | { |
8bfd0a46 | 326 | if (__builtin_expect(_M_init == false, false)) |
2f9f6cef | 327 | _M_initialize(); |
8bfd0a46 BK |
328 | } |
329 | ||
5a1e5472 BK |
330 | void |
331 | _M_destroy() throw(); | |
332 | ||
8bfd0a46 | 333 | char* |
12cde21b | 334 | _M_reserve_block(size_t __bytes, const size_t __thread_id); |
8bfd0a46 BK |
335 | |
336 | void | |
5d51b87a | 337 | _M_reclaim_block(char* __p, size_t __bytes) throw (); |
8bfd0a46 BK |
338 | |
339 | const _Bin_record& | |
340 | _M_get_bin(size_t __which) | |
341 | { return _M_bin[__which]; } | |
342 | ||
343 | void | |
344 | _M_adjust_freelist(const _Bin_record& __bin, _Block_record* __block, | |
345 | size_t __thread_id) | |
346 | { | |
347 | if (__gthread_active_p()) | |
348 | { | |
349 | __block->_M_thread_id = __thread_id; | |
350 | --__bin._M_free[__thread_id]; | |
351 | ++__bin._M_used[__thread_id]; | |
352 | } | |
353 | } | |
354 | ||
2f9f6cef | 355 | // XXX GLIBCXX_ABI Deprecated |
5d51b87a JH |
356 | _GLIBCXX_CONST void |
357 | _M_destroy_thread_key(void*) throw (); | |
8bfd0a46 BK |
358 | |
359 | size_t | |
360 | _M_get_thread_id(); | |
361 | ||
362 | explicit __pool() | |
8fc81078 | 363 | : _M_bin(0), _M_bin_size(1), _M_thread_freelist(0) |
2f9f6cef | 364 | { } |
8bfd0a46 | 365 | |
61b26514 | 366 | explicit __pool(const __pool_base::_Tune& __tune) |
8fc81078 PC |
367 | : __pool_base(__tune), _M_bin(0), _M_bin_size(1), |
368 | _M_thread_freelist(0) | |
2f9f6cef | 369 | { } |
61b26514 | 370 | |
8bfd0a46 BK |
371 | private: |
372 | // An "array" of bin_records each of which represents a specific | |
373 | // power of 2 size. Memory to this "array" is allocated in | |
374 | // _M_initialize(). | |
e282a2bc | 375 | _Bin_record* _M_bin; |
8bfd0a46 BK |
376 | |
377 | // Actual value calculated in _M_initialize(). | |
378 | size_t _M_bin_size; | |
379 | ||
8bfd0a46 | 380 | _Thread_record* _M_thread_freelist; |
12cde21b | 381 | void* _M_thread_freelist_initial; |
2f9f6cef BK |
382 | |
383 | void | |
384 | _M_initialize(); | |
8bfd0a46 | 385 | }; |
1ff9402d | 386 | #endif |
8bfd0a46 | 387 | |
6571df13 | 388 | template<template <bool> class _PoolTp, bool _Thread> |
2f9f6cef | 389 | struct __common_pool |
8bfd0a46 | 390 | { |
2f9f6cef | 391 | typedef _PoolTp<_Thread> pool_type; |
6571df13 | 392 | |
6571df13 | 393 | static pool_type& |
12cde21b BK |
394 | _S_get_pool() |
395 | { | |
6571df13 | 396 | static pool_type _S_pool; |
12cde21b BK |
397 | return _S_pool; |
398 | } | |
2f9f6cef BK |
399 | }; |
400 | ||
401 | template<template <bool> class _PoolTp, bool _Thread> | |
402 | struct __common_pool_base; | |
403 | ||
404 | template<template <bool> class _PoolTp> | |
405 | struct __common_pool_base<_PoolTp, false> | |
406 | : public __common_pool<_PoolTp, false> | |
407 | { | |
408 | using __common_pool<_PoolTp, false>::_S_get_pool; | |
8bfd0a46 BK |
409 | |
410 | static void | |
2f9f6cef BK |
411 | _S_initialize_once() |
412 | { | |
8bfd0a46 BK |
413 | static bool __init; |
414 | if (__builtin_expect(__init == false, false)) | |
415 | { | |
416 | _S_get_pool()._M_initialize_once(); | |
417 | __init = true; | |
418 | } | |
419 | } | |
f263b26e BK |
420 | }; |
421 | ||
8bfd0a46 | 422 | #ifdef __GTHREADS |
6571df13 | 423 | template<template <bool> class _PoolTp> |
2f9f6cef BK |
424 | struct __common_pool_base<_PoolTp, true> |
425 | : public __common_pool<_PoolTp, true> | |
8bfd0a46 | 426 | { |
2f9f6cef | 427 | using __common_pool<_PoolTp, true>::_S_get_pool; |
6571df13 | 428 | |
2f9f6cef BK |
429 | static void |
430 | _S_initialize() | |
431 | { _S_get_pool()._M_initialize_once(); } | |
8bfd0a46 | 432 | |
8bfd0a46 | 433 | static void |
2f9f6cef | 434 | _S_initialize_once() |
8bfd0a46 BK |
435 | { |
436 | static bool __init; | |
437 | if (__builtin_expect(__init == false, false)) | |
438 | { | |
2f9f6cef BK |
439 | if (__gthread_active_p()) |
440 | { | |
441 | // On some platforms, __gthread_once_t is an aggregate. | |
442 | static __gthread_once_t __once = __GTHREAD_ONCE_INIT; | |
443 | __gthread_once(&__once, _S_initialize); | |
444 | } | |
4bd2f9d6 BK |
445 | |
446 | // Double check initialization. May be necessary on some | |
447 | // systems for proper construction when not compiling with | |
448 | // thread flags. | |
449 | _S_get_pool()._M_initialize_once(); | |
8bfd0a46 BK |
450 | __init = true; |
451 | } | |
452 | } | |
2f9f6cef | 453 | }; |
8bfd0a46 BK |
454 | #endif |
455 | ||
939759fc | 456 | /// Policy for shared __pool objects. |
2f9f6cef BK |
457 | template<template <bool> class _PoolTp, bool _Thread> |
458 | struct __common_pool_policy : public __common_pool_base<_PoolTp, _Thread> | |
8bfd0a46 | 459 | { |
6571df13 | 460 | template<typename _Tp1, template <bool> class _PoolTp1 = _PoolTp, |
2f9f6cef | 461 | bool _Thread1 = _Thread> |
6571df13 | 462 | struct _M_rebind |
2f9f6cef | 463 | { typedef __common_pool_policy<_PoolTp1, _Thread1> other; }; |
8bfd0a46 | 464 | |
2f9f6cef BK |
465 | using __common_pool_base<_PoolTp, _Thread>::_S_get_pool; |
466 | using __common_pool_base<_PoolTp, _Thread>::_S_initialize_once; | |
467 | }; | |
468 | ||
469 | ||
470 | template<typename _Tp, template <bool> class _PoolTp, bool _Thread> | |
471 | struct __per_type_pool | |
472 | { | |
473 | typedef _Tp value_type; | |
474 | typedef _PoolTp<_Thread> pool_type; | |
475 | ||
6571df13 BK |
476 | static pool_type& |
477 | _S_get_pool() | |
12cde21b | 478 | { |
6571df13 | 479 | // Sane defaults for the _PoolTp. |
b929615a | 480 | typedef typename pool_type::_Block_record _Block_record; |
2f9f6cef BK |
481 | const static size_t __a = (__alignof__(_Tp) >= sizeof(_Block_record) |
482 | ? __alignof__(_Tp) : sizeof(_Block_record)); | |
b929615a PC |
483 | |
484 | typedef typename __pool_base::_Tune _Tune; | |
2f9f6cef BK |
485 | static _Tune _S_tune(__a, sizeof(_Tp) * 64, |
486 | sizeof(_Tp) * 2 >= __a ? sizeof(_Tp) * 2 : __a, | |
a9dd5a46 | 487 | sizeof(_Tp) * size_t(_Tune::_S_chunk_size), |
b929615a PC |
488 | _Tune::_S_max_threads, |
489 | _Tune::_S_freelist_headroom, | |
05a79eb6 | 490 | std::getenv("GLIBCXX_FORCE_NEW") ? true : false); |
6571df13 | 491 | static pool_type _S_pool(_S_tune); |
12cde21b BK |
492 | return _S_pool; |
493 | } | |
2f9f6cef BK |
494 | }; |
495 | ||
496 | template<typename _Tp, template <bool> class _PoolTp, bool _Thread> | |
497 | struct __per_type_pool_base; | |
498 | ||
499 | template<typename _Tp, template <bool> class _PoolTp> | |
500 | struct __per_type_pool_base<_Tp, _PoolTp, false> | |
501 | : public __per_type_pool<_Tp, _PoolTp, false> | |
502 | { | |
503 | using __per_type_pool<_Tp, _PoolTp, false>::_S_get_pool; | |
8bfd0a46 BK |
504 | |
505 | static void | |
b929615a | 506 | _S_initialize_once() |
2f9f6cef | 507 | { |
8bfd0a46 BK |
508 | static bool __init; |
509 | if (__builtin_expect(__init == false, false)) | |
510 | { | |
511 | _S_get_pool()._M_initialize_once(); | |
512 | __init = true; | |
513 | } | |
514 | } | |
515 | }; | |
516 | ||
2f9f6cef BK |
517 | #ifdef __GTHREADS |
518 | template<typename _Tp, template <bool> class _PoolTp> | |
519 | struct __per_type_pool_base<_Tp, _PoolTp, true> | |
520 | : public __per_type_pool<_Tp, _PoolTp, true> | |
f263b26e | 521 | { |
2f9f6cef | 522 | using __per_type_pool<_Tp, _PoolTp, true>::_S_get_pool; |
8bfd0a46 | 523 | |
2f9f6cef BK |
524 | static void |
525 | _S_initialize() | |
526 | { _S_get_pool()._M_initialize_once(); } | |
8bfd0a46 | 527 | |
8bfd0a46 | 528 | static void |
b929615a | 529 | _S_initialize_once() |
8bfd0a46 BK |
530 | { |
531 | static bool __init; | |
532 | if (__builtin_expect(__init == false, false)) | |
533 | { | |
2f9f6cef BK |
534 | if (__gthread_active_p()) |
535 | { | |
536 | // On some platforms, __gthread_once_t is an aggregate. | |
537 | static __gthread_once_t __once = __GTHREAD_ONCE_INIT; | |
538 | __gthread_once(&__once, _S_initialize); | |
539 | } | |
4bd2f9d6 BK |
540 | |
541 | // Double check initialization. May be necessary on some | |
542 | // systems for proper construction when not compiling with | |
543 | // thread flags. | |
544 | _S_get_pool()._M_initialize_once(); | |
8bfd0a46 BK |
545 | __init = true; |
546 | } | |
547 | } | |
548 | }; | |
1ff9402d | 549 | #endif |
8bfd0a46 | 550 | |
939759fc | 551 | /// Policy for individual __pool objects. |
2f9f6cef BK |
552 | template<typename _Tp, template <bool> class _PoolTp, bool _Thread> |
553 | struct __per_type_pool_policy | |
554 | : public __per_type_pool_base<_Tp, _PoolTp, _Thread> | |
555 | { | |
556 | template<typename _Tp1, template <bool> class _PoolTp1 = _PoolTp, | |
557 | bool _Thread1 = _Thread> | |
558 | struct _M_rebind | |
559 | { typedef __per_type_pool_policy<_Tp1, _PoolTp1, _Thread1> other; }; | |
560 | ||
561 | using __per_type_pool_base<_Tp, _PoolTp, _Thread>::_S_get_pool; | |
562 | using __per_type_pool_base<_Tp, _PoolTp, _Thread>::_S_initialize_once; | |
563 | }; | |
564 | ||
565 | ||
939759fc | 566 | /// Base class for _Tp dependent member functions. |
8bfd0a46 BK |
567 | template<typename _Tp> |
568 | class __mt_alloc_base | |
569 | { | |
570 | public: | |
571 | typedef size_t size_type; | |
572 | typedef ptrdiff_t difference_type; | |
573 | typedef _Tp* pointer; | |
574 | typedef const _Tp* const_pointer; | |
575 | typedef _Tp& reference; | |
576 | typedef const _Tp& const_reference; | |
577 | typedef _Tp value_type; | |
578 | ||
579 | pointer | |
580 | address(reference __x) const | |
882b3d5c | 581 | { return std::__addressof(__x); } |
8bfd0a46 BK |
582 | |
583 | const_pointer | |
584 | address(const_reference __x) const | |
882b3d5c | 585 | { return std::__addressof(__x); } |
8bfd0a46 BK |
586 | |
587 | size_type | |
588 | max_size() const throw() | |
589 | { return size_t(-1) / sizeof(_Tp); } | |
590 | ||
591 | // _GLIBCXX_RESOLVE_LIB_DEFECTS | |
592 | // 402. wrong new expression in [some_] allocator::construct | |
593 | void | |
594 | construct(pointer __p, const _Tp& __val) | |
61fcb9fb PC |
595 | { ::new((void *)__p) _Tp(__val); } |
596 | ||
597 | #ifdef __GXX_EXPERIMENTAL_CXX0X__ | |
598 | template<typename... _Args> | |
599 | void | |
600 | construct(pointer __p, _Args&&... __args) | |
601 | { ::new((void *)__p) _Tp(std::forward<_Args>(__args)...); } | |
602 | #endif | |
8bfd0a46 BK |
603 | |
604 | void | |
605 | destroy(pointer __p) { __p->~_Tp(); } | |
606 | }; | |
607 | ||
12cde21b | 608 | #ifdef __GTHREADS |
6571df13 | 609 | #define __thread_default true |
12cde21b | 610 | #else |
6571df13 | 611 | #define __thread_default false |
12cde21b BK |
612 | #endif |
613 | ||
6309eefc BK |
614 | /** |
615 | * @brief This is a fixed size (power of 2) allocator which - when | |
616 | * compiled with thread support - will maintain one freelist per | |
2a60a9f6 | 617 | * size per thread plus a @a global one. Steps are taken to limit |
6309eefc | 618 | * the per thread freelist sizes (by returning excess back to |
2a60a9f6 | 619 | * the @a global list). |
5b9daa7e | 620 | * @ingroup allocators |
6309eefc BK |
621 | * |
622 | * Further details: | |
939759fc | 623 | * http://gcc.gnu.org/onlinedocs/libstdc++/manual/bk01pt12ch32.html |
6309eefc | 624 | */ |
6571df13 BK |
625 | template<typename _Tp, |
626 | typename _Poolp = __common_pool_policy<__pool, __thread_default> > | |
627 | class __mt_alloc : public __mt_alloc_base<_Tp> | |
8bfd0a46 BK |
628 | { |
629 | public: | |
61b26514 BK |
630 | typedef size_t size_type; |
631 | typedef ptrdiff_t difference_type; | |
632 | typedef _Tp* pointer; | |
633 | typedef const _Tp* const_pointer; | |
634 | typedef _Tp& reference; | |
635 | typedef const _Tp& const_reference; | |
636 | typedef _Tp value_type; | |
6571df13 BK |
637 | typedef _Poolp __policy_type; |
638 | typedef typename _Poolp::pool_type __pool_type; | |
8bfd0a46 BK |
639 | |
640 | template<typename _Tp1, typename _Poolp1 = _Poolp> | |
641 | struct rebind | |
642 | { | |
643 | typedef typename _Poolp1::template _M_rebind<_Tp1>::other pol_type; | |
644 | typedef __mt_alloc<_Tp1, pol_type> other; | |
645 | }; | |
646 | ||
fa5e3f06 | 647 | __mt_alloc() throw() { } |
8bfd0a46 | 648 | |
fa5e3f06 | 649 | __mt_alloc(const __mt_alloc&) throw() { } |
8bfd0a46 BK |
650 | |
651 | template<typename _Tp1, typename _Poolp1> | |
8b5bc374 | 652 | __mt_alloc(const __mt_alloc<_Tp1, _Poolp1>&) throw() { } |
8bfd0a46 BK |
653 | |
654 | ~__mt_alloc() throw() { } | |
655 | ||
656 | pointer | |
657 | allocate(size_type __n, const void* = 0); | |
658 | ||
659 | void | |
660 | deallocate(pointer __p, size_type __n); | |
661 | ||
662 | const __pool_base::_Tune | |
663 | _M_get_options() | |
664 | { | |
665 | // Return a copy, not a reference, for external consumption. | |
6571df13 | 666 | return __policy_type::_S_get_pool()._M_get_options(); |
8bfd0a46 | 667 | } |
f263b26e | 668 | |
8bfd0a46 BK |
669 | void |
670 | _M_set_options(__pool_base::_Tune __t) | |
6571df13 | 671 | { __policy_type::_S_get_pool()._M_set_options(__t); } |
8bfd0a46 BK |
672 | }; |
673 | ||
674 | template<typename _Tp, typename _Poolp> | |
675 | typename __mt_alloc<_Tp, _Poolp>::pointer | |
676 | __mt_alloc<_Tp, _Poolp>:: | |
677 | allocate(size_type __n, const void*) | |
678 | { | |
e762c6f4 | 679 | if (__n > this->max_size()) |
a063e891 PC |
680 | std::__throw_bad_alloc(); |
681 | ||
6571df13 BK |
682 | __policy_type::_S_initialize_once(); |
683 | ||
61b26514 BK |
684 | // Requests larger than _M_max_bytes are handled by operator |
685 | // new/delete directly. | |
6571df13 | 686 | __pool_type& __pool = __policy_type::_S_get_pool(); |
f263b26e | 687 | const size_t __bytes = __n * sizeof(_Tp); |
12cde21b | 688 | if (__pool._M_check_threshold(__bytes)) |
f263b26e BK |
689 | { |
690 | void* __ret = ::operator new(__bytes); | |
691 | return static_cast<_Tp*>(__ret); | |
692 | } | |
a063e891 | 693 | |
f263b26e | 694 | // Round up to power of 2 and figure out which bin to use. |
12cde21b BK |
695 | const size_t __which = __pool._M_get_binmap(__bytes); |
696 | const size_t __thread_id = __pool._M_get_thread_id(); | |
f263b26e BK |
697 | |
698 | // Find out if we have blocks on our freelist. If so, go ahead | |
699 | // and use them directly without having to lock anything. | |
8bfd0a46 BK |
700 | char* __c; |
701 | typedef typename __pool_type::_Bin_record _Bin_record; | |
12cde21b | 702 | const _Bin_record& __bin = __pool._M_get_bin(__which); |
8bfd0a46 | 703 | if (__bin._M_first[__thread_id]) |
f263b26e | 704 | { |
8bfd0a46 BK |
705 | // Already reserved. |
706 | typedef typename __pool_type::_Block_record _Block_record; | |
707 | _Block_record* __block = __bin._M_first[__thread_id]; | |
11aaaa84 | 708 | __bin._M_first[__thread_id] = __block->_M_next; |
8bfd0a46 | 709 | |
12cde21b | 710 | __pool._M_adjust_freelist(__bin, __block, __thread_id); |
7befac71 | 711 | __c = reinterpret_cast<char*>(__block) + __pool._M_get_align(); |
f263b26e | 712 | } |
8bfd0a46 | 713 | else |
c8333c0f | 714 | { |
8bfd0a46 | 715 | // Null, reserve. |
12cde21b | 716 | __c = __pool._M_reserve_block(__bytes, __thread_id); |
f263b26e | 717 | } |
ce7df2fd | 718 | return static_cast<_Tp*>(static_cast<void*>(__c)); |
f263b26e BK |
719 | } |
720 | ||
8bfd0a46 | 721 | template<typename _Tp, typename _Poolp> |
f263b26e | 722 | void |
8bfd0a46 | 723 | __mt_alloc<_Tp, _Poolp>:: |
f263b26e BK |
724 | deallocate(pointer __p, size_type __n) |
725 | { | |
5d1b2a1e BK |
726 | if (__builtin_expect(__p != 0, true)) |
727 | { | |
728 | // Requests larger than _M_max_bytes are handled by | |
729 | // operators new/delete directly. | |
6571df13 | 730 | __pool_type& __pool = __policy_type::_S_get_pool(); |
5d1b2a1e BK |
731 | const size_t __bytes = __n * sizeof(_Tp); |
732 | if (__pool._M_check_threshold(__bytes)) | |
733 | ::operator delete(__p); | |
734 | else | |
735 | __pool._M_reclaim_block(reinterpret_cast<char*>(__p), __bytes); | |
736 | } | |
f263b26e BK |
737 | } |
738 | ||
8bfd0a46 | 739 | template<typename _Tp, typename _Poolp> |
f263b26e | 740 | inline bool |
8bfd0a46 | 741 | operator==(const __mt_alloc<_Tp, _Poolp>&, const __mt_alloc<_Tp, _Poolp>&) |
f263b26e BK |
742 | { return true; } |
743 | ||
8bfd0a46 | 744 | template<typename _Tp, typename _Poolp> |
f263b26e | 745 | inline bool |
8bfd0a46 | 746 | operator!=(const __mt_alloc<_Tp, _Poolp>&, const __mt_alloc<_Tp, _Poolp>&) |
f263b26e | 747 | { return false; } |
12cde21b | 748 | |
6571df13 | 749 | #undef __thread_default |
3cbc7af0 | 750 | |
12ffa228 BK |
751 | _GLIBCXX_END_NAMESPACE_VERSION |
752 | } // namespace | |
1ff9402d | 753 | |
1ff9402d | 754 | #endif |