]> git.ipfire.org Git - thirdparty/gcc.git/blob - libstdc++-v3/src/c++98/mt_allocator.cc
Update copyright years in libstdc++-v3/
[thirdparty/gcc.git] / libstdc++-v3 / src / c++98 / mt_allocator.cc
1 // Allocator details.
2
3 // Copyright (C) 2004-2014 Free Software Foundation, Inc.
4 //
5 // This file is part of the GNU ISO C++ Library. This library is free
6 // software; you can redistribute it and/or modify it under the
7 // terms of the GNU General Public License as published by the
8 // Free Software Foundation; either version 3, or (at your option)
9 // any later version.
10
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15
16 // Under Section 7 of GPL version 3, you are granted additional
17 // permissions described in the GCC Runtime Library Exception, version
18 // 3.1, as published by the Free Software Foundation.
19
20 // You should have received a copy of the GNU General Public License and
21 // a copy of the GCC Runtime Library Exception along with this program;
22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 // <http://www.gnu.org/licenses/>.
24
25 //
26 // ISO C++ 14882:
27 //
28
29 #include <bits/c++config.h>
30 #include <ext/concurrence.h>
31 #include <ext/mt_allocator.h>
32 #include <cstring>
33
34 namespace
35 {
36 #ifdef __GTHREADS
37 struct __freelist
38 {
39 typedef __gnu_cxx::__pool<true>::_Thread_record _Thread_record;
40 _Thread_record* _M_thread_freelist;
41 _Thread_record* _M_thread_freelist_array;
42 size_t _M_max_threads;
43 __gthread_key_t _M_key;
44
45 ~__freelist()
46 {
47 if (_M_thread_freelist_array)
48 {
49 __gthread_key_delete(_M_key);
50 ::operator delete(static_cast<void*>(_M_thread_freelist_array));
51 _M_thread_freelist = 0;
52 }
53 }
54 };
55
56 __freelist&
57 get_freelist()
58 {
59 static __freelist freelist;
60 return freelist;
61 }
62
63 __gnu_cxx::__mutex&
64 get_freelist_mutex()
65 {
66 static __gnu_cxx::__mutex freelist_mutex;
67 return freelist_mutex;
68 }
69
70 static void
71 _M_destroy_thread_key(void* __id)
72 {
73 // Return this thread id record to the front of thread_freelist.
74 __freelist& freelist = get_freelist();
75 {
76 __gnu_cxx::__scoped_lock sentry(get_freelist_mutex());
77 size_t _M_id = reinterpret_cast<size_t>(__id);
78
79 typedef __gnu_cxx::__pool<true>::_Thread_record _Thread_record;
80 _Thread_record* __tr = &freelist._M_thread_freelist_array[_M_id - 1];
81 __tr->_M_next = freelist._M_thread_freelist;
82 freelist._M_thread_freelist = __tr;
83 }
84 }
85 #endif
86 } // anonymous namespace
87
88 namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)
89 {
90 _GLIBCXX_BEGIN_NAMESPACE_VERSION
91
92 void
93 __pool<false>::_M_destroy() throw()
94 {
95 if (_M_init && !_M_options._M_force_new)
96 {
97 for (size_t __n = 0; __n < _M_bin_size; ++__n)
98 {
99 _Bin_record& __bin = _M_bin[__n];
100 while (__bin._M_address)
101 {
102 _Block_address* __tmp = __bin._M_address->_M_next;
103 ::operator delete(__bin._M_address->_M_initial);
104 __bin._M_address = __tmp;
105 }
106 ::operator delete(__bin._M_first);
107 }
108 ::operator delete(_M_bin);
109 ::operator delete(_M_binmap);
110 }
111 }
112
113 void
114 __pool<false>::_M_reclaim_block(char* __p, size_t __bytes) throw ()
115 {
116 // Round up to power of 2 and figure out which bin to use.
117 const size_t __which = _M_binmap[__bytes];
118 _Bin_record& __bin = _M_bin[__which];
119
120 char* __c = __p - _M_get_align();
121 _Block_record* __block = reinterpret_cast<_Block_record*>(__c);
122
123 // Single threaded application - return to global pool.
124 __block->_M_next = __bin._M_first[0];
125 __bin._M_first[0] = __block;
126 }
127
128 char*
129 __pool<false>::_M_reserve_block(size_t __bytes, const size_t __thread_id)
130 {
131 // Round up to power of 2 and figure out which bin to use.
132 const size_t __which = _M_binmap[__bytes];
133 _Bin_record& __bin = _M_bin[__which];
134 const _Tune& __options = _M_get_options();
135 const size_t __bin_size = (__options._M_min_bin << __which)
136 + __options._M_align;
137 size_t __block_count = __options._M_chunk_size - sizeof(_Block_address);
138 __block_count /= __bin_size;
139
140 // Get a new block dynamically, set it up for use.
141 void* __v = ::operator new(__options._M_chunk_size);
142 _Block_address* __address = static_cast<_Block_address*>(__v);
143 __address->_M_initial = __v;
144 __address->_M_next = __bin._M_address;
145 __bin._M_address = __address;
146
147 char* __c = static_cast<char*>(__v) + sizeof(_Block_address);
148 _Block_record* __block = reinterpret_cast<_Block_record*>(__c);
149 __bin._M_first[__thread_id] = __block;
150 while (--__block_count > 0)
151 {
152 __c += __bin_size;
153 __block->_M_next = reinterpret_cast<_Block_record*>(__c);
154 __block = __block->_M_next;
155 }
156 __block->_M_next = 0;
157
158 __block = __bin._M_first[__thread_id];
159 __bin._M_first[__thread_id] = __block->_M_next;
160
161 // NB: For alignment reasons, we can't use the first _M_align
162 // bytes, even when sizeof(_Block_record) < _M_align.
163 return reinterpret_cast<char*>(__block) + __options._M_align;
164 }
165
166 void
167 __pool<false>::_M_initialize()
168 {
169 // _M_force_new must not change after the first allocate(), which
170 // in turn calls this method, so if it's false, it's false forever
171 // and we don't need to return here ever again.
172 if (_M_options._M_force_new)
173 {
174 _M_init = true;
175 return;
176 }
177
178 // Create the bins.
179 // Calculate the number of bins required based on _M_max_bytes.
180 // _M_bin_size is statically-initialized to one.
181 size_t __bin_size = _M_options._M_min_bin;
182 while (_M_options._M_max_bytes > __bin_size)
183 {
184 __bin_size <<= 1;
185 ++_M_bin_size;
186 }
187
188 // Setup the bin map for quick lookup of the relevant bin.
189 const size_t __j = (_M_options._M_max_bytes + 1) * sizeof(_Binmap_type);
190 _M_binmap = static_cast<_Binmap_type*>(::operator new(__j));
191 _Binmap_type* __bp = _M_binmap;
192 _Binmap_type __bin_max = _M_options._M_min_bin;
193 _Binmap_type __bint = 0;
194 for (_Binmap_type __ct = 0; __ct <= _M_options._M_max_bytes; ++__ct)
195 {
196 if (__ct > __bin_max)
197 {
198 __bin_max <<= 1;
199 ++__bint;
200 }
201 *__bp++ = __bint;
202 }
203
204 // Initialize _M_bin and its members.
205 void* __v = ::operator new(sizeof(_Bin_record) * _M_bin_size);
206 _M_bin = static_cast<_Bin_record*>(__v);
207 for (size_t __n = 0; __n < _M_bin_size; ++__n)
208 {
209 _Bin_record& __bin = _M_bin[__n];
210 __v = ::operator new(sizeof(_Block_record*));
211 __bin._M_first = static_cast<_Block_record**>(__v);
212 __bin._M_first[0] = 0;
213 __bin._M_address = 0;
214 }
215 _M_init = true;
216 }
217
218
219 #ifdef __GTHREADS
220 void
221 __pool<true>::_M_destroy() throw()
222 {
223 if (_M_init && !_M_options._M_force_new)
224 {
225 if (__gthread_active_p())
226 {
227 for (size_t __n = 0; __n < _M_bin_size; ++__n)
228 {
229 _Bin_record& __bin = _M_bin[__n];
230 while (__bin._M_address)
231 {
232 _Block_address* __tmp = __bin._M_address->_M_next;
233 ::operator delete(__bin._M_address->_M_initial);
234 __bin._M_address = __tmp;
235 }
236 ::operator delete(__bin._M_first);
237 ::operator delete(__bin._M_free);
238 ::operator delete(__bin._M_used);
239 ::operator delete(__bin._M_mutex);
240 }
241 }
242 else
243 {
244 for (size_t __n = 0; __n < _M_bin_size; ++__n)
245 {
246 _Bin_record& __bin = _M_bin[__n];
247 while (__bin._M_address)
248 {
249 _Block_address* __tmp = __bin._M_address->_M_next;
250 ::operator delete(__bin._M_address->_M_initial);
251 __bin._M_address = __tmp;
252 }
253 ::operator delete(__bin._M_first);
254 }
255 }
256 ::operator delete(_M_bin);
257 ::operator delete(_M_binmap);
258 }
259 }
260
261 void
262 __pool<true>::_M_reclaim_block(char* __p, size_t __bytes) throw ()
263 {
264 // Round up to power of 2 and figure out which bin to use.
265 const size_t __which = _M_binmap[__bytes];
266 const _Bin_record& __bin = _M_bin[__which];
267
268 // Know __p not null, assume valid block.
269 char* __c = __p - _M_get_align();
270 _Block_record* __block = reinterpret_cast<_Block_record*>(__c);
271 if (__gthread_active_p())
272 {
273 // Calculate the number of records to remove from our freelist:
274 // in order to avoid too much contention we wait until the
275 // number of records is "high enough".
276 const size_t __thread_id = _M_get_thread_id();
277 const _Tune& __options = _M_get_options();
278 const size_t __limit = (100 * (_M_bin_size - __which)
279 * __options._M_freelist_headroom);
280
281 size_t __remove = __bin._M_free[__thread_id];
282 __remove *= __options._M_freelist_headroom;
283
284 // NB: We assume that reads of _Atomic_words are atomic.
285 const size_t __max_threads = __options._M_max_threads + 1;
286 _Atomic_word* const __reclaimed_base =
287 reinterpret_cast<_Atomic_word*>(__bin._M_used + __max_threads);
288 const _Atomic_word __reclaimed = __reclaimed_base[__thread_id];
289 const size_t __net_used = __bin._M_used[__thread_id] - __reclaimed;
290
291 // NB: For performance sake we don't resync every time, in order
292 // to spare atomic ops. Note that if __reclaimed increased by,
293 // say, 1024, since the last sync, it means that the other
294 // threads executed the atomic in the else below at least the
295 // same number of times (at least, because _M_reserve_block may
296 // have decreased the counter), therefore one more cannot hurt.
297 if (__reclaimed > 1024)
298 {
299 __bin._M_used[__thread_id] -= __reclaimed;
300 __atomic_add(&__reclaimed_base[__thread_id], -__reclaimed);
301 }
302
303 if (__remove >= __net_used)
304 __remove -= __net_used;
305 else
306 __remove = 0;
307 if (__remove > __limit && __remove > __bin._M_free[__thread_id])
308 {
309 _Block_record* __first = __bin._M_first[__thread_id];
310 _Block_record* __tmp = __first;
311 __remove /= __options._M_freelist_headroom;
312 const size_t __removed = __remove;
313 while (--__remove > 0)
314 __tmp = __tmp->_M_next;
315 __bin._M_first[__thread_id] = __tmp->_M_next;
316 __bin._M_free[__thread_id] -= __removed;
317
318 __gthread_mutex_lock(__bin._M_mutex);
319 __tmp->_M_next = __bin._M_first[0];
320 __bin._M_first[0] = __first;
321 __bin._M_free[0] += __removed;
322 __gthread_mutex_unlock(__bin._M_mutex);
323 }
324
325 // Return this block to our list and update counters and
326 // owner id as needed.
327 if (__block->_M_thread_id == __thread_id)
328 --__bin._M_used[__thread_id];
329 else
330 __atomic_add(&__reclaimed_base[__block->_M_thread_id], 1);
331
332 __block->_M_next = __bin._M_first[__thread_id];
333 __bin._M_first[__thread_id] = __block;
334
335 ++__bin._M_free[__thread_id];
336 }
337 else
338 {
339 // Not using threads, so single threaded application - return
340 // to global pool.
341 __block->_M_next = __bin._M_first[0];
342 __bin._M_first[0] = __block;
343 }
344 }
345
346 char*
347 __pool<true>::_M_reserve_block(size_t __bytes, const size_t __thread_id)
348 {
349 // Round up to power of 2 and figure out which bin to use.
350 const size_t __which = _M_binmap[__bytes];
351 const _Tune& __options = _M_get_options();
352 const size_t __bin_size = ((__options._M_min_bin << __which)
353 + __options._M_align);
354 size_t __block_count = __options._M_chunk_size - sizeof(_Block_address);
355 __block_count /= __bin_size;
356
357 // Are we using threads?
358 // - Yes, check if there are free blocks on the global
359 // list. If so, grab up to __block_count blocks in one
360 // lock and change ownership. If the global list is
361 // empty, we allocate a new chunk and add those blocks
362 // directly to our own freelist (with us as owner).
363 // - No, all operations are made directly to global pool 0
364 // no need to lock or change ownership but check for free
365 // blocks on global list (and if not add new ones) and
366 // get the first one.
367 _Bin_record& __bin = _M_bin[__which];
368 _Block_record* __block = 0;
369 if (__gthread_active_p())
370 {
371 // Resync the _M_used counters.
372 const size_t __max_threads = __options._M_max_threads + 1;
373 _Atomic_word* const __reclaimed_base =
374 reinterpret_cast<_Atomic_word*>(__bin._M_used + __max_threads);
375 const _Atomic_word __reclaimed = __reclaimed_base[__thread_id];
376 __bin._M_used[__thread_id] -= __reclaimed;
377 __atomic_add(&__reclaimed_base[__thread_id], -__reclaimed);
378
379 __gthread_mutex_lock(__bin._M_mutex);
380 if (__bin._M_first[0] == 0)
381 {
382 void* __v = ::operator new(__options._M_chunk_size);
383 _Block_address* __address = static_cast<_Block_address*>(__v);
384 __address->_M_initial = __v;
385 __address->_M_next = __bin._M_address;
386 __bin._M_address = __address;
387 __gthread_mutex_unlock(__bin._M_mutex);
388
389 // No need to hold the lock when we are adding a whole
390 // chunk to our own list.
391 char* __c = static_cast<char*>(__v) + sizeof(_Block_address);
392 __block = reinterpret_cast<_Block_record*>(__c);
393 __bin._M_free[__thread_id] = __block_count;
394 __bin._M_first[__thread_id] = __block;
395 while (--__block_count > 0)
396 {
397 __c += __bin_size;
398 __block->_M_next = reinterpret_cast<_Block_record*>(__c);
399 __block = __block->_M_next;
400 }
401 __block->_M_next = 0;
402 }
403 else
404 {
405 // Is the number of required blocks greater than or equal
406 // to the number that can be provided by the global free
407 // list?
408 __bin._M_first[__thread_id] = __bin._M_first[0];
409 if (__block_count >= __bin._M_free[0])
410 {
411 __bin._M_free[__thread_id] = __bin._M_free[0];
412 __bin._M_free[0] = 0;
413 __bin._M_first[0] = 0;
414 }
415 else
416 {
417 __bin._M_free[__thread_id] = __block_count;
418 __bin._M_free[0] -= __block_count;
419 __block = __bin._M_first[0];
420 while (--__block_count > 0)
421 __block = __block->_M_next;
422 __bin._M_first[0] = __block->_M_next;
423 __block->_M_next = 0;
424 }
425 __gthread_mutex_unlock(__bin._M_mutex);
426 }
427 }
428 else
429 {
430 void* __v = ::operator new(__options._M_chunk_size);
431 _Block_address* __address = static_cast<_Block_address*>(__v);
432 __address->_M_initial = __v;
433 __address->_M_next = __bin._M_address;
434 __bin._M_address = __address;
435
436 char* __c = static_cast<char*>(__v) + sizeof(_Block_address);
437 __block = reinterpret_cast<_Block_record*>(__c);
438 __bin._M_first[0] = __block;
439 while (--__block_count > 0)
440 {
441 __c += __bin_size;
442 __block->_M_next = reinterpret_cast<_Block_record*>(__c);
443 __block = __block->_M_next;
444 }
445 __block->_M_next = 0;
446 }
447
448 __block = __bin._M_first[__thread_id];
449 __bin._M_first[__thread_id] = __block->_M_next;
450
451 if (__gthread_active_p())
452 {
453 __block->_M_thread_id = __thread_id;
454 --__bin._M_free[__thread_id];
455 ++__bin._M_used[__thread_id];
456 }
457
458 // NB: For alignment reasons, we can't use the first _M_align
459 // bytes, even when sizeof(_Block_record) < _M_align.
460 return reinterpret_cast<char*>(__block) + __options._M_align;
461 }
462
463 void
464 __pool<true>::_M_initialize()
465 {
466 // _M_force_new must not change after the first allocate(),
467 // which in turn calls this method, so if it's false, it's false
468 // forever and we don't need to return here ever again.
469 if (_M_options._M_force_new)
470 {
471 _M_init = true;
472 return;
473 }
474
475 // Create the bins.
476 // Calculate the number of bins required based on _M_max_bytes.
477 // _M_bin_size is statically-initialized to one.
478 size_t __bin_size = _M_options._M_min_bin;
479 while (_M_options._M_max_bytes > __bin_size)
480 {
481 __bin_size <<= 1;
482 ++_M_bin_size;
483 }
484
485 // Setup the bin map for quick lookup of the relevant bin.
486 const size_t __j = (_M_options._M_max_bytes + 1) * sizeof(_Binmap_type);
487 _M_binmap = static_cast<_Binmap_type*>(::operator new(__j));
488 _Binmap_type* __bp = _M_binmap;
489 _Binmap_type __bin_max = _M_options._M_min_bin;
490 _Binmap_type __bint = 0;
491 for (_Binmap_type __ct = 0; __ct <= _M_options._M_max_bytes; ++__ct)
492 {
493 if (__ct > __bin_max)
494 {
495 __bin_max <<= 1;
496 ++__bint;
497 }
498 *__bp++ = __bint;
499 }
500
501 // Initialize _M_bin and its members.
502 void* __v = ::operator new(sizeof(_Bin_record) * _M_bin_size);
503 _M_bin = static_cast<_Bin_record*>(__v);
504
505 // If __gthread_active_p() create and initialize the list of
506 // free thread ids. Single threaded applications use thread id 0
507 // directly and have no need for this.
508 if (__gthread_active_p())
509 {
510 __freelist& freelist = get_freelist();
511 {
512 __gnu_cxx::__scoped_lock sentry(get_freelist_mutex());
513
514 if (!freelist._M_thread_freelist_array
515 || freelist._M_max_threads < _M_options._M_max_threads)
516 {
517 const size_t __k = sizeof(_Thread_record)
518 * _M_options._M_max_threads;
519 __v = ::operator new(__k);
520 _M_thread_freelist = static_cast<_Thread_record*>(__v);
521
522 // NOTE! The first assignable thread id is 1 since the
523 // global pool uses id 0
524 size_t __i;
525 for (__i = 1; __i < _M_options._M_max_threads; ++__i)
526 {
527 _Thread_record& __tr = _M_thread_freelist[__i - 1];
528 __tr._M_next = &_M_thread_freelist[__i];
529 __tr._M_id = __i;
530 }
531
532 // Set last record.
533 _M_thread_freelist[__i - 1]._M_next = 0;
534 _M_thread_freelist[__i - 1]._M_id = __i;
535
536 if (!freelist._M_thread_freelist_array)
537 {
538 // Initialize per thread key to hold pointer to
539 // _M_thread_freelist.
540 __gthread_key_create(&freelist._M_key,
541 ::_M_destroy_thread_key);
542 freelist._M_thread_freelist = _M_thread_freelist;
543 }
544 else
545 {
546 _Thread_record* _M_old_freelist
547 = freelist._M_thread_freelist;
548 _Thread_record* _M_old_array
549 = freelist._M_thread_freelist_array;
550 freelist._M_thread_freelist
551 = &_M_thread_freelist[_M_old_freelist - _M_old_array];
552 while (_M_old_freelist)
553 {
554 size_t next_id;
555 if (_M_old_freelist->_M_next)
556 next_id = _M_old_freelist->_M_next - _M_old_array;
557 else
558 next_id = freelist._M_max_threads;
559 _M_thread_freelist[_M_old_freelist->_M_id - 1]._M_next
560 = &_M_thread_freelist[next_id];
561 _M_old_freelist = _M_old_freelist->_M_next;
562 }
563 ::operator delete(static_cast<void*>(_M_old_array));
564 }
565 freelist._M_thread_freelist_array = _M_thread_freelist;
566 freelist._M_max_threads = _M_options._M_max_threads;
567 }
568 }
569
570 const size_t __max_threads = _M_options._M_max_threads + 1;
571 for (size_t __n = 0; __n < _M_bin_size; ++__n)
572 {
573 _Bin_record& __bin = _M_bin[__n];
574 __v = ::operator new(sizeof(_Block_record*) * __max_threads);
575 std::memset(__v, 0, sizeof(_Block_record*) * __max_threads);
576 __bin._M_first = static_cast<_Block_record**>(__v);
577
578 __bin._M_address = 0;
579
580 __v = ::operator new(sizeof(size_t) * __max_threads);
581 std::memset(__v, 0, sizeof(size_t) * __max_threads);
582
583 __bin._M_free = static_cast<size_t*>(__v);
584
585 __v = ::operator new(sizeof(size_t) * __max_threads
586 + sizeof(_Atomic_word) * __max_threads);
587 std::memset(__v, 0, (sizeof(size_t) * __max_threads
588 + sizeof(_Atomic_word) * __max_threads));
589 __bin._M_used = static_cast<size_t*>(__v);
590
591 __v = ::operator new(sizeof(__gthread_mutex_t));
592 __bin._M_mutex = static_cast<__gthread_mutex_t*>(__v);
593
594 #ifdef __GTHREAD_MUTEX_INIT
595 {
596 // Do not copy a POSIX/gthr mutex once in use.
597 __gthread_mutex_t __tmp = __GTHREAD_MUTEX_INIT;
598 *__bin._M_mutex = __tmp;
599 }
600 #else
601 { __GTHREAD_MUTEX_INIT_FUNCTION(__bin._M_mutex); }
602 #endif
603 }
604 }
605 else
606 {
607 for (size_t __n = 0; __n < _M_bin_size; ++__n)
608 {
609 _Bin_record& __bin = _M_bin[__n];
610 __v = ::operator new(sizeof(_Block_record*));
611 __bin._M_first = static_cast<_Block_record**>(__v);
612 __bin._M_first[0] = 0;
613 __bin._M_address = 0;
614 }
615 }
616 _M_init = true;
617 }
618
619 size_t
620 __pool<true>::_M_get_thread_id()
621 {
622 // If we have thread support and it's active we check the thread
623 // key value and return its id or if it's not set we take the
624 // first record from _M_thread_freelist and sets the key and
625 // returns its id.
626 if (__gthread_active_p())
627 {
628 __freelist& freelist = get_freelist();
629 void* v = __gthread_getspecific(freelist._M_key);
630 size_t _M_id = (size_t)v;
631 if (_M_id == 0)
632 {
633 {
634 __gnu_cxx::__scoped_lock sentry(get_freelist_mutex());
635 if (freelist._M_thread_freelist)
636 {
637 _M_id = freelist._M_thread_freelist->_M_id;
638 freelist._M_thread_freelist
639 = freelist._M_thread_freelist->_M_next;
640 }
641 }
642
643 __gthread_setspecific(freelist._M_key, (void*)_M_id);
644 }
645 return _M_id >= _M_options._M_max_threads ? 0 : _M_id;
646 }
647
648 // Otherwise (no thread support or inactive) all requests are
649 // served from the global pool 0.
650 return 0;
651 }
652
653 // XXX GLIBCXX_ABI Deprecated
654 void
655 __pool<true>::_M_destroy_thread_key(void*) throw () { }
656
657 // XXX GLIBCXX_ABI Deprecated
658 void
659 __pool<true>::_M_initialize(__destroy_handler)
660 {
661 // _M_force_new must not change after the first allocate(),
662 // which in turn calls this method, so if it's false, it's false
663 // forever and we don't need to return here ever again.
664 if (_M_options._M_force_new)
665 {
666 _M_init = true;
667 return;
668 }
669
670 // Create the bins.
671 // Calculate the number of bins required based on _M_max_bytes.
672 // _M_bin_size is statically-initialized to one.
673 size_t __bin_size = _M_options._M_min_bin;
674 while (_M_options._M_max_bytes > __bin_size)
675 {
676 __bin_size <<= 1;
677 ++_M_bin_size;
678 }
679
680 // Setup the bin map for quick lookup of the relevant bin.
681 const size_t __j = (_M_options._M_max_bytes + 1) * sizeof(_Binmap_type);
682 _M_binmap = static_cast<_Binmap_type*>(::operator new(__j));
683 _Binmap_type* __bp = _M_binmap;
684 _Binmap_type __bin_max = _M_options._M_min_bin;
685 _Binmap_type __bint = 0;
686 for (_Binmap_type __ct = 0; __ct <= _M_options._M_max_bytes; ++__ct)
687 {
688 if (__ct > __bin_max)
689 {
690 __bin_max <<= 1;
691 ++__bint;
692 }
693 *__bp++ = __bint;
694 }
695
696 // Initialize _M_bin and its members.
697 void* __v = ::operator new(sizeof(_Bin_record) * _M_bin_size);
698 _M_bin = static_cast<_Bin_record*>(__v);
699
700 // If __gthread_active_p() create and initialize the list of
701 // free thread ids. Single threaded applications use thread id 0
702 // directly and have no need for this.
703 if (__gthread_active_p())
704 {
705 __freelist& freelist = get_freelist();
706 {
707 __gnu_cxx::__scoped_lock sentry(get_freelist_mutex());
708
709 if (!freelist._M_thread_freelist_array
710 || freelist._M_max_threads < _M_options._M_max_threads)
711 {
712 const size_t __k = sizeof(_Thread_record)
713 * _M_options._M_max_threads;
714 __v = ::operator new(__k);
715 _M_thread_freelist = static_cast<_Thread_record*>(__v);
716
717 // NOTE! The first assignable thread id is 1 since the
718 // global pool uses id 0
719 size_t __i;
720 for (__i = 1; __i < _M_options._M_max_threads; ++__i)
721 {
722 _Thread_record& __tr = _M_thread_freelist[__i - 1];
723 __tr._M_next = &_M_thread_freelist[__i];
724 __tr._M_id = __i;
725 }
726
727 // Set last record.
728 _M_thread_freelist[__i - 1]._M_next = 0;
729 _M_thread_freelist[__i - 1]._M_id = __i;
730
731 if (!freelist._M_thread_freelist_array)
732 {
733 // Initialize per thread key to hold pointer to
734 // _M_thread_freelist.
735 __gthread_key_create(&freelist._M_key,
736 ::_M_destroy_thread_key);
737 freelist._M_thread_freelist = _M_thread_freelist;
738 }
739 else
740 {
741 _Thread_record* _M_old_freelist
742 = freelist._M_thread_freelist;
743 _Thread_record* _M_old_array
744 = freelist._M_thread_freelist_array;
745 freelist._M_thread_freelist
746 = &_M_thread_freelist[_M_old_freelist - _M_old_array];
747 while (_M_old_freelist)
748 {
749 size_t next_id;
750 if (_M_old_freelist->_M_next)
751 next_id = _M_old_freelist->_M_next - _M_old_array;
752 else
753 next_id = freelist._M_max_threads;
754 _M_thread_freelist[_M_old_freelist->_M_id - 1]._M_next
755 = &_M_thread_freelist[next_id];
756 _M_old_freelist = _M_old_freelist->_M_next;
757 }
758 ::operator delete(static_cast<void*>(_M_old_array));
759 }
760 freelist._M_thread_freelist_array = _M_thread_freelist;
761 freelist._M_max_threads = _M_options._M_max_threads;
762 }
763 }
764
765 const size_t __max_threads = _M_options._M_max_threads + 1;
766 for (size_t __n = 0; __n < _M_bin_size; ++__n)
767 {
768 _Bin_record& __bin = _M_bin[__n];
769 __v = ::operator new(sizeof(_Block_record*) * __max_threads);
770 std::memset(__v, 0, sizeof(_Block_record*) * __max_threads);
771 __bin._M_first = static_cast<_Block_record**>(__v);
772
773 __bin._M_address = 0;
774
775 __v = ::operator new(sizeof(size_t) * __max_threads);
776 std::memset(__v, 0, sizeof(size_t) * __max_threads);
777 __bin._M_free = static_cast<size_t*>(__v);
778
779 __v = ::operator new(sizeof(size_t) * __max_threads +
780 sizeof(_Atomic_word) * __max_threads);
781 std::memset(__v, 0, (sizeof(size_t) * __max_threads
782 + sizeof(_Atomic_word) * __max_threads));
783 __bin._M_used = static_cast<size_t*>(__v);
784
785 __v = ::operator new(sizeof(__gthread_mutex_t));
786 __bin._M_mutex = static_cast<__gthread_mutex_t*>(__v);
787
788 #ifdef __GTHREAD_MUTEX_INIT
789 {
790 // Do not copy a POSIX/gthr mutex once in use.
791 __gthread_mutex_t __tmp = __GTHREAD_MUTEX_INIT;
792 *__bin._M_mutex = __tmp;
793 }
794 #else
795 { __GTHREAD_MUTEX_INIT_FUNCTION(__bin._M_mutex); }
796 #endif
797 }
798 }
799 else
800 {
801 for (size_t __n = 0; __n < _M_bin_size; ++__n)
802 {
803 _Bin_record& __bin = _M_bin[__n];
804 __v = ::operator new(sizeof(_Block_record*));
805 __bin._M_first = static_cast<_Block_record**>(__v);
806 __bin._M_first[0] = 0;
807 __bin._M_address = 0;
808 }
809 }
810 _M_init = true;
811 }
812 #endif
813
814 // Instantiations.
815 template class __mt_alloc<char>;
816 template class __mt_alloc<wchar_t>;
817
818 _GLIBCXX_END_NAMESPACE_VERSION
819 } // namespace