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