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


On Thu, 2004-06-10 at 00:00, Paolo Carlini wrote:
> 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...

Yes! It's fine now. The application which was suffering is now using
much lesser memory.

Thanks.


> ////////////////
> 
> ______________________________________________________________________
> 
> 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>;
-- 
        -Dhruv Matani.
http://www.geocities.com/dhruvbird/

Proud to be a Vegetarian.
http://www.vegetarianstarterkit.com/
http://www.vegkids.com/vegkids/index.html



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