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