136ac495dSmrg // MT-optimized allocator -*- C++ -*-
236ac495dSmrg
3*8feb0f0bSmrg // Copyright (C) 2003-2020 Free Software Foundation, Inc.
436ac495dSmrg //
536ac495dSmrg // This file is part of the GNU ISO C++ Library. This library is free
636ac495dSmrg // software; you can redistribute it and/or modify it under the
736ac495dSmrg // terms of the GNU General Public License as published by the
836ac495dSmrg // Free Software Foundation; either version 3, or (at your option)
936ac495dSmrg // any later version.
1036ac495dSmrg
1136ac495dSmrg // This library is distributed in the hope that it will be useful,
1236ac495dSmrg // but WITHOUT ANY WARRANTY; without even the implied warranty of
1336ac495dSmrg // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1436ac495dSmrg // GNU General Public License for more details.
1536ac495dSmrg
1636ac495dSmrg // Under Section 7 of GPL version 3, you are granted additional
1736ac495dSmrg // permissions described in the GCC Runtime Library Exception, version
1836ac495dSmrg // 3.1, as published by the Free Software Foundation.
1936ac495dSmrg
2036ac495dSmrg // You should have received a copy of the GNU General Public License and
2136ac495dSmrg // a copy of the GCC Runtime Library Exception along with this program;
2236ac495dSmrg // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
2336ac495dSmrg // <http://www.gnu.org/licenses/>.
2436ac495dSmrg
2536ac495dSmrg /** @file ext/mt_allocator.h
2636ac495dSmrg * This file is a GNU extension to the Standard C++ Library.
2736ac495dSmrg */
2836ac495dSmrg
2936ac495dSmrg #ifndef _MT_ALLOCATOR_H
3036ac495dSmrg #define _MT_ALLOCATOR_H 1
3136ac495dSmrg
3236ac495dSmrg #include <new>
3336ac495dSmrg #include <cstdlib>
3436ac495dSmrg #include <bits/functexcept.h>
3536ac495dSmrg #include <ext/atomicity.h>
3636ac495dSmrg #include <bits/move.h>
3736ac495dSmrg #if __cplusplus >= 201103L
3836ac495dSmrg #include <type_traits>
3936ac495dSmrg #endif
4036ac495dSmrg
_GLIBCXX_VISIBILITY(default)4136ac495dSmrg namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)
4236ac495dSmrg {
4336ac495dSmrg _GLIBCXX_BEGIN_NAMESPACE_VERSION
4436ac495dSmrg
4536ac495dSmrg
4636ac495dSmrg typedef void (*__destroy_handler)(void*);
4736ac495dSmrg
4836ac495dSmrg /// Base class for pool object.
4936ac495dSmrg struct __pool_base
5036ac495dSmrg {
5136ac495dSmrg // Using short int as type for the binmap implies we are never
5236ac495dSmrg // caching blocks larger than 32768 with this allocator.
5336ac495dSmrg typedef unsigned short int _Binmap_type;
54*8feb0f0bSmrg typedef std::size_t size_t;
5536ac495dSmrg
5636ac495dSmrg // Variables used to configure the behavior of the allocator,
5736ac495dSmrg // assigned and explained in detail below.
5836ac495dSmrg struct _Tune
5936ac495dSmrg {
6036ac495dSmrg // Compile time constants for the default _Tune values.
6136ac495dSmrg enum { _S_align = 8 };
6236ac495dSmrg enum { _S_max_bytes = 128 };
6336ac495dSmrg enum { _S_min_bin = 8 };
6436ac495dSmrg enum { _S_chunk_size = 4096 - 4 * sizeof(void*) };
6536ac495dSmrg enum { _S_max_threads = 4096 };
6636ac495dSmrg enum { _S_freelist_headroom = 10 };
6736ac495dSmrg
6836ac495dSmrg // Alignment needed.
6936ac495dSmrg // NB: In any case must be >= sizeof(_Block_record), that
7036ac495dSmrg // is 4 on 32 bit machines and 8 on 64 bit machines.
7136ac495dSmrg size_t _M_align;
7236ac495dSmrg
7336ac495dSmrg // Allocation requests (after round-up to power of 2) below
7436ac495dSmrg // this value will be handled by the allocator. A raw new/
7536ac495dSmrg // call will be used for requests larger than this value.
7636ac495dSmrg // NB: Must be much smaller than _M_chunk_size and in any
7736ac495dSmrg // case <= 32768.
7836ac495dSmrg size_t _M_max_bytes;
7936ac495dSmrg
8036ac495dSmrg // Size in bytes of the smallest bin.
8136ac495dSmrg // NB: Must be a power of 2 and >= _M_align (and of course
8236ac495dSmrg // much smaller than _M_max_bytes).
8336ac495dSmrg size_t _M_min_bin;
8436ac495dSmrg
8536ac495dSmrg // In order to avoid fragmenting and minimize the number of
8636ac495dSmrg // new() calls we always request new memory using this
8736ac495dSmrg // value. Based on previous discussions on the libstdc++
8836ac495dSmrg // mailing list we have chosen the value below.
8936ac495dSmrg // See http://gcc.gnu.org/ml/libstdc++/2001-07/msg00077.html
9036ac495dSmrg // NB: At least one order of magnitude > _M_max_bytes.
9136ac495dSmrg size_t _M_chunk_size;
9236ac495dSmrg
9336ac495dSmrg // The maximum number of supported threads. For
9436ac495dSmrg // single-threaded operation, use one. Maximum values will
9536ac495dSmrg // vary depending on details of the underlying system. (For
9636ac495dSmrg // instance, Linux 2.4.18 reports 4070 in
9736ac495dSmrg // /proc/sys/kernel/threads-max, while Linux 2.6.6 reports
9836ac495dSmrg // 65534)
9936ac495dSmrg size_t _M_max_threads;
10036ac495dSmrg
10136ac495dSmrg // Each time a deallocation occurs in a threaded application
10236ac495dSmrg // we make sure that there are no more than
10336ac495dSmrg // _M_freelist_headroom % of used memory on the freelist. If
10436ac495dSmrg // the number of additional records is more than
10536ac495dSmrg // _M_freelist_headroom % of the freelist, we move these
10636ac495dSmrg // records back to the global pool.
10736ac495dSmrg size_t _M_freelist_headroom;
10836ac495dSmrg
10936ac495dSmrg // Set to true forces all allocations to use new().
11036ac495dSmrg bool _M_force_new;
11136ac495dSmrg
11236ac495dSmrg explicit
11336ac495dSmrg _Tune()
11436ac495dSmrg : _M_align(_S_align), _M_max_bytes(_S_max_bytes), _M_min_bin(_S_min_bin),
11536ac495dSmrg _M_chunk_size(_S_chunk_size), _M_max_threads(_S_max_threads),
11636ac495dSmrg _M_freelist_headroom(_S_freelist_headroom),
11736ac495dSmrg _M_force_new(std::getenv("GLIBCXX_FORCE_NEW") ? true : false)
11836ac495dSmrg { }
11936ac495dSmrg
12036ac495dSmrg explicit
12136ac495dSmrg _Tune(size_t __align, size_t __maxb, size_t __minbin, size_t __chunk,
12236ac495dSmrg size_t __maxthreads, size_t __headroom, bool __force)
12336ac495dSmrg : _M_align(__align), _M_max_bytes(__maxb), _M_min_bin(__minbin),
12436ac495dSmrg _M_chunk_size(__chunk), _M_max_threads(__maxthreads),
12536ac495dSmrg _M_freelist_headroom(__headroom), _M_force_new(__force)
12636ac495dSmrg { }
12736ac495dSmrg };
12836ac495dSmrg
12936ac495dSmrg struct _Block_address
13036ac495dSmrg {
13136ac495dSmrg void* _M_initial;
13236ac495dSmrg _Block_address* _M_next;
13336ac495dSmrg };
13436ac495dSmrg
13536ac495dSmrg const _Tune&
13636ac495dSmrg _M_get_options() const
13736ac495dSmrg { return _M_options; }
13836ac495dSmrg
13936ac495dSmrg void
14036ac495dSmrg _M_set_options(_Tune __t)
14136ac495dSmrg {
14236ac495dSmrg if (!_M_init)
14336ac495dSmrg _M_options = __t;
14436ac495dSmrg }
14536ac495dSmrg
14636ac495dSmrg bool
14736ac495dSmrg _M_check_threshold(size_t __bytes)
14836ac495dSmrg { return __bytes > _M_options._M_max_bytes || _M_options._M_force_new; }
14936ac495dSmrg
15036ac495dSmrg size_t
15136ac495dSmrg _M_get_binmap(size_t __bytes)
15236ac495dSmrg { return _M_binmap[__bytes]; }
15336ac495dSmrg
15436ac495dSmrg size_t
15536ac495dSmrg _M_get_align()
15636ac495dSmrg { return _M_options._M_align; }
15736ac495dSmrg
15836ac495dSmrg explicit
15936ac495dSmrg __pool_base()
16036ac495dSmrg : _M_options(_Tune()), _M_binmap(0), _M_init(false) { }
16136ac495dSmrg
16236ac495dSmrg explicit
16336ac495dSmrg __pool_base(const _Tune& __options)
16436ac495dSmrg : _M_options(__options), _M_binmap(0), _M_init(false) { }
16536ac495dSmrg
16636ac495dSmrg private:
16736ac495dSmrg explicit
16836ac495dSmrg __pool_base(const __pool_base&);
16936ac495dSmrg
17036ac495dSmrg __pool_base&
17136ac495dSmrg operator=(const __pool_base&);
17236ac495dSmrg
17336ac495dSmrg protected:
17436ac495dSmrg // Configuration options.
17536ac495dSmrg _Tune _M_options;
17636ac495dSmrg
17736ac495dSmrg _Binmap_type* _M_binmap;
17836ac495dSmrg
17936ac495dSmrg // Configuration of the pool object via _M_options can happen
18036ac495dSmrg // after construction but before initialization. After
18136ac495dSmrg // initialization is complete, this variable is set to true.
18236ac495dSmrg bool _M_init;
18336ac495dSmrg };
18436ac495dSmrg
18536ac495dSmrg
18636ac495dSmrg /**
18736ac495dSmrg * @brief Data describing the underlying memory pool, parameterized on
18836ac495dSmrg * threading support.
18936ac495dSmrg */
19036ac495dSmrg template<bool _Thread>
19136ac495dSmrg class __pool;
19236ac495dSmrg
19336ac495dSmrg /// Specialization for single thread.
19436ac495dSmrg template<>
19536ac495dSmrg class __pool<false> : public __pool_base
19636ac495dSmrg {
19736ac495dSmrg public:
19836ac495dSmrg union _Block_record
19936ac495dSmrg {
20036ac495dSmrg // Points to the block_record of the next free block.
20136ac495dSmrg _Block_record* _M_next;
20236ac495dSmrg };
20336ac495dSmrg
20436ac495dSmrg struct _Bin_record
20536ac495dSmrg {
20636ac495dSmrg // An "array" of pointers to the first free block.
20736ac495dSmrg _Block_record** _M_first;
20836ac495dSmrg
20936ac495dSmrg // A list of the initial addresses of all allocated blocks.
21036ac495dSmrg _Block_address* _M_address;
21136ac495dSmrg };
21236ac495dSmrg
21336ac495dSmrg void
21436ac495dSmrg _M_initialize_once()
21536ac495dSmrg {
21636ac495dSmrg if (__builtin_expect(_M_init == false, false))
21736ac495dSmrg _M_initialize();
21836ac495dSmrg }
21936ac495dSmrg
22036ac495dSmrg void
22136ac495dSmrg _M_destroy() throw();
22236ac495dSmrg
22336ac495dSmrg char*
22436ac495dSmrg _M_reserve_block(size_t __bytes, const size_t __thread_id);
22536ac495dSmrg
22636ac495dSmrg void
22736ac495dSmrg _M_reclaim_block(char* __p, size_t __bytes) throw ();
22836ac495dSmrg
22936ac495dSmrg size_t
23036ac495dSmrg _M_get_thread_id() { return 0; }
23136ac495dSmrg
23236ac495dSmrg const _Bin_record&
23336ac495dSmrg _M_get_bin(size_t __which)
23436ac495dSmrg { return _M_bin[__which]; }
23536ac495dSmrg
23636ac495dSmrg void
23736ac495dSmrg _M_adjust_freelist(const _Bin_record&, _Block_record*, size_t)
23836ac495dSmrg { }
23936ac495dSmrg
24036ac495dSmrg explicit __pool()
24136ac495dSmrg : _M_bin(0), _M_bin_size(1) { }
24236ac495dSmrg
24336ac495dSmrg explicit __pool(const __pool_base::_Tune& __tune)
24436ac495dSmrg : __pool_base(__tune), _M_bin(0), _M_bin_size(1) { }
24536ac495dSmrg
24636ac495dSmrg private:
24736ac495dSmrg // An "array" of bin_records each of which represents a specific
24836ac495dSmrg // power of 2 size. Memory to this "array" is allocated in
24936ac495dSmrg // _M_initialize().
25036ac495dSmrg _Bin_record* _M_bin;
25136ac495dSmrg
25236ac495dSmrg // Actual value calculated in _M_initialize().
25336ac495dSmrg size_t _M_bin_size;
25436ac495dSmrg
25536ac495dSmrg void
25636ac495dSmrg _M_initialize();
25736ac495dSmrg };
25836ac495dSmrg
25936ac495dSmrg #ifdef __GTHREADS
26036ac495dSmrg /// Specialization for thread enabled, via gthreads.h.
26136ac495dSmrg template<>
26236ac495dSmrg class __pool<true> : public __pool_base
26336ac495dSmrg {
26436ac495dSmrg public:
26536ac495dSmrg // Each requesting thread is assigned an id ranging from 1 to
26636ac495dSmrg // _S_max_threads. Thread id 0 is used as a global memory pool.
26736ac495dSmrg // In order to get constant performance on the thread assignment
26836ac495dSmrg // routine, we keep a list of free ids. When a thread first
26936ac495dSmrg // requests memory we remove the first record in this list and
27036ac495dSmrg // stores the address in a __gthread_key. When initializing the
27136ac495dSmrg // __gthread_key we specify a destructor. When this destructor
27236ac495dSmrg // (i.e. the thread dies) is called, we return the thread id to
27336ac495dSmrg // the front of this list.
27436ac495dSmrg struct _Thread_record
27536ac495dSmrg {
27636ac495dSmrg // Points to next free thread id record. NULL if last record in list.
27736ac495dSmrg _Thread_record* _M_next;
27836ac495dSmrg
27936ac495dSmrg // Thread id ranging from 1 to _S_max_threads.
28036ac495dSmrg size_t _M_id;
28136ac495dSmrg };
28236ac495dSmrg
28336ac495dSmrg union _Block_record
28436ac495dSmrg {
28536ac495dSmrg // Points to the block_record of the next free block.
28636ac495dSmrg _Block_record* _M_next;
28736ac495dSmrg
28836ac495dSmrg // The thread id of the thread which has requested this block.
28936ac495dSmrg size_t _M_thread_id;
29036ac495dSmrg };
29136ac495dSmrg
29236ac495dSmrg struct _Bin_record
29336ac495dSmrg {
29436ac495dSmrg // An "array" of pointers to the first free block for each
29536ac495dSmrg // thread id. Memory to this "array" is allocated in
29636ac495dSmrg // _S_initialize() for _S_max_threads + global pool 0.
29736ac495dSmrg _Block_record** _M_first;
29836ac495dSmrg
29936ac495dSmrg // A list of the initial addresses of all allocated blocks.
30036ac495dSmrg _Block_address* _M_address;
30136ac495dSmrg
30236ac495dSmrg // An "array" of counters used to keep track of the amount of
30336ac495dSmrg // blocks that are on the freelist/used for each thread id.
30436ac495dSmrg // - Note that the second part of the allocated _M_used "array"
30536ac495dSmrg // actually hosts (atomic) counters of reclaimed blocks: in
30636ac495dSmrg // _M_reserve_block and in _M_reclaim_block those numbers are
30736ac495dSmrg // subtracted from the first ones to obtain the actual size
30836ac495dSmrg // of the "working set" of the given thread.
30936ac495dSmrg // - Memory to these "arrays" is allocated in _S_initialize()
31036ac495dSmrg // for _S_max_threads + global pool 0.
31136ac495dSmrg size_t* _M_free;
31236ac495dSmrg size_t* _M_used;
31336ac495dSmrg
31436ac495dSmrg // Each bin has its own mutex which is used to ensure data
31536ac495dSmrg // integrity while changing "ownership" on a block. The mutex
31636ac495dSmrg // is initialized in _S_initialize().
31736ac495dSmrg __gthread_mutex_t* _M_mutex;
31836ac495dSmrg };
31936ac495dSmrg
32036ac495dSmrg // XXX GLIBCXX_ABI Deprecated
32136ac495dSmrg void
32236ac495dSmrg _M_initialize(__destroy_handler);
32336ac495dSmrg
32436ac495dSmrg void
32536ac495dSmrg _M_initialize_once()
32636ac495dSmrg {
32736ac495dSmrg if (__builtin_expect(_M_init == false, false))
32836ac495dSmrg _M_initialize();
32936ac495dSmrg }
33036ac495dSmrg
33136ac495dSmrg void
33236ac495dSmrg _M_destroy() throw();
33336ac495dSmrg
33436ac495dSmrg char*
33536ac495dSmrg _M_reserve_block(size_t __bytes, const size_t __thread_id);
33636ac495dSmrg
33736ac495dSmrg void
33836ac495dSmrg _M_reclaim_block(char* __p, size_t __bytes) throw ();
33936ac495dSmrg
34036ac495dSmrg const _Bin_record&
34136ac495dSmrg _M_get_bin(size_t __which)
34236ac495dSmrg { return _M_bin[__which]; }
34336ac495dSmrg
34436ac495dSmrg void
34536ac495dSmrg _M_adjust_freelist(const _Bin_record& __bin, _Block_record* __block,
34636ac495dSmrg size_t __thread_id)
34736ac495dSmrg {
34836ac495dSmrg if (__gthread_active_p())
34936ac495dSmrg {
35036ac495dSmrg __block->_M_thread_id = __thread_id;
35136ac495dSmrg --__bin._M_free[__thread_id];
35236ac495dSmrg ++__bin._M_used[__thread_id];
35336ac495dSmrg }
35436ac495dSmrg }
35536ac495dSmrg
35636ac495dSmrg // XXX GLIBCXX_ABI Deprecated
357a2dc1f3fSmrg void
35836ac495dSmrg _M_destroy_thread_key(void*) throw ();
35936ac495dSmrg
36036ac495dSmrg size_t
36136ac495dSmrg _M_get_thread_id();
36236ac495dSmrg
36336ac495dSmrg explicit __pool()
36436ac495dSmrg : _M_bin(0), _M_bin_size(1), _M_thread_freelist(0)
36536ac495dSmrg { }
36636ac495dSmrg
36736ac495dSmrg explicit __pool(const __pool_base::_Tune& __tune)
36836ac495dSmrg : __pool_base(__tune), _M_bin(0), _M_bin_size(1),
36936ac495dSmrg _M_thread_freelist(0)
37036ac495dSmrg { }
37136ac495dSmrg
37236ac495dSmrg private:
37336ac495dSmrg // An "array" of bin_records each of which represents a specific
37436ac495dSmrg // power of 2 size. Memory to this "array" is allocated in
37536ac495dSmrg // _M_initialize().
37636ac495dSmrg _Bin_record* _M_bin;
37736ac495dSmrg
37836ac495dSmrg // Actual value calculated in _M_initialize().
37936ac495dSmrg size_t _M_bin_size;
38036ac495dSmrg
38136ac495dSmrg _Thread_record* _M_thread_freelist;
38236ac495dSmrg void* _M_thread_freelist_initial;
38336ac495dSmrg
38436ac495dSmrg void
38536ac495dSmrg _M_initialize();
38636ac495dSmrg };
38736ac495dSmrg #endif
38836ac495dSmrg
38936ac495dSmrg template<template <bool> class _PoolTp, bool _Thread>
39036ac495dSmrg struct __common_pool
39136ac495dSmrg {
39236ac495dSmrg typedef _PoolTp<_Thread> pool_type;
39336ac495dSmrg
39436ac495dSmrg static pool_type&
39536ac495dSmrg _S_get_pool()
39636ac495dSmrg {
39736ac495dSmrg static pool_type _S_pool;
39836ac495dSmrg return _S_pool;
39936ac495dSmrg }
40036ac495dSmrg };
40136ac495dSmrg
40236ac495dSmrg template<template <bool> class _PoolTp, bool _Thread>
40336ac495dSmrg struct __common_pool_base;
40436ac495dSmrg
40536ac495dSmrg template<template <bool> class _PoolTp>
40636ac495dSmrg struct __common_pool_base<_PoolTp, false>
40736ac495dSmrg : public __common_pool<_PoolTp, false>
40836ac495dSmrg {
40936ac495dSmrg using __common_pool<_PoolTp, false>::_S_get_pool;
41036ac495dSmrg
41136ac495dSmrg static void
41236ac495dSmrg _S_initialize_once()
41336ac495dSmrg {
41436ac495dSmrg static bool __init;
41536ac495dSmrg if (__builtin_expect(__init == false, false))
41636ac495dSmrg {
41736ac495dSmrg _S_get_pool()._M_initialize_once();
41836ac495dSmrg __init = true;
41936ac495dSmrg }
42036ac495dSmrg }
42136ac495dSmrg };
42236ac495dSmrg
42336ac495dSmrg #ifdef __GTHREADS
42436ac495dSmrg template<template <bool> class _PoolTp>
42536ac495dSmrg struct __common_pool_base<_PoolTp, true>
42636ac495dSmrg : public __common_pool<_PoolTp, true>
42736ac495dSmrg {
42836ac495dSmrg using __common_pool<_PoolTp, true>::_S_get_pool;
42936ac495dSmrg
43036ac495dSmrg static void
43136ac495dSmrg _S_initialize()
43236ac495dSmrg { _S_get_pool()._M_initialize_once(); }
43336ac495dSmrg
43436ac495dSmrg static void
43536ac495dSmrg _S_initialize_once()
43636ac495dSmrg {
43736ac495dSmrg static bool __init;
43836ac495dSmrg if (__builtin_expect(__init == false, false))
43936ac495dSmrg {
44036ac495dSmrg if (__gthread_active_p())
44136ac495dSmrg {
44236ac495dSmrg // On some platforms, __gthread_once_t is an aggregate.
44336ac495dSmrg static __gthread_once_t __once = __GTHREAD_ONCE_INIT;
44436ac495dSmrg __gthread_once(&__once, _S_initialize);
44536ac495dSmrg }
44636ac495dSmrg
44736ac495dSmrg // Double check initialization. May be necessary on some
44836ac495dSmrg // systems for proper construction when not compiling with
44936ac495dSmrg // thread flags.
45036ac495dSmrg _S_get_pool()._M_initialize_once();
45136ac495dSmrg __init = true;
45236ac495dSmrg }
45336ac495dSmrg }
45436ac495dSmrg };
45536ac495dSmrg #endif
45636ac495dSmrg
45736ac495dSmrg /// Policy for shared __pool objects.
45836ac495dSmrg template<template <bool> class _PoolTp, bool _Thread>
45936ac495dSmrg struct __common_pool_policy : public __common_pool_base<_PoolTp, _Thread>
46036ac495dSmrg {
46136ac495dSmrg template<typename _Tp1, template <bool> class _PoolTp1 = _PoolTp,
46236ac495dSmrg bool _Thread1 = _Thread>
46336ac495dSmrg struct _M_rebind
46436ac495dSmrg { typedef __common_pool_policy<_PoolTp1, _Thread1> other; };
46536ac495dSmrg
46636ac495dSmrg using __common_pool_base<_PoolTp, _Thread>::_S_get_pool;
46736ac495dSmrg using __common_pool_base<_PoolTp, _Thread>::_S_initialize_once;
46836ac495dSmrg };
46936ac495dSmrg
47036ac495dSmrg
47136ac495dSmrg template<typename _Tp, template <bool> class _PoolTp, bool _Thread>
47236ac495dSmrg struct __per_type_pool
47336ac495dSmrg {
47436ac495dSmrg typedef _Tp value_type;
47536ac495dSmrg typedef _PoolTp<_Thread> pool_type;
47636ac495dSmrg
47736ac495dSmrg static pool_type&
47836ac495dSmrg _S_get_pool()
47936ac495dSmrg {
480*8feb0f0bSmrg using std::size_t;
48136ac495dSmrg // Sane defaults for the _PoolTp.
48236ac495dSmrg typedef typename pool_type::_Block_record _Block_record;
48336ac495dSmrg const static size_t __a = (__alignof__(_Tp) >= sizeof(_Block_record)
48436ac495dSmrg ? __alignof__(_Tp) : sizeof(_Block_record));
48536ac495dSmrg
48636ac495dSmrg typedef typename __pool_base::_Tune _Tune;
48736ac495dSmrg static _Tune _S_tune(__a, sizeof(_Tp) * 64,
48836ac495dSmrg sizeof(_Tp) * 2 >= __a ? sizeof(_Tp) * 2 : __a,
48936ac495dSmrg sizeof(_Tp) * size_t(_Tune::_S_chunk_size),
49036ac495dSmrg _Tune::_S_max_threads,
49136ac495dSmrg _Tune::_S_freelist_headroom,
49236ac495dSmrg std::getenv("GLIBCXX_FORCE_NEW") ? true : false);
49336ac495dSmrg static pool_type _S_pool(_S_tune);
49436ac495dSmrg return _S_pool;
49536ac495dSmrg }
49636ac495dSmrg };
49736ac495dSmrg
49836ac495dSmrg template<typename _Tp, template <bool> class _PoolTp, bool _Thread>
49936ac495dSmrg struct __per_type_pool_base;
50036ac495dSmrg
50136ac495dSmrg template<typename _Tp, template <bool> class _PoolTp>
50236ac495dSmrg struct __per_type_pool_base<_Tp, _PoolTp, false>
50336ac495dSmrg : public __per_type_pool<_Tp, _PoolTp, false>
50436ac495dSmrg {
50536ac495dSmrg using __per_type_pool<_Tp, _PoolTp, false>::_S_get_pool;
50636ac495dSmrg
50736ac495dSmrg static void
50836ac495dSmrg _S_initialize_once()
50936ac495dSmrg {
51036ac495dSmrg static bool __init;
51136ac495dSmrg if (__builtin_expect(__init == false, false))
51236ac495dSmrg {
51336ac495dSmrg _S_get_pool()._M_initialize_once();
51436ac495dSmrg __init = true;
51536ac495dSmrg }
51636ac495dSmrg }
51736ac495dSmrg };
51836ac495dSmrg
51936ac495dSmrg #ifdef __GTHREADS
52036ac495dSmrg template<typename _Tp, template <bool> class _PoolTp>
52136ac495dSmrg struct __per_type_pool_base<_Tp, _PoolTp, true>
52236ac495dSmrg : public __per_type_pool<_Tp, _PoolTp, true>
52336ac495dSmrg {
52436ac495dSmrg using __per_type_pool<_Tp, _PoolTp, true>::_S_get_pool;
52536ac495dSmrg
52636ac495dSmrg static void
52736ac495dSmrg _S_initialize()
52836ac495dSmrg { _S_get_pool()._M_initialize_once(); }
52936ac495dSmrg
53036ac495dSmrg static void
53136ac495dSmrg _S_initialize_once()
53236ac495dSmrg {
53336ac495dSmrg static bool __init;
53436ac495dSmrg if (__builtin_expect(__init == false, false))
53536ac495dSmrg {
53636ac495dSmrg if (__gthread_active_p())
53736ac495dSmrg {
53836ac495dSmrg // On some platforms, __gthread_once_t is an aggregate.
53936ac495dSmrg static __gthread_once_t __once = __GTHREAD_ONCE_INIT;
54036ac495dSmrg __gthread_once(&__once, _S_initialize);
54136ac495dSmrg }
54236ac495dSmrg
54336ac495dSmrg // Double check initialization. May be necessary on some
54436ac495dSmrg // systems for proper construction when not compiling with
54536ac495dSmrg // thread flags.
54636ac495dSmrg _S_get_pool()._M_initialize_once();
54736ac495dSmrg __init = true;
54836ac495dSmrg }
54936ac495dSmrg }
55036ac495dSmrg };
55136ac495dSmrg #endif
55236ac495dSmrg
55336ac495dSmrg /// Policy for individual __pool objects.
55436ac495dSmrg template<typename _Tp, template <bool> class _PoolTp, bool _Thread>
55536ac495dSmrg struct __per_type_pool_policy
55636ac495dSmrg : public __per_type_pool_base<_Tp, _PoolTp, _Thread>
55736ac495dSmrg {
55836ac495dSmrg template<typename _Tp1, template <bool> class _PoolTp1 = _PoolTp,
55936ac495dSmrg bool _Thread1 = _Thread>
56036ac495dSmrg struct _M_rebind
56136ac495dSmrg { typedef __per_type_pool_policy<_Tp1, _PoolTp1, _Thread1> other; };
56236ac495dSmrg
56336ac495dSmrg using __per_type_pool_base<_Tp, _PoolTp, _Thread>::_S_get_pool;
56436ac495dSmrg using __per_type_pool_base<_Tp, _PoolTp, _Thread>::_S_initialize_once;
56536ac495dSmrg };
56636ac495dSmrg
56736ac495dSmrg
56836ac495dSmrg /// Base class for _Tp dependent member functions.
56936ac495dSmrg template<typename _Tp>
57036ac495dSmrg class __mt_alloc_base
57136ac495dSmrg {
57236ac495dSmrg public:
573*8feb0f0bSmrg typedef std::size_t size_type;
574*8feb0f0bSmrg typedef std::ptrdiff_t difference_type;
57536ac495dSmrg typedef _Tp* pointer;
57636ac495dSmrg typedef const _Tp* const_pointer;
57736ac495dSmrg typedef _Tp& reference;
57836ac495dSmrg typedef const _Tp& const_reference;
57936ac495dSmrg typedef _Tp value_type;
58036ac495dSmrg
58136ac495dSmrg #if __cplusplus >= 201103L
58236ac495dSmrg // _GLIBCXX_RESOLVE_LIB_DEFECTS
58336ac495dSmrg // 2103. propagate_on_container_move_assignment
58436ac495dSmrg typedef std::true_type propagate_on_container_move_assignment;
58536ac495dSmrg #endif
58636ac495dSmrg
58736ac495dSmrg pointer
58836ac495dSmrg address(reference __x) const _GLIBCXX_NOEXCEPT
58936ac495dSmrg { return std::__addressof(__x); }
59036ac495dSmrg
59136ac495dSmrg const_pointer
59236ac495dSmrg address(const_reference __x) const _GLIBCXX_NOEXCEPT
59336ac495dSmrg { return std::__addressof(__x); }
59436ac495dSmrg
59536ac495dSmrg size_type
59636ac495dSmrg max_size() const _GLIBCXX_USE_NOEXCEPT
597*8feb0f0bSmrg { return size_type(-1) / sizeof(_Tp); }
59836ac495dSmrg
59936ac495dSmrg #if __cplusplus >= 201103L
60036ac495dSmrg template<typename _Up, typename... _Args>
60136ac495dSmrg void
60236ac495dSmrg construct(_Up* __p, _Args&&... __args)
60336ac495dSmrg { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
60436ac495dSmrg
60536ac495dSmrg template<typename _Up>
60636ac495dSmrg void
60736ac495dSmrg destroy(_Up* __p) { __p->~_Up(); }
60836ac495dSmrg #else
60936ac495dSmrg // _GLIBCXX_RESOLVE_LIB_DEFECTS
61036ac495dSmrg // 402. wrong new expression in [some_] allocator::construct
61136ac495dSmrg void
61236ac495dSmrg construct(pointer __p, const _Tp& __val)
61336ac495dSmrg { ::new((void *)__p) _Tp(__val); }
61436ac495dSmrg
61536ac495dSmrg void
61636ac495dSmrg destroy(pointer __p) { __p->~_Tp(); }
61736ac495dSmrg #endif
61836ac495dSmrg };
61936ac495dSmrg
62036ac495dSmrg #ifdef __GTHREADS
62136ac495dSmrg #define __thread_default true
62236ac495dSmrg #else
62336ac495dSmrg #define __thread_default false
62436ac495dSmrg #endif
62536ac495dSmrg
62636ac495dSmrg /**
62736ac495dSmrg * @brief This is a fixed size (power of 2) allocator which - when
62836ac495dSmrg * compiled with thread support - will maintain one freelist per
62936ac495dSmrg * size per thread plus a @a global one. Steps are taken to limit
63036ac495dSmrg * the per thread freelist sizes (by returning excess back to
63136ac495dSmrg * the @a global list).
63236ac495dSmrg * @ingroup allocators
63336ac495dSmrg *
63436ac495dSmrg * Further details:
63536ac495dSmrg * https://gcc.gnu.org/onlinedocs/libstdc++/manual/mt_allocator.html
63636ac495dSmrg */
63736ac495dSmrg template<typename _Tp,
63836ac495dSmrg typename _Poolp = __common_pool_policy<__pool, __thread_default> >
63936ac495dSmrg class __mt_alloc : public __mt_alloc_base<_Tp>
64036ac495dSmrg {
64136ac495dSmrg public:
642*8feb0f0bSmrg typedef std::size_t size_type;
643*8feb0f0bSmrg typedef std::ptrdiff_t difference_type;
64436ac495dSmrg typedef _Tp* pointer;
64536ac495dSmrg typedef const _Tp* const_pointer;
64636ac495dSmrg typedef _Tp& reference;
64736ac495dSmrg typedef const _Tp& const_reference;
64836ac495dSmrg typedef _Tp value_type;
64936ac495dSmrg typedef _Poolp __policy_type;
65036ac495dSmrg typedef typename _Poolp::pool_type __pool_type;
65136ac495dSmrg
65236ac495dSmrg template<typename _Tp1, typename _Poolp1 = _Poolp>
65336ac495dSmrg struct rebind
65436ac495dSmrg {
65536ac495dSmrg typedef typename _Poolp1::template _M_rebind<_Tp1>::other pol_type;
65636ac495dSmrg typedef __mt_alloc<_Tp1, pol_type> other;
65736ac495dSmrg };
65836ac495dSmrg
65936ac495dSmrg __mt_alloc() _GLIBCXX_USE_NOEXCEPT { }
66036ac495dSmrg
66136ac495dSmrg __mt_alloc(const __mt_alloc&) _GLIBCXX_USE_NOEXCEPT { }
66236ac495dSmrg
66336ac495dSmrg template<typename _Tp1, typename _Poolp1>
66436ac495dSmrg __mt_alloc(const __mt_alloc<_Tp1, _Poolp1>&) _GLIBCXX_USE_NOEXCEPT { }
66536ac495dSmrg
66636ac495dSmrg ~__mt_alloc() _GLIBCXX_USE_NOEXCEPT { }
66736ac495dSmrg
668c0a68be4Smrg _GLIBCXX_NODISCARD pointer
66936ac495dSmrg allocate(size_type __n, const void* = 0);
67036ac495dSmrg
67136ac495dSmrg void
67236ac495dSmrg deallocate(pointer __p, size_type __n);
67336ac495dSmrg
67436ac495dSmrg const __pool_base::_Tune
67536ac495dSmrg _M_get_options()
67636ac495dSmrg {
67736ac495dSmrg // Return a copy, not a reference, for external consumption.
67836ac495dSmrg return __policy_type::_S_get_pool()._M_get_options();
67936ac495dSmrg }
68036ac495dSmrg
68136ac495dSmrg void
68236ac495dSmrg _M_set_options(__pool_base::_Tune __t)
68336ac495dSmrg { __policy_type::_S_get_pool()._M_set_options(__t); }
68436ac495dSmrg };
68536ac495dSmrg
68636ac495dSmrg template<typename _Tp, typename _Poolp>
687c0a68be4Smrg _GLIBCXX_NODISCARD typename __mt_alloc<_Tp, _Poolp>::pointer
68836ac495dSmrg __mt_alloc<_Tp, _Poolp>::
68936ac495dSmrg allocate(size_type __n, const void*)
69036ac495dSmrg {
69136ac495dSmrg if (__n > this->max_size())
69236ac495dSmrg std::__throw_bad_alloc();
69336ac495dSmrg
69436ac495dSmrg #if __cpp_aligned_new
69536ac495dSmrg // Types with extended alignment are handled by operator new/delete.
69636ac495dSmrg if (alignof(_Tp) > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
69736ac495dSmrg {
69836ac495dSmrg std::align_val_t __al = std::align_val_t(alignof(_Tp));
69936ac495dSmrg return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp), __al));
70036ac495dSmrg }
70136ac495dSmrg #endif
70236ac495dSmrg
70336ac495dSmrg __policy_type::_S_initialize_once();
70436ac495dSmrg
70536ac495dSmrg // Requests larger than _M_max_bytes are handled by operator
70636ac495dSmrg // new/delete directly.
70736ac495dSmrg __pool_type& __pool = __policy_type::_S_get_pool();
708*8feb0f0bSmrg const size_type __bytes = __n * sizeof(_Tp);
70936ac495dSmrg if (__pool._M_check_threshold(__bytes))
71036ac495dSmrg {
71136ac495dSmrg void* __ret = ::operator new(__bytes);
71236ac495dSmrg return static_cast<_Tp*>(__ret);
71336ac495dSmrg }
71436ac495dSmrg
71536ac495dSmrg // Round up to power of 2 and figure out which bin to use.
716*8feb0f0bSmrg const size_type __which = __pool._M_get_binmap(__bytes);
717*8feb0f0bSmrg const size_type __thread_id = __pool._M_get_thread_id();
71836ac495dSmrg
71936ac495dSmrg // Find out if we have blocks on our freelist. If so, go ahead
72036ac495dSmrg // and use them directly without having to lock anything.
72136ac495dSmrg char* __c;
72236ac495dSmrg typedef typename __pool_type::_Bin_record _Bin_record;
72336ac495dSmrg const _Bin_record& __bin = __pool._M_get_bin(__which);
72436ac495dSmrg if (__bin._M_first[__thread_id])
72536ac495dSmrg {
72636ac495dSmrg // Already reserved.
72736ac495dSmrg typedef typename __pool_type::_Block_record _Block_record;
72836ac495dSmrg _Block_record* __block = __bin._M_first[__thread_id];
72936ac495dSmrg __bin._M_first[__thread_id] = __block->_M_next;
73036ac495dSmrg
73136ac495dSmrg __pool._M_adjust_freelist(__bin, __block, __thread_id);
73236ac495dSmrg __c = reinterpret_cast<char*>(__block) + __pool._M_get_align();
73336ac495dSmrg }
73436ac495dSmrg else
73536ac495dSmrg {
73636ac495dSmrg // Null, reserve.
73736ac495dSmrg __c = __pool._M_reserve_block(__bytes, __thread_id);
73836ac495dSmrg }
73936ac495dSmrg return static_cast<_Tp*>(static_cast<void*>(__c));
74036ac495dSmrg }
74136ac495dSmrg
74236ac495dSmrg template<typename _Tp, typename _Poolp>
74336ac495dSmrg void
74436ac495dSmrg __mt_alloc<_Tp, _Poolp>::
74536ac495dSmrg deallocate(pointer __p, size_type __n)
74636ac495dSmrg {
74736ac495dSmrg if (__builtin_expect(__p != 0, true))
74836ac495dSmrg {
74936ac495dSmrg #if __cpp_aligned_new
75036ac495dSmrg // Types with extended alignment are handled by operator new/delete.
75136ac495dSmrg if (alignof(_Tp) > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
75236ac495dSmrg {
75336ac495dSmrg ::operator delete(__p, std::align_val_t(alignof(_Tp)));
75436ac495dSmrg return;
75536ac495dSmrg }
75636ac495dSmrg #endif
75736ac495dSmrg
75836ac495dSmrg // Requests larger than _M_max_bytes are handled by
75936ac495dSmrg // operators new/delete directly.
76036ac495dSmrg __pool_type& __pool = __policy_type::_S_get_pool();
761*8feb0f0bSmrg const size_type __bytes = __n * sizeof(_Tp);
76236ac495dSmrg if (__pool._M_check_threshold(__bytes))
76336ac495dSmrg ::operator delete(__p);
76436ac495dSmrg else
76536ac495dSmrg __pool._M_reclaim_block(reinterpret_cast<char*>(__p), __bytes);
76636ac495dSmrg }
76736ac495dSmrg }
76836ac495dSmrg
76936ac495dSmrg template<typename _Tp, typename _Poolp>
77036ac495dSmrg inline bool
77136ac495dSmrg operator==(const __mt_alloc<_Tp, _Poolp>&, const __mt_alloc<_Tp, _Poolp>&)
77236ac495dSmrg { return true; }
77336ac495dSmrg
774*8feb0f0bSmrg #if __cpp_impl_three_way_comparison < 201907L
77536ac495dSmrg template<typename _Tp, typename _Poolp>
77636ac495dSmrg inline bool
77736ac495dSmrg operator!=(const __mt_alloc<_Tp, _Poolp>&, const __mt_alloc<_Tp, _Poolp>&)
77836ac495dSmrg { return false; }
779*8feb0f0bSmrg #endif
78036ac495dSmrg
78136ac495dSmrg #undef __thread_default
78236ac495dSmrg
78336ac495dSmrg _GLIBCXX_END_NAMESPACE_VERSION
78436ac495dSmrg } // namespace
78536ac495dSmrg
78636ac495dSmrg #endif
787