This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
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