1 // MT-optimized allocator -*- C++ -*-
2 
3 // Copyright (C) 2003, 2004 Free Software Foundation, Inc.
4 //
5 // This file is part of the GNU ISO C++ Library.  This library is free
6 // software; you can redistribute it and/or modify it under the
7 // terms of the GNU General Public License as published by the
8 // Free Software Foundation; either version 2, or (at your option)
9 // any later version.
10 
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15 
16 // You should have received a copy of the GNU General Public License along
17 // with this library; see the file COPYING.  If not, write to the Free
18 // Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
19 // USA.
20 
21 // As a special exception, you may use this file as part of a free software
22 // library without restriction.  Specifically, if other files instantiate
23 // templates or use macros or inline functions from this file, or you compile
24 // this file and link it with other files to produce an executable, this
25 // file does not by itself cause the resulting executable to be covered by
26 // the GNU General Public License.  This exception does not however
27 // invalidate any other reasons why the executable file might be covered by
28 // the GNU General Public License.
29 
30 /** @file ext/mt_allocator.h
31  *  This file is a GNU extension to the Standard C++ Library.
32  *  You should only include this header if you are using GCC 3 or later.
33  */
34 
35 #ifndef _MT_ALLOCATOR_H
36 #define _MT_ALLOCATOR_H 1
37 
38 #include <new>
39 #include <cstdlib>
40 #include <bits/functexcept.h>
41 #include <bits/gthr.h>
42 #include <bits/atomicity.h>
43 
44 namespace __gnu_cxx
45 {
46   /**
47    *  This is a fixed size (power of 2) allocator which - when
48    *  compiled with thread support - will maintain one freelist per
49    *  size per thread plus a "global" one. Steps are taken to limit
50    *  the per thread freelist sizes (by returning excess back to
51    *  "global").
52    *
53    *  Further details:
54    *  http://gcc.gnu.org/onlinedocs/libstdc++/ext/mt_allocator.html
55    */
56   template<typename _Tp>
57     class __mt_alloc
58     {
59     public:
60       typedef size_t                    size_type;
61       typedef ptrdiff_t                 difference_type;
62       typedef _Tp*                      pointer;
63       typedef const _Tp*                const_pointer;
64       typedef _Tp&                      reference;
65       typedef const _Tp&                const_reference;
66       typedef _Tp                       value_type;
67 
68       template<typename _Tp1>
69         struct rebind
70         { typedef __mt_alloc<_Tp1> other; };
71 
72       __mt_alloc() throw()
73       {
74 	// XXX
75       }
76 
77       __mt_alloc(const __mt_alloc&) throw()
78       {
79 	// XXX
80       }
81 
82       template<typename _Tp1>
83         __mt_alloc(const __mt_alloc<_Tp1>& obj) throw()
84         {
85 	  // XXX
86 	}
87 
88       ~__mt_alloc() throw() { }
89 
90       pointer
91       address(reference __x) const
92       { return &__x; }
93 
94       const_pointer
95       address(const_reference __x) const
96       { return &__x; }
97 
98       size_type
99       max_size() const throw()
100       { return size_t(-1) / sizeof(_Tp); }
101 
102       // _GLIBCXX_RESOLVE_LIB_DEFECTS
103       // 402. wrong new expression in [some_] allocator::construct
104       void
105       construct(pointer __p, const _Tp& __val)
106       { ::new(__p) _Tp(__val); }
107 
108       void
109       destroy(pointer __p) { __p->~_Tp(); }
110 
111       pointer
112       allocate(size_type __n, const void* = 0);
113 
114       void
115       deallocate(pointer __p, size_type __n);
116 
117       // Variables used to configure the behavior of the allocator,
118       // assigned and explained in detail below.
119       struct _Tune
120       {
121 	// Alignment needed.
122 	// NB: In any case must be >= sizeof(_Block_record), that
123 	// is 4 on 32 bit machines and 8 on 64 bit machines.
124 	size_t  _M_align;
125 
126 	// Allocation requests (after round-up to power of 2) below
127 	// this value will be handled by the allocator. A raw new/
128 	// call will be used for requests larger than this value.
129 	size_t	_M_max_bytes;
130 
131 	// Size in bytes of the smallest bin.
132 	// NB: Must be a power of 2 and >= _M_align.
133 	size_t  _M_min_bin;
134 
135 	// In order to avoid fragmenting and minimize the number of
136 	// new() calls we always request new memory using this
137 	// value. Based on previous discussions on the libstdc++
138 	// mailing list we have choosen the value below.
139 	// See http://gcc.gnu.org/ml/libstdc++/2001-07/msg00077.html
140 	size_t 	_M_chunk_size;
141 
142 	// The maximum number of supported threads. Our Linux 2.4.18
143 	// reports 4070 in /proc/sys/kernel/threads-max
144 	size_t 	_M_max_threads;
145 
146 	// Each time a deallocation occurs in a threaded application
147 	// we make sure that there are no more than
148 	// _M_freelist_headroom % of used memory on the freelist. If
149 	// the number of additional records is more than
150 	// _M_freelist_headroom % of the freelist, we move these
151 	// records back to the global pool.
152 	size_t 	_M_freelist_headroom;
153 
154 	// Set to true forces all allocations to use new().
155 	bool 	_M_force_new;
156 
157 	explicit
158 	_Tune()
159 	: _M_align(8), _M_max_bytes(128), _M_min_bin(8),
160 	  _M_chunk_size(4096 - 4 * sizeof(void*)),
161 	  _M_max_threads(4096), _M_freelist_headroom(10),
162 	  _M_force_new(getenv("GLIBCXX_FORCE_NEW") ? true : false)
163 	{ }
164 
165 	explicit
166 	_Tune(size_t __align, size_t __maxb, size_t __minbin,
167 	      size_t __chunk, size_t __maxthreads, size_t __headroom,
168 	      bool __force)
169 	: _M_align(__align), _M_max_bytes(__maxb), _M_min_bin(__minbin),
170 	  _M_chunk_size(__chunk), _M_max_threads(__maxthreads),
171 	  _M_freelist_headroom(__headroom), _M_force_new(__force)
172 	{ }
173       };
174 
175     private:
176       // We need to create the initial lists and set up some variables
177       // before we can answer to the first request for memory.
178 #ifdef __GTHREADS
179       static __gthread_once_t 		_S_once;
180 #endif
181       static bool 			_S_init;
182 
183       static void
184       _S_initialize();
185 
186       // Configuration options.
187       static _Tune 	       		_S_options;
188 
189       static const _Tune
190       _S_get_options()
191       { return _S_options; }
192 
193       static void
194       _S_set_options(_Tune __t)
195       {
196 	if (!_S_init)
197 	  _S_options = __t;
198       }
199 
200       // Using short int as type for the binmap implies we are never
201       // caching blocks larger than 65535 with this allocator
202       typedef unsigned short int        _Binmap_type;
203       static _Binmap_type* 		_S_binmap;
204 
205       // Each requesting thread is assigned an id ranging from 1 to
206       // _S_max_threads. Thread id 0 is used as a global memory pool.
207       // In order to get constant performance on the thread assignment
208       // routine, we keep a list of free ids. When a thread first
209       // requests memory we remove the first record in this list and
210       // stores the address in a __gthread_key. When initializing the
211       // __gthread_key we specify a destructor. When this destructor
212       // (i.e. the thread dies) is called, we return the thread id to
213       // the front of this list.
214 #ifdef __GTHREADS
215       struct _Thread_record
216       {
217         // Points to next free thread id record. NULL if last record in list.
218         _Thread_record* volatile        _M_next;
219 
220 	// Thread id ranging from 1 to _S_max_threads.
221         size_t                          _M_id;
222       };
223 
224       static _Thread_record* volatile 	_S_thread_freelist_first;
225       static __gthread_mutex_t 		_S_thread_freelist_mutex;
226       static __gthread_key_t 		_S_thread_key;
227 
228       static void
229       _S_destroy_thread_key(void* __freelist_pos);
230 #endif
231 
232       static size_t
233       _S_get_thread_id();
234 
235       union _Block_record
236       {
237 	// Points to the block_record of the next free block.
238         _Block_record* volatile         _M_next;
239 
240 #ifdef __GTHREADS
241 	// The thread id of the thread which has requested this block.
242         size_t                          _M_thread_id;
243 #endif
244       };
245 
246       struct _Bin_record
247       {
248 	// An "array" of pointers to the first free block for each
249 	// thread id. Memory to this "array" is allocated in _S_initialize()
250 	// for _S_max_threads + global pool 0.
251         _Block_record** volatile        _M_first;
252 
253 #ifdef __GTHREADS
254 	// An "array" of counters used to keep track of the amount of
255 	// blocks that are on the freelist/used for each thread id.
256 	// Memory to these "arrays" is allocated in _S_initialize() for
257 	// _S_max_threads + global pool 0.
258         size_t* volatile                _M_free;
259         size_t* volatile                _M_used;
260 
261 	// Each bin has its own mutex which is used to ensure data
262 	// integrity while changing "ownership" on a block.  The mutex
263 	// is initialized in _S_initialize().
264         __gthread_mutex_t*              _M_mutex;
265 #endif
266       };
267 
268       // An "array" of bin_records each of which represents a specific
269       // power of 2 size. Memory to this "array" is allocated in
270       // _S_initialize().
271       static _Bin_record* volatile     	_S_bin;
272 
273       // Actual value calculated in _S_initialize().
274       static size_t 	       	     	_S_bin_size;
275     };
276 
277   template<typename _Tp>
278     typename __mt_alloc<_Tp>::pointer
279     __mt_alloc<_Tp>::
280     allocate(size_type __n, const void*)
281     {
282       // Although the test in __gthread_once() would suffice, we wrap
283       // test of the once condition in our own unlocked check. This
284       // saves one function call to pthread_once() (which itself only
285       // tests for the once value unlocked anyway and immediately
286       // returns if set)
287       if (!_S_init)
288 	{
289 #ifdef __GTHREADS
290 	  if (__gthread_active_p())
291 	    __gthread_once(&_S_once, _S_initialize);
292 #endif
293 	  if (!_S_init)
294 	    _S_initialize();
295 	}
296 
297       // Requests larger than _M_max_bytes are handled by new/delete
298       // directly.
299       const size_t __bytes = __n * sizeof(_Tp);
300       if (__bytes > _S_options._M_max_bytes || _S_options._M_force_new)
301 	{
302 	  void* __ret = ::operator new(__bytes);
303 	  return static_cast<_Tp*>(__ret);
304 	}
305 
306       // Round up to power of 2 and figure out which bin to use.
307       const size_t __which = _S_binmap[__bytes];
308       const size_t __thread_id = _S_get_thread_id();
309 
310       // Find out if we have blocks on our freelist.  If so, go ahead
311       // and use them directly without having to lock anything.
312       const _Bin_record& __bin = _S_bin[__which];
313       _Block_record* __block = NULL;
314       if (__bin._M_first[__thread_id] == NULL)
315 	{
316 	  // NB: For alignment reasons, we can't use the first _M_align
317 	  // bytes, even when sizeof(_Block_record) < _M_align.
318 	  const size_t __bin_size = ((_S_options._M_min_bin << __which)
319 				     + _S_options._M_align);
320 	  size_t __block_count = _S_options._M_chunk_size / __bin_size;
321 
322 	  // Are we using threads?
323 	  // - Yes, check if there are free blocks on the global
324 	  //   list. If so, grab up to __block_count blocks in one
325 	  //   lock and change ownership. If the global list is
326 	  //   empty, we allocate a new chunk and add those blocks
327 	  //   directly to our own freelist (with us as owner).
328 	  // - No, all operations are made directly to global pool 0
329 	  //   no need to lock or change ownership but check for free
330 	  //   blocks on global list (and if not add new ones) and
331 	  //   get the first one.
332 #ifdef __GTHREADS
333 	  if (__gthread_active_p())
334 	    {
335 	      __gthread_mutex_lock(__bin._M_mutex);
336 	      if (__bin._M_first[0] == NULL)
337 		{
338 		  // No need to hold the lock when we are adding a
339 		  // whole chunk to our own list.
340 		  __gthread_mutex_unlock(__bin._M_mutex);
341 
342 		  void* __v = ::operator new(_S_options._M_chunk_size);
343 		  __bin._M_first[__thread_id] = static_cast<_Block_record*>(__v);
344 		  __bin._M_free[__thread_id] = __block_count;
345 
346 		  --__block_count;
347 		  __block = __bin._M_first[__thread_id];
348 		  while (__block_count-- > 0)
349 		    {
350 		      char* __c = reinterpret_cast<char*>(__block) + __bin_size;
351 		      __block->_M_next = reinterpret_cast<_Block_record*>(__c);
352 		      __block = __block->_M_next;
353 		    }
354 		  __block->_M_next = NULL;
355 		}
356 	      else
357 		{
358 		  // Is the number of required blocks greater than or
359 		  // equal to the number that can be provided by the
360 		  // global free list?
361 		  __bin._M_first[__thread_id] = __bin._M_first[0];
362 		  if (__block_count >= __bin._M_free[0])
363 		    {
364 		      __bin._M_free[__thread_id] = __bin._M_free[0];
365 		      __bin._M_free[0] = 0;
366 		      __bin._M_first[0] = NULL;
367 		    }
368 		  else
369 		    {
370 		      __bin._M_free[__thread_id] = __block_count;
371 		      __bin._M_free[0] -= __block_count;
372 		      --__block_count;
373 		      __block = __bin._M_first[0];
374 		      while (__block_count-- > 0)
375 			__block = __block->_M_next;
376 		      __bin._M_first[0] = __block->_M_next;
377 		      __block->_M_next = NULL;
378 		    }
379 		  __gthread_mutex_unlock(__bin._M_mutex);
380 		}
381 	    }
382 	  else
383 #endif
384 	    {
385 	      void* __v = ::operator new(_S_options._M_chunk_size);
386 	      __bin._M_first[0] = static_cast<_Block_record*>(__v);
387 
388 	      --__block_count;
389 	      __block = __bin._M_first[0];
390 	      while (__block_count-- > 0)
391 		{
392 		  char* __c = reinterpret_cast<char*>(__block) + __bin_size;
393 		  __block->_M_next = reinterpret_cast<_Block_record*>(__c);
394 		  __block = __block->_M_next;
395 		}
396 	      __block->_M_next = NULL;
397 	    }
398 	}
399 
400       __block = __bin._M_first[__thread_id];
401       __bin._M_first[__thread_id] = __bin._M_first[__thread_id]->_M_next;
402 #ifdef __GTHREADS
403       if (__gthread_active_p())
404 	{
405 	  __block->_M_thread_id = __thread_id;
406 	  --__bin._M_free[__thread_id];
407 	  ++__bin._M_used[__thread_id];
408 	}
409 #endif
410 
411       char* __c = reinterpret_cast<char*>(__block) + _S_options._M_align;
412       return static_cast<_Tp*>(static_cast<void*>(__c));
413     }
414 
415   template<typename _Tp>
416     void
417     __mt_alloc<_Tp>::
418     deallocate(pointer __p, size_type __n)
419     {
420       // Requests larger than _M_max_bytes are handled by operators
421       // new/delete directly.
422       const size_t __bytes = __n * sizeof(_Tp);
423       if (__bytes > _S_options._M_max_bytes || _S_options._M_force_new)
424 	{
425 	  ::operator delete(__p);
426 	  return;
427 	}
428 
429       // Round up to power of 2 and figure out which bin to use.
430       const size_t __which = _S_binmap[__bytes];
431       const _Bin_record& __bin = _S_bin[__which];
432 
433       char* __c = reinterpret_cast<char*>(__p) - _S_options._M_align;
434       _Block_record* __block = reinterpret_cast<_Block_record*>(__c);
435 
436 #ifdef __GTHREADS
437       if (__gthread_active_p())
438 	{
439 	  // Calculate the number of records to remove from our freelist:
440 	  // in order to avoid too much contention we wait until the
441 	  // number of records is "high enough".
442 	  const size_t __thread_id = _S_get_thread_id();
443 
444 	  long __remove = ((__bin._M_free[__thread_id]
445 			    * _S_options._M_freelist_headroom)
446 			   - __bin._M_used[__thread_id]);
447 	  if (__remove > static_cast<long>(100 * (_S_bin_size - __which)
448 					   * _S_options._M_freelist_headroom)
449 	      && __remove > static_cast<long>(__bin._M_free[__thread_id]))
450 	    {
451 	      _Block_record* __tmp = __bin._M_first[__thread_id];
452 	      _Block_record* __first = __tmp;
453 	      __remove /= _S_options._M_freelist_headroom;
454 	      const long __removed = __remove;
455 	      --__remove;
456 	      while (__remove-- > 0)
457 		__tmp = __tmp->_M_next;
458 	      __bin._M_first[__thread_id] = __tmp->_M_next;
459 	      __bin._M_free[__thread_id] -= __removed;
460 
461 	      __gthread_mutex_lock(__bin._M_mutex);
462 	      __tmp->_M_next = __bin._M_first[0];
463 	      __bin._M_first[0] = __first;
464 	      __bin._M_free[0] += __removed;
465 	      __gthread_mutex_unlock(__bin._M_mutex);
466 	    }
467 
468 	  // Return this block to our list and update counters and
469 	  // owner id as needed.
470 	  --__bin._M_used[__block->_M_thread_id];
471 
472 	  __block->_M_next = __bin._M_first[__thread_id];
473 	  __bin._M_first[__thread_id] = __block;
474 
475 	  ++__bin._M_free[__thread_id];
476 	}
477       else
478 #endif
479 	{
480 	  // Single threaded application - return to global pool.
481 	  __block->_M_next = __bin._M_first[0];
482 	  __bin._M_first[0] = __block;
483 	}
484     }
485 
486   template<typename _Tp>
487     void
488     __mt_alloc<_Tp>::
489     _S_initialize()
490     {
491       // This method is called on the first allocation (when _S_init is still
492       // false) to create the bins.
493 
494       // Ensure that the static initialization of _S_options has
495       // happened.  This depends on (a) _M_align == 0 being an invalid
496       // value that is only present at startup, and (b) the real
497       // static initialization that happens later not actually
498       // changing anything.
499       if (_S_options._M_align == 0)
500         new (&_S_options) _Tune;
501 
502       // _M_force_new must not change after the first allocate(),
503       // which in turn calls this method, so if it's false, it's false
504       // forever and we don't need to return here ever again.
505       if (_S_options._M_force_new)
506 	{
507 	  _S_init = true;
508 	  return;
509 	}
510 
511       // Calculate the number of bins required based on _M_max_bytes.
512       // _S_bin_size is statically-initialized to one.
513       size_t __bin_size = _S_options._M_min_bin;
514       while (_S_options._M_max_bytes > __bin_size)
515 	{
516 	  __bin_size <<= 1;
517 	  ++_S_bin_size;
518 	}
519 
520       // Setup the bin map for quick lookup of the relevant bin.
521       const size_t __j = (_S_options._M_max_bytes + 1) * sizeof(_Binmap_type);
522       _S_binmap = static_cast<_Binmap_type*>(::operator new(__j));
523 
524       _Binmap_type* __bp = _S_binmap;
525       _Binmap_type __bin_max = _S_options._M_min_bin;
526       _Binmap_type __bint = 0;
527       for (_Binmap_type __ct = 0; __ct <= _S_options._M_max_bytes; ++__ct)
528         {
529           if (__ct > __bin_max)
530             {
531               __bin_max <<= 1;
532               ++__bint;
533             }
534           *__bp++ = __bint;
535         }
536 
537       // Initialize _S_bin and its members.
538       void* __v = ::operator new(sizeof(_Bin_record) * _S_bin_size);
539       _S_bin = static_cast<_Bin_record*>(__v);
540 
541       // If __gthread_active_p() create and initialize the list of
542       // free thread ids. Single threaded applications use thread id 0
543       // directly and have no need for this.
544 #ifdef __GTHREADS
545       if (__gthread_active_p())
546         {
547 	  const size_t __k = sizeof(_Thread_record) * _S_options._M_max_threads;
548 	  __v = ::operator new(__k);
549           _S_thread_freelist_first = static_cast<_Thread_record*>(__v);
550 
551 	  // NOTE! The first assignable thread id is 1 since the
552 	  // global pool uses id 0
553           size_t __i;
554           for (__i = 1; __i < _S_options._M_max_threads; ++__i)
555             {
556 	      _Thread_record& __tr = _S_thread_freelist_first[__i - 1];
557               __tr._M_next = &_S_thread_freelist_first[__i];
558               __tr._M_id = __i;
559             }
560 
561           // Set last record.
562           _S_thread_freelist_first[__i - 1]._M_next = NULL;
563           _S_thread_freelist_first[__i - 1]._M_id = __i;
564 
565 	  // Make sure this is initialized.
566 #ifndef __GTHREAD_MUTEX_INIT
567 	  __GTHREAD_MUTEX_INIT_FUNCTION(&_S_thread_freelist_mutex);
568 #endif
569           // Initialize per thread key to hold pointer to
570           // _S_thread_freelist.
571           __gthread_key_create(&_S_thread_key, _S_destroy_thread_key);
572 
573 	  const size_t __max_threads = _S_options._M_max_threads + 1;
574 	  for (size_t __n = 0; __n < _S_bin_size; ++__n)
575 	    {
576 	      _Bin_record& __bin = _S_bin[__n];
577 	      __v = ::operator new(sizeof(_Block_record*) * __max_threads);
578 	      __bin._M_first = static_cast<_Block_record**>(__v);
579 
580 	      __v = ::operator new(sizeof(size_t) * __max_threads);
581               __bin._M_free = static_cast<size_t*>(__v);
582 
583 	      __v = ::operator new(sizeof(size_t) * __max_threads);
584               __bin._M_used = static_cast<size_t*>(__v);
585 
586 	      __v = ::operator new(sizeof(__gthread_mutex_t));
587               __bin._M_mutex = static_cast<__gthread_mutex_t*>(__v);
588 
589 #ifdef __GTHREAD_MUTEX_INIT
590               {
591                 // Do not copy a POSIX/gthr mutex once in use.
592                 __gthread_mutex_t __tmp = __GTHREAD_MUTEX_INIT;
593                 *__bin._M_mutex = __tmp;
594               }
595 #else
596               { __GTHREAD_MUTEX_INIT_FUNCTION(__bin._M_mutex); }
597 #endif
598 
599 	      for (size_t __threadn = 0; __threadn < __max_threads;
600 		   ++__threadn)
601 		{
602 		  __bin._M_first[__threadn] = NULL;
603 		  __bin._M_free[__threadn] = 0;
604 		  __bin._M_used[__threadn] = 0;
605 		}
606 	    }
607 	}
608       else
609 #endif
610 	for (size_t __n = 0; __n < _S_bin_size; ++__n)
611 	  {
612 	    _Bin_record& __bin = _S_bin[__n];
613 	    __v = ::operator new(sizeof(_Block_record*));
614 	    __bin._M_first = static_cast<_Block_record**>(__v);
615 	    __bin._M_first[0] = NULL;
616 	  }
617 
618       _S_init = true;
619     }
620 
621   template<typename _Tp>
622     size_t
623     __mt_alloc<_Tp>::
624     _S_get_thread_id()
625     {
626 #ifdef __GTHREADS
627       // If we have thread support and it's active we check the thread
628       // key value and return its id or if it's not set we take the
629       // first record from _S_thread_freelist and sets the key and
630       // returns it's id.
631       if (__gthread_active_p())
632         {
633           _Thread_record* __freelist_pos =
634 	    static_cast<_Thread_record*>(__gthread_getspecific(_S_thread_key));
635 	  if (__freelist_pos == NULL)
636             {
637 	      // Since _S_options._M_max_threads must be larger than
638 	      // the theoretical max number of threads of the OS the
639 	      // list can never be empty.
640               __gthread_mutex_lock(&_S_thread_freelist_mutex);
641               __freelist_pos = _S_thread_freelist_first;
642               _S_thread_freelist_first = _S_thread_freelist_first->_M_next;
643               __gthread_mutex_unlock(&_S_thread_freelist_mutex);
644 
645               __gthread_setspecific(_S_thread_key,
646 				    static_cast<void*>(__freelist_pos));
647             }
648           return __freelist_pos->_M_id;
649         }
650 #endif
651       // Otherwise (no thread support or inactive) all requests are
652       // served from the global pool 0.
653       return 0;
654     }
655 
656 #ifdef __GTHREADS
657   template<typename _Tp>
658     void
659     __mt_alloc<_Tp>::
660     _S_destroy_thread_key(void* __freelist_pos)
661     {
662       // Return this thread id record to front of thread_freelist.
663       __gthread_mutex_lock(&_S_thread_freelist_mutex);
664       _Thread_record* __tr = static_cast<_Thread_record*>(__freelist_pos);
665       __tr->_M_next = _S_thread_freelist_first;
666       _S_thread_freelist_first = __tr;
667       __gthread_mutex_unlock(&_S_thread_freelist_mutex);
668     }
669 #endif
670 
671   template<typename _Tp>
672     inline bool
673     operator==(const __mt_alloc<_Tp>&, const __mt_alloc<_Tp>&)
674     { return true; }
675 
676   template<typename _Tp>
677     inline bool
678     operator!=(const __mt_alloc<_Tp>&, const __mt_alloc<_Tp>&)
679     { return false; }
680 
681   template<typename _Tp>
682     bool __mt_alloc<_Tp>::_S_init = false;
683 
684   template<typename _Tp>
685     typename __mt_alloc<_Tp>::_Tune __mt_alloc<_Tp>::_S_options;
686 
687   template<typename _Tp>
688     typename __mt_alloc<_Tp>::_Binmap_type* __mt_alloc<_Tp>::_S_binmap;
689 
690   template<typename _Tp>
691     typename __mt_alloc<_Tp>::_Bin_record* volatile __mt_alloc<_Tp>::_S_bin;
692 
693   template<typename _Tp>
694     size_t __mt_alloc<_Tp>::_S_bin_size = 1;
695 
696   // Actual initialization in _S_initialize().
697 #ifdef __GTHREADS
698   template<typename _Tp>
699     __gthread_once_t __mt_alloc<_Tp>::_S_once = __GTHREAD_ONCE_INIT;
700 
701   template<typename _Tp>
702     typename __mt_alloc<_Tp>::_Thread_record*
703     volatile __mt_alloc<_Tp>::_S_thread_freelist_first = NULL;
704 
705   template<typename _Tp>
706     __gthread_key_t __mt_alloc<_Tp>::_S_thread_key;
707 
708   template<typename _Tp>
709     __gthread_mutex_t
710 #ifdef __GTHREAD_MUTEX_INIT
711     __mt_alloc<_Tp>::_S_thread_freelist_mutex = __GTHREAD_MUTEX_INIT;
712 #else
713     __mt_alloc<_Tp>::_S_thread_freelist_mutex;
714 #endif
715 #endif
716 } // namespace __gnu_cxx
717 
718 #endif
719