This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: patch: mt_allocator.h


Dhruv Matani wrote:

Whatever. Don't bother sending another patch for this minor issue. I

will play a bit myself with the current one (looks ok)

Thanks!

Ok, the below is what I have tested check/check-performance on x86 and x86-64 (4-way).

The most relevant changes:

 1- Everything is inside the implementation struct __mt_base.
 2- In order to deal with multiple definitions issues, I used
    a trick that I (re-)learned from Wolfgang Bangerth: __mt_base
    has a dummy template parameter enforcing weak linkage.

All in all, the current general design is consistent with that of
pool_allocator. Also checked that the performance are not impacted
negatively in any way, of course. On the other hand, I concur that
the memory overhead should be much improved in real applications.

I'm thinking of committing to mainline tomorrow: please have a
look...

Thanks,
Paolo.

////////////////
2004-06-09  Dhruv Matani  <dhruvbird@gmx.net>
	    Paolo Carlini  <pcarlini@suse.de>
	
	* include/ext/mt_allocator.h: Convert to type-less free-lists:
	move the implementation details to struct __mt_base, from
	which __mt_alloc derives.
	* src/allocator.cc: Instantiate __mt_base.
diff -prN libstdc++-v3-orig/include/ext/mt_allocator.h libstdc++-v3/include/ext/mt_allocator.h
*** libstdc++-v3-orig/include/ext/mt_allocator.h	Tue May 18 17:58:33 2004
--- libstdc++-v3/include/ext/mt_allocator.h	Wed Jun  9 18:47:03 2004
***************
*** 43,119 ****
  
  namespace __gnu_cxx
  {
!   /**
!    *  This is a fixed size (power of 2) allocator which - when
!    *  compiled with thread support - will maintain one freelist per
!    *  size per thread plus a "global" one. Steps are taken to limit
!    *  the per thread freelist sizes (by returning excess back to
!    *  "global").
!    *
!    *  Further details:
!    *  http://gcc.gnu.org/onlinedocs/libstdc++/ext/mt_allocator.html
!    */
!   template<typename _Tp>
!     class __mt_alloc
      {
-     public:
-       typedef size_t                    size_type;
-       typedef ptrdiff_t                 difference_type;
-       typedef _Tp*                      pointer;
-       typedef const _Tp*                const_pointer;
-       typedef _Tp&                      reference;
-       typedef const _Tp&                const_reference;
-       typedef _Tp                       value_type;
- 
-       template<typename _Tp1>
-         struct rebind
-         { typedef __mt_alloc<_Tp1> other; };
- 
-       __mt_alloc() throw() 
-       {
- 	// XXX
-       }
- 
-       __mt_alloc(const __mt_alloc&) throw() 
-       {
- 	// XXX
-       }
- 
-       template<typename _Tp1>
-         __mt_alloc(const __mt_alloc<_Tp1>& obj) throw()  
-         {
- 	  // XXX
- 	}
- 
-       ~__mt_alloc() throw() { }
- 
-       pointer
-       address(reference __x) const
-       { return &__x; }
- 
-       const_pointer
-       address(const_reference __x) const
-       { return &__x; }
- 
-       size_type
-       max_size() const throw() 
-       { return size_t(-1) / sizeof(_Tp); }
- 
-       // _GLIBCXX_RESOLVE_LIB_DEFECTS
-       // 402. wrong new expression in [some_] allocator::construct
-       void 
-       construct(pointer __p, const _Tp& __val) 
-       { ::new(__p) _Tp(__val); }
- 
-       void 
-       destroy(pointer __p) { __p->~_Tp(); }
- 
-       pointer
-       allocate(size_type __n, const void* = 0);
- 
-       void
-       deallocate(pointer __p, size_type __n);
- 
        // Variables used to configure the behavior of the allocator,
        // assigned and explained in detail below.
        struct _Tune
--- 43,51 ----
  
  namespace __gnu_cxx
  {
!   template<bool __dummy>
!     struct __mt_base
      {
        // Variables used to configure the behavior of the allocator,
        // assigned and explained in detail below.
        struct _Tune
*************** namespace __gnu_cxx
*** 121,141 ****
  	// Allocation requests (after round-up to power of 2) below
  	// this value will be handled by the allocator. A raw new/
  	// call will be used for requests larger than this value.
! 	size_t	_M_max_bytes; 
! 
  	// Size in bytes of the smallest bin (must be a power of 2).
! 	size_t  _M_min_bin;
! 
  	// In order to avoid fragmenting and minimize the number of
  	// new() calls we always request new memory using this
  	// value. Based on previous discussions on the libstdc++
  	// mailing list we have choosen the value below.
  	// See http://gcc.gnu.org/ml/libstdc++/2001-07/msg00077.html
! 	size_t 	_M_chunk_size;
! 
  	// The maximum number of supported threads. Our Linux 2.4.18
  	// reports 4070 in /proc/sys/kernel/threads-max
! 	size_t 	_M_max_threads;
  
  	// Each time a deallocation occurs in a threaded application
  	// we make sure that there are no more than
--- 53,73 ----
  	// Allocation requests (after round-up to power of 2) below
  	// this value will be handled by the allocator. A raw new/
  	// call will be used for requests larger than this value.
! 	size_t	  _M_max_bytes; 
! 	
  	// Size in bytes of the smallest bin (must be a power of 2).
! 	size_t    _M_min_bin;
! 	
  	// In order to avoid fragmenting and minimize the number of
  	// new() calls we always request new memory using this
  	// value. Based on previous discussions on the libstdc++
  	// mailing list we have choosen the value below.
  	// See http://gcc.gnu.org/ml/libstdc++/2001-07/msg00077.html
! 	size_t 	  _M_chunk_size;
!       
  	// The maximum number of supported threads. Our Linux 2.4.18
  	// reports 4070 in /proc/sys/kernel/threads-max
! 	size_t 	  _M_max_threads;
  
  	// Each time a deallocation occurs in a threaded application
  	// we make sure that there are no more than
*************** namespace __gnu_cxx
*** 143,152 ****
  	// the number of additional records is more than
  	// _M_freelist_headroom % of the freelist, we move these
  	// records back to the global pool.
! 	size_t 	_M_freelist_headroom;
  
  	// Set to true forces all allocations to use new().
! 	bool 	_M_force_new; 
       
  	explicit
  	_Tune()
--- 75,84 ----
  	// the number of additional records is more than
  	// _M_freelist_headroom % of the freelist, we move these
  	// records back to the global pool.
! 	size_t 	  _M_freelist_headroom;
  
  	// Set to true forces all allocations to use new().
! 	bool 	  _M_force_new; 
       
  	explicit
  	_Tune()
*************** namespace __gnu_cxx
*** 158,200 ****
  
  	explicit
  	_Tune(size_t __maxb, size_t __minbin, size_t __chunk,
! 	      size_t __maxthreads, size_t __headroom, bool __force) 
! 	: _M_max_bytes(__maxb), _M_min_bin(__minbin), _M_chunk_size(__chunk), 
  	  _M_max_threads(__maxthreads), _M_freelist_headroom(__headroom), 
  	  _M_force_new(__force)
  	{ }
        };
  
-     private:
        // We need to create the initial lists and set up some variables
        // before we can answer to the first request for memory.
  #ifdef __GTHREADS
        static __gthread_once_t 		_S_once;
  #endif
        static bool 			_S_init;
! 
        static void
        _S_initialize();
! 
        // Configuration options.
        static _Tune 	       		_S_options;
! 
        static const _Tune
        _S_get_options()
        { return _S_options; }
! 
        static void
        _S_set_options(_Tune __t)
        { 
  	if (!_S_init)
  	  _S_options = __t;
        }
! 
        // Using short int as type for the binmap implies we are never
        // caching blocks larger than 65535 with this allocator
!       typedef unsigned short int        _Binmap_type;
!       static _Binmap_type* 		_S_binmap;
! 
        // Each requesting thread is assigned an id ranging from 1 to
        // _S_max_threads. Thread id 0 is used as a global memory pool.
        // In order to get constant performance on the thread assignment
--- 90,131 ----
  
  	explicit
  	_Tune(size_t __maxb, size_t __minbin, size_t __chunk,
! 	      size_t __maxthreads, size_t __headroom, bool __force)
! 	: _M_max_bytes(__maxb), _M_min_bin(__minbin), _M_chunk_size(__chunk),
  	  _M_max_threads(__maxthreads), _M_freelist_headroom(__headroom), 
  	  _M_force_new(__force)
  	{ }
        };
  
        // We need to create the initial lists and set up some variables
        // before we can answer to the first request for memory.
  #ifdef __GTHREADS
        static __gthread_once_t 		_S_once;
  #endif
        static bool 			_S_init;
!       
        static void
        _S_initialize();
!       
        // Configuration options.
        static _Tune 	       		_S_options;
!       
        static const _Tune
        _S_get_options()
        { return _S_options; }
!       
        static void
        _S_set_options(_Tune __t)
        { 
  	if (!_S_init)
  	  _S_options = __t;
        }
!       
        // Using short int as type for the binmap implies we are never
        // caching blocks larger than 65535 with this allocator
!       typedef unsigned short int          _Binmap_type;
!       static _Binmap_type* 	          _S_binmap;
!       
        // Each requesting thread is assigned an id ranging from 1 to
        // _S_max_threads. Thread id 0 is used as a global memory pool.
        // In order to get constant performance on the thread assignment
*************** namespace __gnu_cxx
*** 207,238 ****
  #ifdef __GTHREADS
        struct _Thread_record
        {
!         // Points to next free thread id record. NULL if last record in list.
!         _Thread_record* volatile        _M_next;
! 
  	// Thread id ranging from 1 to _S_max_threads.
!         size_t                          _M_id;
        };
  
!       static _Thread_record* volatile 	_S_thread_freelist_first;
!       static __gthread_mutex_t 		_S_thread_freelist_mutex;
!       static __gthread_key_t 		_S_thread_key;
! 
        static void 
        _S_destroy_thread_key(void* __freelist_pos);
  #endif
  
        static size_t 
!       _S_get_thread_id();
! 
        union _Block_record
        {
  	// Points to the block_record of the next free block.
!         _Block_record* volatile         _M_next;
! 
  #ifdef __GTHREADS
  	// The thread id of the thread which has requested this block.
!         size_t                          _M_thread_id;
  #endif
        };
  
--- 138,169 ----
  #ifdef __GTHREADS
        struct _Thread_record
        {
! 	// Points to next free thread id record. NULL if last record in list.
! 	_Thread_record* volatile          _M_next;
! 	
  	// Thread id ranging from 1 to _S_max_threads.
! 	size_t                            _M_id;
        };
  
!       static _Thread_record* volatile     _S_thread_freelist_first;
!       static __gthread_mutex_t 	          _S_thread_freelist_mutex;
!       static __gthread_key_t 	          _S_thread_key;
!       
        static void 
        _S_destroy_thread_key(void* __freelist_pos);
  #endif
  
        static size_t 
!       _S_get_thread_id();    
!       
        union _Block_record
        {
  	// Points to the block_record of the next free block.
! 	_Block_record* volatile           _M_next;
! 	
  #ifdef __GTHREADS
  	// The thread id of the thread which has requested this block.
! 	size_t                            _M_thread_id;
  #endif
        };
  
*************** namespace __gnu_cxx
*** 241,270 ****
  	// An "array" of pointers to the first free block for each
  	// thread id. Memory to this "array" is allocated in _S_initialize()
  	// for _S_max_threads + global pool 0.
!         _Block_record** volatile        _M_first;
! 
  #ifdef __GTHREADS
  	// An "array" of counters used to keep track of the amount of
  	// blocks that are on the freelist/used for each thread id.
  	// Memory to these "arrays" is allocated in _S_initialize() for
  	// _S_max_threads + global pool 0.
!         size_t* volatile                _M_free;
!         size_t* volatile                _M_used;
! 
  	// Each bin has its own mutex which is used to ensure data
  	// integrity while changing "ownership" on a block.  The mutex
  	// is initialized in _S_initialize().
!         __gthread_mutex_t*              _M_mutex;
  #endif
        };
  
        // An "array" of bin_records each of which represents a specific
        // power of 2 size. Memory to this "array" is allocated in
        // _S_initialize().
!       static _Bin_record* volatile     	_S_bin;
! 
        // Actual value calculated in _S_initialize().
!       static size_t 	       	     	_S_bin_size; 
      };
  
    template<typename _Tp>
