source: svn/newcon3bcm2_21bu/toolchain/include/c++/3.4.2/ext/mt_allocator.h

Last change on this file was 76, checked in by megakiss, 10 years ago

1W 대기전력을 만족시키기 위하여 POWEROFF시 튜너를 Standby 상태로 함

  • Property svn:executable set to *
File size: 22.9 KB
Line 
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
44namespace __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
Note: See TracBrowser for help on using the repository browser.