xref: /netbsd-src/external/gpl3/gcc.old/dist/libstdc++-v3/include/ext/mt_allocator.h (revision 8feb0f0b7eaff0608f8350bbfa3098827b4bb91b)
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