--- 172,489 ----
  	// An "array" of pointers to the first free block for each
  	// thread id. Memory to this "array" is allocated in _S_initialize()
  	// for _S_max_threads + global pool 0.
! 	_Block_record** volatile          _M_first;
!       
  #ifdef __GTHREADS
  	// An "array" of counters used to keep track of the amount of
  	// blocks that are on the freelist/used for each thread id.
  	// Memory to these "arrays" is allocated in _S_initialize() for
  	// _S_max_threads + global pool 0.
! 	size_t* volatile                  _M_free;
! 	size_t* volatile                  _M_used;
! 	
  	// Each bin has its own mutex which is used to ensure data
  	// integrity while changing "ownership" on a block.  The mutex
  	// is initialized in _S_initialize().
! 	__gthread_mutex_t*                _M_mutex;
  #endif
        };
  
        // An "array" of bin_records each of which represents a specific
        // power of 2 size. Memory to this "array" is allocated in
        // _S_initialize().
!       static _Bin_record* volatile        _S_bin;
!       
        // Actual value calculated in _S_initialize().
!       static size_t 	       	          _S_bin_size; 
!     };
! 
! #ifdef __GTHREADS
!   template<bool __dummy>
!     void
!     __mt_base<__dummy>::
!     _S_destroy_thread_key(void* __freelist_pos)
!     {
!       // Return this thread id record to front of thread_freelist.
!       __gthread_mutex_lock(&_S_thread_freelist_mutex);
!       _Thread_record* __tr = static_cast<_Thread_record*>(__freelist_pos);
!       __tr->_M_next = _S_thread_freelist_first;
!       _S_thread_freelist_first = __tr;
!       __gthread_mutex_unlock(&_S_thread_freelist_mutex);
!     }
! #endif
! 
!   template<bool __dummy>
!     size_t
!     __mt_base<__dummy>::
!     _S_get_thread_id()
!     {
! #ifdef __GTHREADS
!       // If we have thread support and it's active we check the thread
!       // key value and return its id or if it's not set we take the
!       // first record from _S_thread_freelist and sets the key and
!       // returns it's id.
!       if (__gthread_active_p())
! 	{
! 	  _Thread_record* __freelist_pos =
! 	    static_cast<_Thread_record*>(__gthread_getspecific(_S_thread_key)); 
! 	  if (__freelist_pos == NULL)
! 	    {
! 	      // Since _S_options._M_max_threads must be larger than
! 	      // the theoretical max number of threads of the OS the
! 	      // list can never be empty.
! 	      __gthread_mutex_lock(&_S_thread_freelist_mutex);
! 	      __freelist_pos = _S_thread_freelist_first;
! 	      _S_thread_freelist_first = _S_thread_freelist_first->_M_next;
! 	      __gthread_mutex_unlock(&_S_thread_freelist_mutex);
! 	      
! 	      __gthread_setspecific(_S_thread_key, 
! 				    static_cast<void*>(__freelist_pos));
! 	    }
! 	  return __freelist_pos->_M_id;
! 	}
! #endif
!       // Otherwise (no thread support or inactive) all requests are
!       // served from the global pool 0.
!       return 0;
!     }
! 
!   template<bool __dummy>
!     void
!     __mt_base<__dummy>::
!     _S_initialize()
!     {
!       if (_S_options._M_force_new)
! 	return;
!     
!       // Calculate the number of bins required based on _M_max_bytes.
!       // _S_bin_size is statically-initialized to one.
!       size_t __bin_size = _S_options._M_min_bin;
!       while (_S_options._M_max_bytes > __bin_size)
! 	{
! 	  __bin_size <<= 1;
! 	  ++_S_bin_size;
! 	}
!       
!       // Setup the bin map for quick lookup of the relevant bin.
!       const size_t __j = (_S_options._M_max_bytes + 1) * sizeof(_Binmap_type);
!       _S_binmap = static_cast<_Binmap_type*>(::operator new(__j));
!       
!       _Binmap_type* __bp = _S_binmap;
!       _Binmap_type __bin_max = _S_options._M_min_bin;
!       _Binmap_type __bint = 0;
!       for (_Binmap_type __ct = 0; __ct <= _S_options._M_max_bytes; ++__ct)
! 	{
! 	  if (__ct > __bin_max)
! 	    {
! 	      __bin_max <<= 1;
! 	      ++__bint;
! 	    }
! 	  *__bp++ = __bint;
! 	}
!       
!       // Initialize _S_bin and its members.
!       void* __v = ::operator new(sizeof(_Bin_record) * _S_bin_size);
!       _S_bin = static_cast<_Bin_record*>(__v);
!       
!       // If __gthread_active_p() create and initialize the list of
!       // free thread ids. Single threaded applications use thread id 0
!       // directly and have no need for this.
! #ifdef __GTHREADS
!       if (__gthread_active_p())
! 	{
! 	  const size_t __k = sizeof(_Thread_record) * _S_options._M_max_threads;
! 	  __v = ::operator new(__k);
! 	  _S_thread_freelist_first = static_cast<_Thread_record*>(__v);
! 	  
! 	  // NB: The first assignable thread id is 1 since the
! 	  // global pool uses id 0
! 	  size_t __i;
! 	  for (__i = 1; __i < _S_options._M_max_threads; ++__i)
! 	    {
! 	      _Thread_record& __tr = _S_thread_freelist_first[__i - 1];
! 	      __tr._M_next = &_S_thread_freelist_first[__i];
! 	      __tr._M_id = __i;
! 	    }
! 	  
! 	  // Set last record.
! 	  _S_thread_freelist_first[__i - 1]._M_next = NULL;
! 	  _S_thread_freelist_first[__i - 1]._M_id = __i;
! 	  
! 	  // Make sure this is initialized.
! #ifndef __GTHREAD_MUTEX_INIT
! 	  __GTHREAD_MUTEX_INIT_FUNCTION(&_S_thread_freelist_mutex);
! #endif
! 	  // Initialize per thread key to hold pointer to
! 	  // _S_thread_freelist.
! 	  __gthread_key_create(&_S_thread_key, _S_destroy_thread_key);
! 	
! 	  const size_t __max_threads = _S_options._M_max_threads + 1;
! 	  for (size_t __n = 0; __n < _S_bin_size; ++__n)
! 	    {
! 	      _Bin_record& __bin = _S_bin[__n];
! 	      __v = ::operator new(sizeof(_Block_record*) * __max_threads);
! 	      __bin._M_first = static_cast<_Block_record**>(__v);
! 	      
! 	      __v = ::operator new(sizeof(size_t) * __max_threads);
! 	      __bin._M_free = static_cast<size_t*>(__v);
! 	      
! 	      __v = ::operator new(sizeof(size_t) * __max_threads);
! 	      __bin._M_used = static_cast<size_t*>(__v);
! 	      
! 	      __v = ::operator new(sizeof(__gthread_mutex_t));
! 	      __bin._M_mutex = static_cast<__gthread_mutex_t*>(__v);
! 	      
! #ifdef __GTHREAD_MUTEX_INIT
! 	      {
! 		// Do not copy a POSIX/gthr mutex once in use.
! 		__gthread_mutex_t __tmp = __GTHREAD_MUTEX_INIT;
! 		*__bin._M_mutex = __tmp;
! 	      }
! #else
! 	      { __GTHREAD_MUTEX_INIT_FUNCTION(__bin._M_mutex); }
! #endif
! 	      
! 	      for (size_t __threadn = 0; __threadn < __max_threads;
! 		   ++__threadn)
! 		{
! 		  __bin._M_first[__threadn] = NULL;
! 		  __bin._M_free[__threadn] = 0;
! 		  __bin._M_used[__threadn] = 0;
! 		}
! 	    }
! 	}
!       else
! #endif	
! 	for (size_t __n = 0; __n < _S_bin_size; ++__n)
! 	  {
! 	    _Bin_record& __bin = _S_bin[__n];
! 	    __v = ::operator new(sizeof(_Block_record*));
! 	    __bin._M_first = static_cast<_Block_record**>(__v);
! 	    __bin._M_first[0] = NULL;
! 	  }
!       
!       _S_init = true;
!     }
! 
!   template<bool __dummy>
!     bool
!     __mt_base<__dummy>::_S_init = false;
! 
!   template<bool __dummy>
!     typename __mt_base<__dummy>::_Tune
!     __mt_base<__dummy>::_S_options;
! 
!   template<bool __dummy>
!     typename __mt_base<__dummy>::_Binmap_type*
!     __mt_base<__dummy>::_S_binmap;
! 
!   template<bool __dummy>
!     typename __mt_base<__dummy>::_Bin_record* volatile
!     __mt_base<__dummy>::_S_bin;
! 
!   template<bool __dummy>
!     size_t
!     __mt_base<__dummy>::_S_bin_size = 1;
! 
!   // Actual initialization in _S_initialize().
! #ifdef __GTHREADS
!   template<bool __dummy>
!     __gthread_once_t
!     __mt_base<__dummy>::_S_once = __GTHREAD_ONCE_INIT;
! 
!   template<bool __dummy>
!     typename __mt_base<__dummy>::_Thread_record* volatile
!     __mt_base<__dummy>::_S_thread_freelist_first = NULL;
! 
!   template<bool __dummy>
!     __gthread_key_t
!     __mt_base<__dummy>::_S_thread_key;
! 
!   template<bool __dummy>
!     __gthread_mutex_t
! #ifdef __GTHREAD_MUTEX_INIT
!     __mt_base<__dummy>::_S_thread_freelist_mutex = __GTHREAD_MUTEX_INIT;
! #else
!     __mt_base<__dummy>::_S_thread_freelist_mutex;
! #endif
! #endif
! 
!   typedef __mt_base<true> __mt_alloc_base;
! 
!   /**
!    *  This is a fixed size (power of 2) allocator which - when
!    *  compiled with thread support - will maintain one freelist per
!    *  size per thread plus a "global" one. Steps are taken to limit
!    *  the per thread freelist sizes (by returning excess back to
!    *  "global").
!    *
!    *  Further details:
!    *  http://gcc.gnu.org/onlinedocs/libstdc++/ext/mt_allocator.html
!    */
!   template<typename _Tp>
!     class __mt_alloc : private __mt_alloc_base
!     {
!     public:
!       typedef size_t                    size_type;
!       typedef ptrdiff_t                 difference_type;
!       typedef _Tp*                      pointer;
!       typedef const _Tp*                const_pointer;
!       typedef _Tp&                      reference;
!       typedef const _Tp&                const_reference;
!       typedef _Tp                       value_type;
!       
!       template<typename _Tp1>
!         struct rebind
! 	{ typedef __mt_alloc<_Tp1> other; };
!     
!       __mt_alloc() throw() 
!       {
! 	// XXX
!       }
!     
!       __mt_alloc(const __mt_alloc&) throw() 
!       {
! 	// XXX
!       }
! 
!       template<typename _Tp1>
!         __mt_alloc(const __mt_alloc<_Tp1>& obj) throw()  
!         {
! 	  // XXX
! 	}
!     
!       ~__mt_alloc() throw() { }
!     
!       pointer
!       address(reference __x) const
!       { return &__x; }
!       
!       const_pointer
!       address(const_reference __x) const
!       { return &__x; }
!       
!       size_type
!       max_size() const throw() 
!       { return size_t(-1) / sizeof(_Tp); }
!       
!       // _GLIBCXX_RESOLVE_LIB_DEFECTS
!       // 402. wrong new expression in [some_] allocator::construct
!       void 
!       construct(pointer __p, const _Tp& __val) 
!       { ::new(__p) _Tp(__val); }
!       
!       void 
!       destroy(pointer __p) { __p->~_Tp(); }
!       
!       pointer
!       allocate(size_type __n, const void* = 0);
!       
!       void
!       deallocate(pointer __p, size_type __n);
! 
!       using __mt_alloc_base::_S_get_options;
!       using __mt_alloc_base::_S_set_options;
      };
  
    template<typename _Tp>
