Bring in a trimmed down gcc-3.4-20040618.
[dragonfly.git] / contrib / gcc-3.4 / libstdc++-v3 / include / ext / mt_allocator.h
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         // Allocation requests (after round-up to power of 2) below
122         // this value will be handled by the allocator. A raw new/
123         // call will be used for requests larger than this value.
124         size_t  _M_max_bytes; 
125
126         // Size in bytes of the smallest bin (must be a power of 2).
127         size_t  _M_min_bin;
128
129         // In order to avoid fragmenting and minimize the number of
130         // new() calls we always request new memory using this
131         // value. Based on previous discussions on the libstdc++
132         // mailing list we have choosen the value below.
133         // See http://gcc.gnu.org/ml/libstdc++/2001-07/msg00077.html
134         size_t  _M_chunk_size;
135
136         // The maximum number of supported threads. Our Linux 2.4.18
137         // reports 4070 in /proc/sys/kernel/threads-max
138         size_t  _M_max_threads;
139
140         // Each time a deallocation occurs in a threaded application
141         // we make sure that there are no more than
142         // _M_freelist_headroom % of used memory on the freelist. If
143         // the number of additional records is more than
144         // _M_freelist_headroom % of the freelist, we move these
145         // records back to the global pool.
146         size_t  _M_freelist_headroom;
147
148         // Set to true forces all allocations to use new().
149         bool    _M_force_new; 
150      
151         explicit
152         _Tune()
153         : _M_max_bytes(128), _M_min_bin(8),
154           _M_chunk_size(4096 - 4 * sizeof(void*)), 
155           _M_max_threads(4096), _M_freelist_headroom(10), 
156           _M_force_new(getenv("GLIBCXX_FORCE_NEW") ? true : false)
157         { }
158
159         explicit
160         _Tune(size_t __maxb, size_t __minbin, size_t __chunk,
161               size_t __maxthreads, size_t __headroom, bool __force) 
162         : _M_max_bytes(__maxb), _M_min_bin(__minbin), _M_chunk_size(__chunk), 
163           _M_max_threads(__maxthreads), _M_freelist_headroom(__headroom), 
164           _M_force_new(__force)
165         { }
166       };
167
168     private:
169       // We need to create the initial lists and set up some variables
170       // before we can answer to the first request for memory.
171 #ifdef __GTHREADS
172       static __gthread_once_t           _S_once;
173 #endif
174       static bool                       _S_init;
175
176       static void
177       _S_initialize();
178
179       // Configuration options.
180       static _Tune                      _S_options;
181
182       static const _Tune
183       _S_get_options()
184       { return _S_options; }
185
186       static void
187       _S_set_options(_Tune __t)
188       { 
189         if (!_S_init)
190           _S_options = __t;
191       }
192
193       // Using short int as type for the binmap implies we are never
194       // caching blocks larger than 65535 with this allocator
195       typedef unsigned short int        _Binmap_type;
196       static _Binmap_type*              _S_binmap;
197
198       // Each requesting thread is assigned an id ranging from 1 to
199       // _S_max_threads. Thread id 0 is used as a global memory pool.
200       // In order to get constant performance on the thread assignment
201       // routine, we keep a list of free ids. When a thread first
202       // requests memory we remove the first record in this list and
203       // stores the address in a __gthread_key. When initializing the
204       // __gthread_key we specify a destructor. When this destructor
205       // (i.e. the thread dies) is called, we return the thread id to
206       // the front of this list.
207 #ifdef __GTHREADS
208       struct _Thread_record
209       {
210         // Points to next free thread id record. NULL if last record in list.
211         _Thread_record* volatile        _M_next;
212
213         // Thread id ranging from 1 to _S_max_threads.
214         size_t                          _M_id;
215       };
216
217       static _Thread_record* volatile   _S_thread_freelist_first;
218       static __gthread_mutex_t          _S_thread_freelist_mutex;
219       static __gthread_key_t            _S_thread_key;
220
221       static void 
222       _S_destroy_thread_key(void* __freelist_pos);
223 #endif
224
225       static size_t 
226       _S_get_thread_id();
227
228       union _Block_record
229       {
230         // Points to the block_record of the next free block.
231         _Block_record* volatile         _M_next;
232
233 #ifdef __GTHREADS
234         // The thread id of the thread which has requested this block.
235         size_t                          _M_thread_id;
236 #endif
237       };
238
239       struct _Bin_record
240       {
241         // An "array" of pointers to the first free block for each
242         // thread id. Memory to this "array" is allocated in _S_initialize()
243         // for _S_max_threads + global pool 0.
244         _Block_record** volatile        _M_first;
245
246 #ifdef __GTHREADS
247         // An "array" of counters used to keep track of the amount of
248         // blocks that are on the freelist/used for each thread id.
249         // Memory to these "arrays" is allocated in _S_initialize() for
250         // _S_max_threads + global pool 0.
251         size_t* volatile                _M_free;
252         size_t* volatile                _M_used;
253
254         // Each bin has its own mutex which is used to ensure data
255         // integrity while changing "ownership" on a block.  The mutex
256         // is initialized in _S_initialize().
257         __gthread_mutex_t*              _M_mutex;
258 #endif
259       };
260
261       // An "array" of bin_records each of which represents a specific
262       // power of 2 size. Memory to this "array" is allocated in
263       // _S_initialize().
264       static _Bin_record* volatile      _S_bin;
265
266       // Actual value calculated in _S_initialize().
267       static size_t                     _S_bin_size; 
268     };
269
270   template<typename _Tp>
271     typename __mt_alloc<_Tp>::pointer
272     __mt_alloc<_Tp>::
273     allocate(size_type __n, const void*)
274     {
275       // Although the test in __gthread_once() would suffice, we wrap
276       // test of the once condition in our own unlocked check. This
277       // saves one function call to pthread_once() (which itself only
278       // tests for the once value unlocked anyway and immediately
279       // returns if set)
280       if (!_S_init)
281         {
282 #ifdef __GTHREADS
283           if (__gthread_active_p())
284             __gthread_once(&_S_once, _S_initialize);
285 #endif
286           if (!_S_init)
287             _S_initialize();
288         }
289       
290       // Requests larger than _M_max_bytes are handled by new/delete
291       // directly.
292       const size_t __bytes = __n * sizeof(_Tp);
293       if (__bytes > _S_options._M_max_bytes || _S_options._M_force_new)
294         {
295           void* __ret = ::operator new(__bytes);
296           return static_cast<_Tp*>(__ret);
297         }
298
299       // Round up to power of 2 and figure out which bin to use.
300       const size_t __which = _S_binmap[__bytes];      
301       const size_t __thread_id = _S_get_thread_id();
302       
303       // Find out if we have blocks on our freelist.  If so, go ahead
304       // and use them directly without having to lock anything.
305       const _Bin_record& __bin = _S_bin[__which];
306       _Block_record* __block = NULL;
307       if (__bin._M_first[__thread_id] == NULL)
308         {
309           const size_t __bin_size = ((_S_options._M_min_bin << __which)
310                                      + sizeof(_Block_record));
311           size_t __block_count = _S_options._M_chunk_size / __bin_size;   
312
313           // Are we using threads?
314           // - Yes, check if there are free blocks on the global
315           //   list. If so, grab up to __block_count blocks in one
316           //   lock and change ownership. If the global list is 
317           //   empty, we allocate a new chunk and add those blocks 
318           //   directly to our own freelist (with us as owner).
319           // - No, all operations are made directly to global pool 0
320           //   no need to lock or change ownership but check for free
321           //   blocks on global list (and if not add new ones) and
322           //   get the first one.
323 #ifdef __GTHREADS
324           if (__gthread_active_p())
325             {
326               __gthread_mutex_lock(__bin._M_mutex);
327               if (__bin._M_first[0] == NULL)
328                 {
329                   // No need to hold the lock when we are adding a
330                   // whole chunk to our own list.
331                   __gthread_mutex_unlock(__bin._M_mutex);
332                   
333                   void* __v = ::operator new(_S_options._M_chunk_size);
334                   __bin._M_first[__thread_id] = static_cast<_Block_record*>(__v);
335                   __bin._M_free[__thread_id] = __block_count;
336
337                   --__block_count;
338                   __block = __bin._M_first[__thread_id];
339                   while (__block_count-- > 0)
340                     {
341                       char* __c = reinterpret_cast<char*>(__block) + __bin_size;
342                       __block->_M_next = reinterpret_cast<_Block_record*>(__c);
343                       __block = __block->_M_next;
344                     }
345                   __block->_M_next = NULL;
346                 }
347               else
348                 {
349                   // Is the number of required blocks greater than or
350                   // equal to the number that can be provided by the
351                   // global free list?
352                   __bin._M_first[__thread_id] = __bin._M_first[0];
353                   if (__block_count >= __bin._M_free[0])
354                     {
355                       __bin._M_free[__thread_id] = __bin._M_free[0];
356                       __bin._M_free[0] = 0;
357                       __bin._M_first[0] = NULL;
358                     }
359                   else
360                     {
361                       __bin._M_free[__thread_id] = __block_count;
362                       __bin._M_free[0] -= __block_count;
363                       --__block_count;
364                       __block = __bin._M_first[0];
365                       while (__block_count-- > 0)
366                         __block = __block->_M_next;
367                       __bin._M_first[0] = __block->_M_next;
368                       __block->_M_next = NULL;
369                     }
370                   __gthread_mutex_unlock(__bin._M_mutex);
371                 }
372             }
373           else
374 #endif
375             {
376               void* __v = ::operator new(_S_options._M_chunk_size);
377               __bin._M_first[0] = static_cast<_Block_record*>(__v);
378               
379               --__block_count;
380               __block = __bin._M_first[0];
381               while (__block_count-- > 0)
382                 {
383                   char* __c = reinterpret_cast<char*>(__block) + __bin_size;
384                   __block->_M_next = reinterpret_cast<_Block_record*>(__c);
385                   __block = __block->_M_next;
386                 }
387               __block->_M_next = NULL;
388             }
389         }
390
391       __block = __bin._M_first[__thread_id];
392       __bin._M_first[__thread_id] = __bin._M_first[__thread_id]->_M_next;
393 #ifdef __GTHREADS
394       if (__gthread_active_p())
395         {
396           __block->_M_thread_id = __thread_id;
397           --__bin._M_free[__thread_id];
398           ++__bin._M_used[__thread_id];
399         }
400 #endif
401
402       char* __c = reinterpret_cast<char*>(__block) + sizeof(_Block_record);
403       return static_cast<_Tp*>(static_cast<void*>(__c));
404     }
405   
406   template<typename _Tp>
407     void
408     __mt_alloc<_Tp>::
409     deallocate(pointer __p, size_type __n)
410     {
411       // Requests larger than _M_max_bytes are handled by operators
412       // new/delete directly.
413       const size_t __bytes = __n * sizeof(_Tp);
414       if (__bytes > _S_options._M_max_bytes || _S_options._M_force_new)
415         {
416           ::operator delete(__p);
417           return;
418         }
419       
420       // Round up to power of 2 and figure out which bin to use.
421       const size_t __which = _S_binmap[__bytes];
422       const _Bin_record& __bin = _S_bin[__which];
423
424       char* __c = reinterpret_cast<char*>(__p) - sizeof(_Block_record);
425       _Block_record* __block = reinterpret_cast<_Block_record*>(__c);
426       
427 #ifdef __GTHREADS
428       if (__gthread_active_p())
429         {
430           // Calculate the number of records to remove from our freelist:
431           // in order to avoid too much contention we wait until the
432           // number of records is "high enough".
433           const size_t __thread_id = _S_get_thread_id();
434
435           long __remove = ((__bin._M_free[__thread_id]
436                             * _S_options._M_freelist_headroom)
437                            - __bin._M_used[__thread_id]);
438           if (__remove > static_cast<long>(100 * (_S_bin_size - __which)
439                                            * _S_options._M_freelist_headroom)
440               && __remove > static_cast<long>(__bin._M_free[__thread_id]))
441             {
442               _Block_record* __tmp = __bin._M_first[__thread_id];
443               _Block_record* __first = __tmp;
444               __remove /= _S_options._M_freelist_headroom;
445               const long __removed = __remove;
446               --__remove;
447               while (__remove-- > 0)
448                 __tmp = __tmp->_M_next;
449               __bin._M_first[__thread_id] = __tmp->_M_next;
450               __bin._M_free[__thread_id] -= __removed;
451
452               __gthread_mutex_lock(__bin._M_mutex);
453               __tmp->_M_next = __bin._M_first[0];
454               __bin._M_first[0] = __first;
455               __bin._M_free[0] += __removed;
456               __gthread_mutex_unlock(__bin._M_mutex);
457             }
458           
459           // Return this block to our list and update counters and
460           // owner id as needed.
461           --__bin._M_used[__block->_M_thread_id];
462
463           __block->_M_next = __bin._M_first[__thread_id];
464           __bin._M_first[__thread_id] = __block;
465           
466           ++__bin._M_free[__thread_id];
467         }
468       else
469 #endif
470         {
471           // Single threaded application - return to global pool.
472           __block->_M_next = __bin._M_first[0];
473           __bin._M_first[0] = __block;
474         }
475     }
476   
477   template<typename _Tp>
478     void
479     __mt_alloc<_Tp>::
480     _S_initialize()
481     {
482       if (_S_options._M_force_new)
483         return;
484
485       // Calculate the number of bins required based on _M_max_bytes.
486       // _S_bin_size is statically-initialized to one.
487       size_t __bin_size = _S_options._M_min_bin;
488       while (_S_options._M_max_bytes > __bin_size)
489         {
490           __bin_size <<= 1;
491           ++_S_bin_size;
492         }
493
494       // Setup the bin map for quick lookup of the relevant bin.
495       const size_t __j = (_S_options._M_max_bytes + 1) * sizeof(_Binmap_type);
496       _S_binmap = static_cast<_Binmap_type*>(::operator new(__j));
497
498       _Binmap_type* __bp = _S_binmap;
499       _Binmap_type __bin_max = _S_options._M_min_bin;
500       _Binmap_type __bint = 0;
501       for (_Binmap_type __ct = 0; __ct <= _S_options._M_max_bytes; ++__ct)
502         {
503           if (__ct > __bin_max)
504             {
505               __bin_max <<= 1;
506               ++__bint;
507             }
508           *__bp++ = __bint;
509         }
510
511       // Initialize _S_bin and its members.
512       void* __v = ::operator new(sizeof(_Bin_record) * _S_bin_size);
513       _S_bin = static_cast<_Bin_record*>(__v);
514
515       // If __gthread_active_p() create and initialize the list of
516       // free thread ids. Single threaded applications use thread id 0
517       // directly and have no need for this.
518 #ifdef __GTHREADS
519       if (__gthread_active_p())
520         {
521           const size_t __k = sizeof(_Thread_record) * _S_options._M_max_threads;
522           __v = ::operator new(__k);
523           _S_thread_freelist_first = static_cast<_Thread_record*>(__v);
524
525           // NOTE! The first assignable thread id is 1 since the
526           // global pool uses id 0
527           size_t __i;
528           for (__i = 1; __i < _S_options._M_max_threads; ++__i)
529             {
530               _Thread_record& __tr = _S_thread_freelist_first[__i - 1];
531               __tr._M_next = &_S_thread_freelist_first[__i];
532               __tr._M_id = __i;
533             }
534
535           // Set last record.
536           _S_thread_freelist_first[__i - 1]._M_next = NULL;
537           _S_thread_freelist_first[__i - 1]._M_id = __i;
538
539           // Make sure this is initialized.
540 #ifndef __GTHREAD_MUTEX_INIT
541           __GTHREAD_MUTEX_INIT_FUNCTION(&_S_thread_freelist_mutex);
542 #endif
543           // Initialize per thread key to hold pointer to
544           // _S_thread_freelist.
545           __gthread_key_create(&_S_thread_key, _S_destroy_thread_key);
546
547           const size_t __max_threads = _S_options._M_max_threads + 1;
548           for (size_t __n = 0; __n < _S_bin_size; ++__n)
549             {
550               _Bin_record& __bin = _S_bin[__n];
551               __v = ::operator new(sizeof(_Block_record*) * __max_threads);
552               __bin._M_first = static_cast<_Block_record**>(__v);
553
554               __v = ::operator new(sizeof(size_t) * __max_threads);
555               __bin._M_free = static_cast<size_t*>(__v);
556
557               __v = ::operator new(sizeof(size_t) * __max_threads);
558               __bin._M_used = static_cast<size_t*>(__v);
559
560               __v = ::operator new(sizeof(__gthread_mutex_t));
561               __bin._M_mutex = static_cast<__gthread_mutex_t*>(__v);
562
563 #ifdef __GTHREAD_MUTEX_INIT
564               {
565                 // Do not copy a POSIX/gthr mutex once in use.
566                 __gthread_mutex_t __tmp = __GTHREAD_MUTEX_INIT;
567                 *__bin._M_mutex = __tmp;
568               }
569 #else
570               { __GTHREAD_MUTEX_INIT_FUNCTION(__bin._M_mutex); }
571 #endif
572
573               for (size_t __threadn = 0; __threadn < __max_threads;
574                    ++__threadn)
575                 {
576                   __bin._M_first[__threadn] = NULL;
577                   __bin._M_free[__threadn] = 0;
578                   __bin._M_used[__threadn] = 0;
579                 }
580             }
581         }
582       else
583 #endif  
584         for (size_t __n = 0; __n < _S_bin_size; ++__n)
585           {
586             _Bin_record& __bin = _S_bin[__n];
587             __v = ::operator new(sizeof(_Block_record*));
588             __bin._M_first = static_cast<_Block_record**>(__v);
589             __bin._M_first[0] = NULL;
590           }
591
592       _S_init = true;
593     }
594
595   template<typename _Tp>
596     size_t
597     __mt_alloc<_Tp>::
598     _S_get_thread_id()
599     {
600 #ifdef __GTHREADS
601       // If we have thread support and it's active we check the thread
602       // key value and return its id or if it's not set we take the
603       // first record from _S_thread_freelist and sets the key and
604       // returns it's id.
605       if (__gthread_active_p())
606         {
607           _Thread_record* __freelist_pos =
608             static_cast<_Thread_record*>(__gthread_getspecific(_S_thread_key)); 
609           if (__freelist_pos == NULL)
610             {
611               // Since _S_options._M_max_threads must be larger than
612               // the theoretical max number of threads of the OS the
613               // list can never be empty.
614               __gthread_mutex_lock(&_S_thread_freelist_mutex);
615               __freelist_pos = _S_thread_freelist_first;
616               _S_thread_freelist_first = _S_thread_freelist_first->_M_next;
617               __gthread_mutex_unlock(&_S_thread_freelist_mutex);
618
619               __gthread_setspecific(_S_thread_key, 
620                                     static_cast<void*>(__freelist_pos));
621             }
622           return __freelist_pos->_M_id;
623         }
624 #endif
625       // Otherwise (no thread support or inactive) all requests are
626       // served from the global pool 0.
627       return 0;
628     }
629
630 #ifdef __GTHREADS
631   template<typename _Tp>
632     void
633     __mt_alloc<_Tp>::
634     _S_destroy_thread_key(void* __freelist_pos)
635     {
636       // Return this thread id record to front of thread_freelist.
637       __gthread_mutex_lock(&_S_thread_freelist_mutex);
638       _Thread_record* __tr = static_cast<_Thread_record*>(__freelist_pos);
639       __tr->_M_next = _S_thread_freelist_first;
640       _S_thread_freelist_first = __tr;
641       __gthread_mutex_unlock(&_S_thread_freelist_mutex);
642     }
643 #endif
644
645   template<typename _Tp>
646     inline bool
647     operator==(const __mt_alloc<_Tp>&, const __mt_alloc<_Tp>&)
648     { return true; }
649   
650   template<typename _Tp>
651     inline bool
652     operator!=(const __mt_alloc<_Tp>&, const __mt_alloc<_Tp>&)
653     { return false; }
654
655   template<typename _Tp> 
656     bool __mt_alloc<_Tp>::_S_init = false;
657
658   template<typename _Tp> 
659     typename __mt_alloc<_Tp>::_Tune __mt_alloc<_Tp>::_S_options;
660
661   template<typename _Tp> 
662     typename __mt_alloc<_Tp>::_Binmap_type* __mt_alloc<_Tp>::_S_binmap;
663
664   template<typename _Tp> 
665     typename __mt_alloc<_Tp>::_Bin_record* volatile __mt_alloc<_Tp>::_S_bin;
666
667   template<typename _Tp> 
668     size_t __mt_alloc<_Tp>::_S_bin_size = 1;
669
670   // Actual initialization in _S_initialize().
671 #ifdef __GTHREADS
672   template<typename _Tp> 
673     __gthread_once_t __mt_alloc<_Tp>::_S_once = __GTHREAD_ONCE_INIT;
674
675   template<typename _Tp> 
676     typename __mt_alloc<_Tp>::_Thread_record*
677     volatile __mt_alloc<_Tp>::_S_thread_freelist_first = NULL;
678
679   template<typename _Tp> 
680     __gthread_key_t __mt_alloc<_Tp>::_S_thread_key;
681
682   template<typename _Tp> 
683     __gthread_mutex_t
684 #ifdef __GTHREAD_MUTEX_INIT
685     __mt_alloc<_Tp>::_S_thread_freelist_mutex = __GTHREAD_MUTEX_INIT;
686 #else
687     __mt_alloc<_Tp>::_S_thread_freelist_mutex;
688 #endif
689 #endif
690 } // namespace __gnu_cxx
691
692 #endif