1 // MT-optimized allocator -*- C++ -*-
3 // Copyright (C) 2003, 2004 Free Software Foundation, Inc.
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 2, or (at your option)
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.
16 // You should have received a copy of the GNU General Public License along
17 // with this library; see the file COPYING. If not, write to the Free
18 // Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
21 // As a special exception, you may use this file as part of a free software
22 // library without restriction. Specifically, if other files instantiate
23 // templates or use macros or inline functions from this file, or you compile
24 // this file and link it with other files to produce an executable, this
25 // file does not by itself cause the resulting executable to be covered by
26 // the GNU General Public License. This exception does not however
27 // invalidate any other reasons why the executable file might be covered by
28 // the GNU General Public License.
30 /** @file ext/mt_allocator.h
31 * This file is a GNU extension to the Standard C++ Library.
32 * You should only include this header if you are using GCC 3 or later.
35 #ifndef _MT_ALLOCATOR_H
36 #define _MT_ALLOCATOR_H 1
40 #include <bits/functexcept.h>
41 #include <bits/gthr.h>
42 #include <bits/atomicity.h>
47 * This is a fixed size (power of 2) allocator which - when
48 * compiled with thread support - will maintain one freelist per
49 * size per thread plus a "global" one. Steps are taken to limit
50 * the per thread freelist sizes (by returning excess back to
54 * http://gcc.gnu.org/onlinedocs/libstdc++/ext/mt_allocator.html
56 template<typename _Tp>
60 typedef size_t size_type;
61 typedef ptrdiff_t difference_type;
63 typedef const _Tp* const_pointer;
64 typedef _Tp& reference;
65 typedef const _Tp& const_reference;
66 typedef _Tp value_type;
68 template<typename _Tp1>
70 { typedef __mt_alloc<_Tp1> other; };
77 __mt_alloc(const __mt_alloc&) throw()
82 template<typename _Tp1>
83 __mt_alloc(const __mt_alloc<_Tp1>& obj) throw()
88 ~__mt_alloc() throw() { }
91 address(reference __x) const { return &__x; }
94 address(const_reference __x) const { return &__x; }
97 max_size() const throw()
98 { return size_t(-1) / sizeof(_Tp); }
100 // _GLIBCXX_RESOLVE_LIB_DEFECTS
101 // 402. wrong new expression in [some_] allocator::construct
103 construct(pointer __p, const _Tp& __val)
104 { ::new(__p) _Tp(__val); }
107 destroy(pointer __p) { __p->~_Tp(); }
110 allocate(size_t __n, const void* = 0);
113 deallocate(pointer __p, size_type __n);
115 // Variables used to configure the behavior of the allocator,
116 // assigned and explained in detail below.
119 // Allocation requests (after round-up to power of 2) below
120 // this value will be handled by the allocator. A raw new/
121 // call will be used for requests larger than this value.
124 // In order to avoid fragmenting and minimize the number of
125 // new() calls we always request new memory using this
126 // value. Based on previous discussions on the libstdc++
127 // mailing list we have choosen the value below.
128 // See http://gcc.gnu.org/ml/libstdc++/2001-07/msg00077.html
129 size_t _M_chunk_size;
131 // The maximum number of supported threads. Our Linux 2.4.18
132 // reports 4070 in /proc/sys/kernel/threads-max
133 size_t _M_max_threads;
135 // Each time a deallocation occurs in a threaded application
136 // we make sure that there are no more than
137 // _M_freelist_headroom % of used memory on the freelist. If
138 // the number of additional records is more than
139 // _M_freelist_headroom % of the freelist, we move these
140 // records back to the global pool.
141 size_t _M_freelist_headroom;
143 // Set to true forces all allocations to use new().
147 : _M_max_bytes(128), _M_chunk_size(4096 - 4 * sizeof(void*)),
149 _M_max_threads(4096),
153 _M_freelist_headroom(10),
154 _M_force_new(getenv("GLIBCXX_FORCE_NEW") ? true : false)
157 explicit tune(size_t __maxb, size_t __chunk, size_t __maxthreads,
158 size_t __headroom, bool __force)
159 : _M_max_bytes(__maxb), _M_chunk_size(__chunk),
160 _M_max_threads(__maxthreads), _M_freelist_headroom(__headroom),
161 _M_force_new(__force)
166 // We need to create the initial lists and set up some variables
167 // before we can answer to the first request for memory.
169 static __gthread_once_t _S_once;
176 // Configuration options.
177 static tune _S_options;
180 _S_get_options() { return _S_options; }
183 _S_set_options(tune __t)
189 // Using short int as type for the binmap implies we are never
190 // caching blocks larger than 65535 with this allocator
191 typedef unsigned short int binmap_type;
192 static binmap_type* _S_binmap;
194 // Each requesting thread is assigned an id ranging from 1 to
195 // _S_max_threads. Thread id 0 is used as a global memory pool.
196 // In order to get constant performance on the thread assignment
197 // routine, we keep a list of free ids. When a thread first
198 // requests memory we remove the first record in this list and
199 // stores the address in a __gthread_key. When initializing the
200 // __gthread_key we specify a destructor. When this destructor
201 // (i.e. the thread dies) is called, we return the thread id to
202 // the front of this list.
206 // Points to next free thread id record. NULL if last record in list.
207 thread_record* volatile next;
209 // Thread id ranging from 1 to _S_max_threads.
213 static thread_record* volatile _S_thread_freelist_first;
214 static __gthread_mutex_t _S_thread_freelist_mutex;
215 static __gthread_key_t _S_thread_key;
218 _S_destroy_thread_key(void* freelist_pos);
226 // Points to the next block_record for its thread_id.
227 block_record* volatile next;
229 // The thread id of the thread which has requested this block.
237 // An "array" of pointers to the first free block for each
238 // thread id. Memory to this "array" is allocated in _S_initialize()
239 // for _S_max_threads + global pool 0.
240 block_record** volatile first;
242 // An "array" of counters used to keep track of the amount of
243 // blocks that are on the freelist/used for each thread id.
244 // Memory to these "arrays" is allocated in _S_initialize() for
245 // _S_max_threads + global pool 0.
246 size_t* volatile free;
247 size_t* volatile used;
249 // Each bin has its own mutex which is used to ensure data
250 // integrity while changing "ownership" on a block. The mutex
251 // is initialized in _S_initialize().
253 __gthread_mutex_t* mutex;
257 // An "array" of bin_records each of which represents a specific
258 // power of 2 size. Memory to this "array" is allocated in
260 static bin_record* volatile _S_bin;
262 // Actual value calculated in _S_initialize().
263 static size_t _S_bin_size;
266 template<typename _Tp>
267 typename __mt_alloc<_Tp>::pointer
269 allocate(size_t __n, const void*)
271 // Although the test in __gthread_once() would suffice, we wrap
272 // test of the once condition in our own unlocked check. This
273 // saves one function call to pthread_once() (which itself only
274 // tests for the once value unlocked anyway and immediately
279 if (__gthread_active_p())
280 __gthread_once(&_S_once, _S_initialize);
286 // Requests larger than _M_max_bytes are handled by new/delete
288 const size_t __bytes = __n * sizeof(_Tp);
289 if (__bytes > _S_options._M_max_bytes || _S_options._M_force_new)
291 void* __ret = ::operator new(__bytes);
292 return static_cast<_Tp*>(__ret);
295 // Round up to power of 2 and figure out which bin to use.
296 size_t bin = _S_binmap[__bytes];
299 size_t thread_id = _S_get_thread_id();
301 size_t thread_id = 0;
304 // Find out if we have blocks on our freelist. If so, go ahead
305 // and use them directly without having to lock anything.
306 block_record* block = NULL;
307 if (_S_bin[bin].first[thread_id] == NULL)
309 // Are we using threads?
310 // - Yes, check if there are free blocks on the global
311 // list. If so, grab up to block_count blocks in one
312 // lock and change ownership. If the global list is
313 // empty, we allocate a new chunk and add those blocks
314 // directly to our own freelist (with us as owner).
315 // - No, all operations are made directly to global pool 0
316 // no need to lock or change ownership but check for free
317 // blocks on global list (and if not add new ones) and
318 // get the first one.
320 if (__gthread_active_p())
322 size_t bin_t = 1 << bin;
324 _S_options._M_chunk_size /(bin_t + sizeof(block_record));
326 __gthread_mutex_lock(_S_bin[bin].mutex);
328 if (_S_bin[bin].first[0] == NULL)
330 // No need to hold the lock when we are adding a
331 // whole chunk to our own list.
332 __gthread_mutex_unlock(_S_bin[bin].mutex);
334 _S_bin[bin].first[thread_id] =
335 static_cast<block_record*>(::operator new(_S_options._M_chunk_size));
337 if (!_S_bin[bin].first[thread_id])
338 std::__throw_bad_alloc();
340 _S_bin[bin].free[thread_id] = block_count;
343 block = _S_bin[bin].first[thread_id];
345 while (block_count > 0)
347 block->next = (block_record*)((char*)block +
348 (bin_t + sizeof(block_record)));
349 block->thread_id = thread_id;
355 block->thread_id = thread_id;
359 size_t global_count = 0;
361 while (_S_bin[bin].first[0] != NULL
362 && global_count < block_count)
364 tmp = _S_bin[bin].first[0]->next;
365 block = _S_bin[bin].first[0];
367 if (_S_bin[bin].first[thread_id] == NULL)
369 _S_bin[bin].first[thread_id] = block;
374 block->next = _S_bin[bin].first[thread_id];
375 _S_bin[bin].first[thread_id] = block;
378 block->thread_id = thread_id;
379 _S_bin[bin].free[thread_id]++;
380 _S_bin[bin].first[0] = tmp;
383 __gthread_mutex_unlock(_S_bin[bin].mutex);
386 // Return the first newly added block in our list and
387 // update the counters
388 block = _S_bin[bin].first[thread_id];
389 _S_bin[bin].first[thread_id] =
390 _S_bin[bin].first[thread_id]->next;
391 _S_bin[bin].free[thread_id]--;
392 _S_bin[bin].used[thread_id]++;
397 _S_bin[bin].first[0] =
398 static_cast<block_record*>(::operator new(_S_options._M_chunk_size));
400 size_t bin_t = 1 << bin;
402 _S_options._M_chunk_size / (bin_t + sizeof(block_record));
405 block = _S_bin[bin].first[0];
406 while (block_count > 0)
408 block->next = (block_record*)((char*)block +
409 (bin_t + sizeof(block_record)));
414 block = _S_bin[bin].first[0];
417 _S_bin[bin].first[0] = _S_bin[bin].first[0]->next;
422 // "Default" operation - we have blocks on our own
423 // freelist grab the first record and update the counters.
424 block = _S_bin[bin].first[thread_id];
426 _S_bin[bin].first[thread_id] = _S_bin[bin].first[thread_id]->next;
429 if (__gthread_active_p())
431 _S_bin[bin].free[thread_id]--;
432 _S_bin[bin].used[thread_id]++;
436 return static_cast<_Tp*>(static_cast<void*>((char*)block +
437 sizeof(block_record)));
440 template<typename _Tp>
443 deallocate(pointer __p, size_type __n)
445 // Requests larger than _M_max_bytes are handled by operators
446 // new/delete directly.
447 if (__n * sizeof(_Tp) > _S_options._M_max_bytes
448 || _S_options._M_force_new)
450 ::operator delete(__p);
454 // Round up to power of 2 and figure out which bin to use.
455 size_t bin = _S_binmap[__n * sizeof(_Tp)];
458 size_t thread_id = _S_get_thread_id();
460 size_t thread_id = 0;
463 block_record* block = (block_record*)((char*)__p
464 - sizeof(block_record));
467 if (__gthread_active_p())
469 // Calculate the number of records to remove from our freelist.
470 int remove = _S_bin[bin].free[thread_id] -
471 (_S_bin[bin].used[thread_id] / _S_options._M_freelist_headroom);
473 // The calculation above will almost always tell us to
474 // remove one or two records at a time, but this creates too
475 // much contention when locking and therefore we wait until
476 // the number of records is "high enough".
477 if (remove > (int)(100 * (_S_bin_size - bin)) &&
478 remove > (int)(_S_bin[bin].free[thread_id] /
479 _S_options._M_freelist_headroom))
481 __gthread_mutex_lock(_S_bin[bin].mutex);
485 tmp = _S_bin[bin].first[thread_id]->next;
486 if (_S_bin[bin].first[0] == NULL)
488 _S_bin[bin].first[0] = _S_bin[bin].first[thread_id];
489 _S_bin[bin].first[0]->next = NULL;
493 _S_bin[bin].first[thread_id]->next = _S_bin[bin].first[0];
494 _S_bin[bin].first[0] = _S_bin[bin].first[thread_id];
497 _S_bin[bin].first[thread_id] = tmp;
498 _S_bin[bin].free[thread_id]--;
501 __gthread_mutex_unlock(_S_bin[bin].mutex);
504 // Return this block to our list and update counters and
505 // owner id as needed.
506 if (_S_bin[bin].first[thread_id] == NULL)
508 _S_bin[bin].first[thread_id] = block;
513 block->next = _S_bin[bin].first[thread_id];
514 _S_bin[bin].first[thread_id] = block;
517 _S_bin[bin].free[thread_id]++;
519 if (thread_id == block->thread_id)
520 _S_bin[bin].used[thread_id]--;
523 _S_bin[bin].used[block->thread_id]--;
524 block->thread_id = thread_id;
530 // Single threaded application - return to global pool.
531 if (_S_bin[bin].first[0] == NULL)
533 _S_bin[bin].first[0] = block;
538 block->next = _S_bin[bin].first[0];
539 _S_bin[bin].first[0] = block;
544 template<typename _Tp>
549 if (_S_options._M_force_new)
552 // Calculate the number of bins required based on _M_max_bytes.
553 // _S_bin_size is statically-initialized to one.
555 while (_S_options._M_max_bytes > bin_size)
557 bin_size = bin_size << 1;
561 // Setup the bin map for quick lookup of the relevant bin.
562 const size_t n1 = (_S_options._M_max_bytes + 1) * sizeof(binmap_type);
563 _S_binmap = static_cast<binmap_type*>(::operator new(n1));
565 binmap_type* bp_t = _S_binmap;
566 binmap_type bin_max_t = 1;
567 binmap_type bin_t = 0;
568 for (binmap_type ct = 0; ct <= _S_options._M_max_bytes; ct++)
578 // If __gthread_active_p() create and initialize the list of
579 // free thread ids. Single threaded applications use thread id 0
580 // directly and have no need for this.
582 if (__gthread_active_p())
584 const size_t n2 = sizeof(thread_record) * _S_options._M_max_threads;
585 _S_thread_freelist_first = static_cast<thread_record*>(::operator new(n2));
587 // NOTE! The first assignable thread id is 1 since the
588 // global pool uses id 0
590 for (i = 1; i < _S_options._M_max_threads; i++)
592 thread_record& tr = _S_thread_freelist_first[i - 1];
593 tr.next = &_S_thread_freelist_first[i];
598 _S_thread_freelist_first[i - 1].next = NULL;
599 _S_thread_freelist_first[i - 1].id = i;
602 // Make sure this is initialized.
603 #ifndef __GTHREAD_MUTEX_INIT
604 __GTHREAD_MUTEX_INIT_FUNCTION(&_S_thread_freelist_mutex);
606 // Initialize per thread key to hold pointer to
607 // _S_thread_freelist.
608 __gthread_key_create(&_S_thread_key, _S_destroy_thread_key);
612 // Initialize _S_bin and its members.
613 _S_bin = static_cast<bin_record*>(::operator
614 new(sizeof(bin_record) * _S_bin_size));
616 // Maximum number of threads.
619 if (__gthread_active_p())
620 __n = _S_options._M_max_threads + 1;
623 for (size_t bin = 0; bin < _S_bin_size; bin++)
625 bin_record& br = _S_bin[bin];
626 br.first = static_cast<block_record**>(::operator new(sizeof(block_record*) * __n));
629 if (__gthread_active_p())
631 br.free = static_cast<size_t*>(::operator new(sizeof(size_t)
633 br.used = static_cast<size_t*>(::operator new(sizeof(size_t)
635 br.mutex = static_cast<__gthread_mutex_t*>(::operator new(sizeof(__gthread_mutex_t)));
637 #ifdef __GTHREAD_MUTEX_INIT
639 // Do not copy a POSIX/gthr mutex once in use.
640 __gthread_mutex_t __tmp = __GTHREAD_MUTEX_INIT;
644 { __GTHREAD_MUTEX_INIT_FUNCTION(br.mutex); }
649 for (size_t thread = 0; thread < __n; thread++)
651 br.first[thread] = NULL;
653 if (__gthread_active_p())
665 template<typename _Tp>
668 _S_destroy_thread_key(void* freelist_pos)
670 // Return this thread id record to front of thread_freelist.
671 __gthread_mutex_lock(&_S_thread_freelist_mutex);
672 ((thread_record*)freelist_pos)->next = _S_thread_freelist_first;
673 _S_thread_freelist_first = (thread_record*)freelist_pos;
674 __gthread_mutex_unlock(&_S_thread_freelist_mutex);
677 template<typename _Tp>
682 // If we have thread support and it's active we check the thread
683 // key value and return it's id or if it's not set we take the
684 // first record from _S_thread_freelist and sets the key and
686 if (__gthread_active_p())
688 thread_record* freelist_pos = static_cast<thread_record*>(__gthread_getspecific(_S_thread_key));
689 if (freelist_pos == NULL)
691 // Since _S_options._M_max_threads must be larger than
692 // the theoretical max number of threads of the OS the
693 // list can never be empty.
694 __gthread_mutex_lock(&_S_thread_freelist_mutex);
695 freelist_pos = _S_thread_freelist_first;
696 _S_thread_freelist_first = _S_thread_freelist_first->next;
697 __gthread_mutex_unlock(&_S_thread_freelist_mutex);
699 __gthread_setspecific(_S_thread_key,
700 static_cast<void*>(freelist_pos));
702 return freelist_pos->id;
705 // Otherwise (no thread support or inactive) all requests are
706 // served from the global pool 0.
711 template<typename _Tp>
713 operator==(const __mt_alloc<_Tp>&, const __mt_alloc<_Tp>&)
716 template<typename _Tp>
718 operator!=(const __mt_alloc<_Tp>&, const __mt_alloc<_Tp>&)
721 template<typename _Tp>
722 bool __mt_alloc<_Tp>::_S_init = false;
724 template<typename _Tp>
725 typename __mt_alloc<_Tp>::tune __mt_alloc<_Tp>::_S_options;
727 template<typename _Tp>
728 typename __mt_alloc<_Tp>::binmap_type* __mt_alloc<_Tp>::_S_binmap;
730 template<typename _Tp>
731 typename __mt_alloc<_Tp>::bin_record* volatile __mt_alloc<_Tp>::_S_bin;
733 template<typename _Tp>
734 size_t __mt_alloc<_Tp>::_S_bin_size = 1;
736 // Actual initialization in _S_initialize().
738 template<typename _Tp>
739 __gthread_once_t __mt_alloc<_Tp>::_S_once = __GTHREAD_ONCE_INIT;
741 template<typename _Tp>
742 typename __mt_alloc<_Tp>::thread_record*
743 volatile __mt_alloc<_Tp>::_S_thread_freelist_first = NULL;
745 template<typename _Tp>
746 __gthread_key_t __mt_alloc<_Tp>::_S_thread_key;
748 template<typename _Tp>
750 #ifdef __GTHREAD_MUTEX_INIT
751 __mt_alloc<_Tp>::_S_thread_freelist_mutex = __GTHREAD_MUTEX_INIT;
753 __mt_alloc<_Tp>::_S_thread_freelist_mutex;
756 } // namespace __gnu_cxx