*************** namespace __gnu_cxx
*** 475,648 ****
      }
    
    template<typename _Tp>
-     void
-     __mt_alloc<_Tp>::
-     _S_initialize()
-     {
-       if (_S_options._M_force_new)
- 	return;
- 
-       // Calculate the number of bins required based on _M_max_bytes.
-       // _S_bin_size is statically-initialized to one.
-       size_t __bin_size = _S_options._M_min_bin;
-       while (_S_options._M_max_bytes > __bin_size)
- 	{
- 	  __bin_size <<= 1;
- 	  ++_S_bin_size;
- 	}
- 
-       // Setup the bin map for quick lookup of the relevant bin.
-       const size_t __j = (_S_options._M_max_bytes + 1) * sizeof(_Binmap_type);
-       _S_binmap = static_cast<_Binmap_type*>(::operator new(__j));
- 
-       _Binmap_type* __bp = _S_binmap;
-       _Binmap_type __bin_max = _S_options._M_min_bin;
-       _Binmap_type __bint = 0;
-       for (_Binmap_type __ct = 0; __ct <= _S_options._M_max_bytes; ++__ct)
-         {
-           if (__ct > __bin_max)
-             {
-               __bin_max <<= 1;
-               ++__bint;
-             }
-           *__bp++ = __bint;
-         }
- 
-       // Initialize _S_bin and its members.
-       void* __v = ::operator new(sizeof(_Bin_record) * _S_bin_size);
-       _S_bin = static_cast<_Bin_record*>(__v);
- 
-       // If __gthread_active_p() create and initialize the list of
-       // free thread ids. Single threaded applications use thread id 0
-       // directly and have no need for this.
- #ifdef __GTHREADS
-       if (__gthread_active_p())
-         {
- 	  const size_t __k = sizeof(_Thread_record) * _S_options._M_max_threads;
- 	  __v = ::operator new(__k);
-           _S_thread_freelist_first = static_cast<_Thread_record*>(__v);
- 
- 	  // NOTE! The first assignable thread id is 1 since the
- 	  // global pool uses id 0
-           size_t __i;
-           for (__i = 1; __i < _S_options._M_max_threads; ++__i)
-             {
- 	      _Thread_record& __tr = _S_thread_freelist_first[__i - 1];
-               __tr._M_next = &_S_thread_freelist_first[__i];
-               __tr._M_id = __i;
-             }
- 
-           // Set last record.
-           _S_thread_freelist_first[__i - 1]._M_next = NULL;
-           _S_thread_freelist_first[__i - 1]._M_id = __i;
- 
- 	  // Make sure this is initialized.
- #ifndef __GTHREAD_MUTEX_INIT
- 	  __GTHREAD_MUTEX_INIT_FUNCTION(&_S_thread_freelist_mutex);
- #endif
-           // Initialize per thread key to hold pointer to
-           // _S_thread_freelist.
-           __gthread_key_create(&_S_thread_key, _S_destroy_thread_key);
- 
- 	  const size_t __max_threads = _S_options._M_max_threads + 1;
- 	  for (size_t __n = 0; __n < _S_bin_size; ++__n)
- 	    {
- 	      _Bin_record& __bin = _S_bin[__n];
- 	      __v = ::operator new(sizeof(_Block_record*) * __max_threads);
- 	      __bin._M_first = static_cast<_Block_record**>(__v);
- 
- 	      __v = ::operator new(sizeof(size_t) * __max_threads);
-               __bin._M_free = static_cast<size_t*>(__v);
- 
- 	      __v = ::operator new(sizeof(size_t) * __max_threads);
-               __bin._M_used = static_cast<size_t*>(__v);
- 
- 	      __v = ::operator new(sizeof(__gthread_mutex_t));
-               __bin._M_mutex = static_cast<__gthread_mutex_t*>(__v);
- 
- #ifdef __GTHREAD_MUTEX_INIT
-               {
-                 // Do not copy a POSIX/gthr mutex once in use.
-                 __gthread_mutex_t __tmp = __GTHREAD_MUTEX_INIT;
-                 *__bin._M_mutex = __tmp;
-               }
- #else
-               { __GTHREAD_MUTEX_INIT_FUNCTION(__bin._M_mutex); }
- #endif
- 
- 	      for (size_t __threadn = 0; __threadn < __max_threads;
- 		   ++__threadn)
- 		{
- 		  __bin._M_first[__threadn] = NULL;
- 		  __bin._M_free[__threadn] = 0;
- 		  __bin._M_used[__threadn] = 0;
- 		}
- 	    }
- 	}
-       else
- #endif	
- 	for (size_t __n = 0; __n < _S_bin_size; ++__n)
- 	  {
- 	    _Bin_record& __bin = _S_bin[__n];
- 	    __v = ::operator new(sizeof(_Block_record*));
- 	    __bin._M_first = static_cast<_Block_record**>(__v);
- 	    __bin._M_first[0] = NULL;
- 	  }
- 
-       _S_init = true;
-     }
- 
-   template<typename _Tp>
-     size_t
-     __mt_alloc<_Tp>::
-     _S_get_thread_id()
-     {
- #ifdef __GTHREADS
-       // If we have thread support and it's active we check the thread
-       // key value and return its id or if it's not set we take the
-       // first record from _S_thread_freelist and sets the key and
-       // returns it's id.
-       if (__gthread_active_p())
-         {
-           _Thread_record* __freelist_pos =
- 	    static_cast<_Thread_record*>(__gthread_getspecific(_S_thread_key)); 
- 	  if (__freelist_pos == NULL)
-             {
- 	      // Since _S_options._M_max_threads must be larger than
- 	      // the theoretical max number of threads of the OS the
- 	      // list can never be empty.
-               __gthread_mutex_lock(&_S_thread_freelist_mutex);
-               __freelist_pos = _S_thread_freelist_first;
-               _S_thread_freelist_first = _S_thread_freelist_first->_M_next;
-               __gthread_mutex_unlock(&_S_thread_freelist_mutex);
- 
-               __gthread_setspecific(_S_thread_key, 
- 				    static_cast<void*>(__freelist_pos));
-             }
-           return __freelist_pos->_M_id;
-         }
- #endif
-       // Otherwise (no thread support or inactive) all requests are
-       // served from the global pool 0.
-       return 0;
-     }
- 
- #ifdef __GTHREADS
-   template<typename _Tp>
-     void
-     __mt_alloc<_Tp>::
-     _S_destroy_thread_key(void* __freelist_pos)
-     {
-       // Return this thread id record to front of thread_freelist.
-       __gthread_mutex_lock(&_S_thread_freelist_mutex);
-       _Thread_record* __tr = static_cast<_Thread_record*>(__freelist_pos);
-       __tr->_M_next = _S_thread_freelist_first;
-       _S_thread_freelist_first = __tr;
-       __gthread_mutex_unlock(&_S_thread_freelist_mutex);
-     }
- #endif
- 
-   template<typename _Tp>
      inline bool
      operator==(const __mt_alloc<_Tp>&, const __mt_alloc<_Tp>&)
      { return true; }
--- 694,699 ----
*************** namespace __gnu_cxx
*** 651,692 ****
      inline bool
      operator!=(const __mt_alloc<_Tp>&, const __mt_alloc<_Tp>&)
      { return false; }
- 
-   template<typename _Tp> 
-     bool __mt_alloc<_Tp>::_S_init = false;
- 
-   template<typename _Tp> 
-     typename __mt_alloc<_Tp>::_Tune __mt_alloc<_Tp>::_S_options;
- 
-   template<typename _Tp> 
-     typename __mt_alloc<_Tp>::_Binmap_type* __mt_alloc<_Tp>::_S_binmap;
- 
-   template<typename _Tp> 
-     typename __mt_alloc<_Tp>::_Bin_record* volatile __mt_alloc<_Tp>::_S_bin;
- 
-   template<typename _Tp> 
-     size_t __mt_alloc<_Tp>::_S_bin_size = 1;
- 
-   // Actual initialization in _S_initialize().
- #ifdef __GTHREADS
-   template<typename _Tp> 
-     __gthread_once_t __mt_alloc<_Tp>::_S_once = __GTHREAD_ONCE_INIT;
- 
-   template<typename _Tp> 
-     typename __mt_alloc<_Tp>::_Thread_record*
-     volatile __mt_alloc<_Tp>::_S_thread_freelist_first = NULL;
- 
-   template<typename _Tp> 
-     __gthread_key_t __mt_alloc<_Tp>::_S_thread_key;
- 
-   template<typename _Tp> 
-     __gthread_mutex_t
- #ifdef __GTHREAD_MUTEX_INIT
-     __mt_alloc<_Tp>::_S_thread_freelist_mutex = __GTHREAD_MUTEX_INIT;
- #else
-     __mt_alloc<_Tp>::_S_thread_freelist_mutex;
- #endif
- #endif
  } // namespace __gnu_cxx
- 
  #endif
--- 702,706 ----
diff -prN libstdc++-v3-orig/src/allocator.cc libstdc++-v3/src/allocator.cc
*** libstdc++-v3-orig/src/allocator.cc	Tue Jun  8 19:17:08 2004
--- libstdc++-v3/src/allocator.cc	Wed Jun  9 17:53:27 2004
*************** namespace __gnu_cxx
*** 43,48 ****
--- 43,50 ----
    template class __mt_alloc<char>;
    template class __mt_alloc<wchar_t>;
  
+   template class __mt_base<true>;
+ 
    // Static members of __pool_alloc.
    template class __pool_alloc<char>;
    template class __pool_alloc<wchar_t>;

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]