diff options
author | Benjamin Kosnik <bkoz@gcc.gnu.org> | 2005-09-12 04:49:11 +0000 |
---|---|---|
committer | Benjamin Kosnik <bkoz@gcc.gnu.org> | 2005-09-12 04:49:11 +0000 |
commit | 2f9f6cef1cdc149a05754839ca27af001c8d3d1e (patch) | |
tree | 8b5f928c92d3aae14b4285ea94519fe9d16b10f5 /libstdc++-v3 | |
parent | 56b4ea3de8efa797ff0edf9504704803d2ae4981 (diff) | |
download | gcc-2f9f6cef1cdc149a05754839ca27af001c8d3d1e.zip gcc-2f9f6cef1cdc149a05754839ca27af001c8d3d1e.tar.gz gcc-2f9f6cef1cdc149a05754839ca27af001c8d3d1e.tar.bz2 |
[multiple changes]
2005-09-11 Benjamin Kosnik <bkoz@redhat.com>
PR libstdc++/19265
PR libstdc++/22309
* include/ext/mt_allocator.h
(__gnu_cxx::__create_handler): Remove.
(__pool<true>::_M_destroy_thread_key): Compatibility only.
(__pool<true>::_M_initialize(__destroy): Same.
(__pool<true>::_M_initialize): New.
(__pool<true>::_M_initialize_once): Nothing fancy.
(__pool<true>::_M_once): Remove.
(__common_pool): New.
(__common_pool_base): New.
(__per_type_pool): New.
(__per_type_pool_base): New.
* src/mt_allocator.cc: Same.
* config/linker-map.gnu (__pool<true>::_M_initialize()): Add.
2005-09-11 Jakub Jelinek <jakub@redhat.com>
PR libstdc++/19265
PR libstdc++/22309
* src/mt_allocator.cc (__gnu_internal::freelist_mutex): Make static.
(__gnu_internal::__freelist): New type.
(__gnu_internal::freelist): New variable.
(__gnu_internal::_M_destroy_thread_key): New function.
(__gnu_cxx::__pool<true>::_M_destroy): Don't delete
_M_thread_freelist_initial.
(__gnu_cxx::__pool<true>::_M_initialize): Make argument nameless.
Don't use _M_thread_freelist and _M_thread_freelist_initial
__pool<true> fields, instead use __gnu_internal::freelist fields, call
gthread_key_create just once. Use
__gnu_internal::_M_destroy_thread_key as key destructor.
(__gnu_cxx::__pool<true>::_M_get_thread_id): Store size_t id
rather than _Thread_record* in the thread specific value. Don't
use _M_thread_freelist __pool<true> field, instead use
__gnu_internal::freelist fields.
(__gnu_cxx::__pool<true>::_M_destroy_thread_key): Do nothing.
2005-09-11 Benjamin Kosnik <bkoz@redhat.com>
Jakub Jelinek <jakub@redhat.com>
PR libstdc++/19265
PR libstdc++/22309
* testsuite/testsuite_shared.cc: New.
* testsuite/lib/dg-options.exp (dg-require-sharedlib): New.
* testsuite/lib/libstdc++.exp (libstdc++_init): Look for shared
library, and set v3-sharedlib based on this.
(check_v3_target_sharedlib): New.
(proc v3-build_support): Build shared objects.
* testsuite/ext/mt_allocator/22309_thread.cc: New, use above.
From-SVN: r104161
Diffstat (limited to 'libstdc++-v3')
-rw-r--r-- | libstdc++-v3/ChangeLog | 52 | ||||
-rw-r--r-- | libstdc++-v3/config/linker-map.gnu | 6 | ||||
-rw-r--r-- | libstdc++-v3/include/ext/mt_allocator.h | 238 | ||||
-rw-r--r-- | libstdc++-v3/src/mt_allocator.cc | 327 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/ext/mt_allocator/22309_thread.cc | 101 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/lib/dg-options.exp | 9 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/lib/libstdc++.exp | 67 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/testsuite_shared.cc | 36 |
8 files changed, 633 insertions, 203 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index ad1fb5d..cb6c84c 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,55 @@ +2005-09-11 Benjamin Kosnik <bkoz@redhat.com> + + PR libstdc++/19265 + PR libstdc++/22309 + * include/ext/mt_allocator.h + (__gnu_cxx::__create_handler): Remove. + (__pool<true>::_M_destroy_thread_key): Compatibility only. + (__pool<true>::_M_initialize(__destroy): Same. + (__pool<true>::_M_initialize): New. + (__pool<true>::_M_initialize_once): Nothing fancy. + (__pool<true>::_M_once): Remove. + (__common_pool): New. + (__common_pool_base): New. + (__per_type_pool): New. + (__per_type_pool_base): New. + * src/mt_allocator.cc: Same. + * config/linker-map.gnu (__pool<true>::_M_initialize()): Add. + +2005-09-11 Jakub Jelinek <jakub@redhat.com> + + PR libstdc++/19265 + PR libstdc++/22309 + * src/mt_allocator.cc (__gnu_internal::freelist_mutex): Make static. + (__gnu_internal::__freelist): New type. + (__gnu_internal::freelist): New variable. + (__gnu_internal::_M_destroy_thread_key): New function. + (__gnu_cxx::__pool<true>::_M_destroy): Don't delete + _M_thread_freelist_initial. + (__gnu_cxx::__pool<true>::_M_initialize): Make argument nameless. + Don't use _M_thread_freelist and _M_thread_freelist_initial + __pool<true> fields, instead use __gnu_internal::freelist fields, call + gthread_key_create just once. Use + __gnu_internal::_M_destroy_thread_key as key destructor. + (__gnu_cxx::__pool<true>::_M_get_thread_id): Store size_t id + rather than _Thread_record* in the thread specific value. Don't + use _M_thread_freelist __pool<true> field, instead use + __gnu_internal::freelist fields. + (__gnu_cxx::__pool<true>::_M_destroy_thread_key): Do nothing. + +2005-09-11 Benjamin Kosnik <bkoz@redhat.com> + Jakub Jelinek <jakub@redhat.com> + + PR libstdc++/19265 + PR libstdc++/22309 + * testsuite/testsuite_shared.cc: New. + * testsuite/lib/dg-options.exp (dg-require-sharedlib): New. + * testsuite/lib/libstdc++.exp (libstdc++_init): Look for shared + library, and set v3-sharedlib based on this. + (check_v3_target_sharedlib): New. + (proc v3-build_support): Build shared objects. + * testsuite/ext/mt_allocator/22309_thread.cc: New, use above. + 2005-09-11 Paolo Carlini <pcarlini@suse.de> PR libstdc++/23781 diff --git a/libstdc++-v3/config/linker-map.gnu b/libstdc++-v3/config/linker-map.gnu index 3099bfb..eb8fab6 100644 --- a/libstdc++-v3/config/linker-map.gnu +++ b/libstdc++-v3/config/linker-map.gnu @@ -515,8 +515,8 @@ GLIBCXX_3.4.3 { } GLIBCXX_3.4.2; GLIBCXX_3.4.4 { - - _ZN9__gnu_cxx6__poolILb0EE13_M_initializeEv; + + _ZN9__gnu_cxx6__poolILb0EE13_M_initializeEv; _ZN9__gnu_cxx6__poolILb1EE13_M_initializeEPFvPvE; _ZN9__gnu_cxx6__poolILb1EE21_M_destroy_thread_keyEPv; _ZN9__gnu_cxx6__poolILb1EE16_M_get_thread_idEv; @@ -571,6 +571,8 @@ GLIBCXX_3.4.6 { _ZNKSt15basic_stringbufIwSt11char_traitsIwESaIwEE3strEv; + _ZN9__gnu_cxx6__poolILb1EE13_M_initializeEv; + } GLIBCXX_3.4.5; # Symbols in the support library (libsupc++) have their own tag. diff --git a/libstdc++-v3/include/ext/mt_allocator.h b/libstdc++-v3/include/ext/mt_allocator.h index b2cf89b..311e219 100644 --- a/libstdc++-v3/include/ext/mt_allocator.h +++ b/libstdc++-v3/include/ext/mt_allocator.h @@ -43,7 +43,6 @@ namespace __gnu_cxx { typedef void (*__destroy_handler)(void*); - typedef void (*__create_handler)(void); /// @brief Base class for pool object. struct __pool_base @@ -185,12 +184,6 @@ namespace __gnu_cxx template<bool _Thread> class __pool; - template<> - class __pool<true>; - - template<> - class __pool<false>; - /// Specialization for single thread. template<> class __pool<false> : public __pool_base @@ -313,24 +306,15 @@ namespace __gnu_cxx __gthread_mutex_t* _M_mutex; }; + // XXX GLIBCXX_ABI Deprecated void - _M_initialize(__destroy_handler __d); + _M_initialize(__destroy_handler); void - _M_initialize_once(__create_handler __c) + _M_initialize_once() { - // Although the test in __gthread_once() would suffice, we - // wrap test of the once condition in our own unlocked - // check. This saves one function call to pthread_once() - // (which itself only tests for the once value unlocked anyway - // and immediately returns if set) if (__builtin_expect(_M_init == false, false)) - { - if (__gthread_active_p()) - __gthread_once(&_M_once, __c); - if (!_M_init) - __c(); - } + _M_initialize(); } void @@ -358,28 +342,21 @@ namespace __gnu_cxx } } + // XXX GLIBCXX_ABI Deprecated void - _M_destroy_thread_key(void* __freelist_pos); + _M_destroy_thread_key(void*); size_t _M_get_thread_id(); explicit __pool() : _M_bin(NULL), _M_bin_size(1), _M_thread_freelist(NULL) - { - // On some platforms, __gthread_once_t is an aggregate. - __gthread_once_t __tmp = __GTHREAD_ONCE_INIT; - _M_once = __tmp; - } + { } explicit __pool(const __pool_base::_Tune& __tune) : __pool_base(__tune), _M_bin(NULL), _M_bin_size(1), _M_thread_freelist(NULL) - { - // On some platforms, __gthread_once_t is an aggregate. - __gthread_once_t __tmp = __GTHREAD_ONCE_INIT; - _M_once = __tmp; - } + { } private: // An "array" of bin_records each of which represents a specific @@ -390,39 +367,39 @@ namespace __gnu_cxx // Actual value calculated in _M_initialize(). size_t _M_bin_size; - __gthread_once_t _M_once; - _Thread_record* _M_thread_freelist; void* _M_thread_freelist_initial; + + void + _M_initialize(); }; #endif - - /// @brief Policy for shared __pool objects. template<template <bool> class _PoolTp, bool _Thread> - struct __common_pool_policy; - - /// Partial specialization for single thread. - template<template <bool> class _PoolTp> - struct __common_pool_policy<_PoolTp, false> + struct __common_pool { - typedef _PoolTp<false> pool_type; + typedef _PoolTp<_Thread> pool_type; - template<typename _Tp1, template <bool> class _PoolTp1 = _PoolTp, - bool _Thread1 = false> - struct _M_rebind - { typedef __common_pool_policy<_PoolTp1, _Thread1> other; }; - static pool_type& _S_get_pool() { static pool_type _S_pool; return _S_pool; } + }; + + template<template <bool> class _PoolTp, bool _Thread> + struct __common_pool_base; + + template<template <bool> class _PoolTp> + struct __common_pool_base<_PoolTp, false> + : public __common_pool<_PoolTp, false> + { + using __common_pool<_PoolTp, false>::_S_get_pool; static void - _S_initialize_once() - { + _S_initialize_once() + { static bool __init; if (__builtin_expect(__init == false, false)) { @@ -433,76 +410,67 @@ namespace __gnu_cxx }; #ifdef __GTHREADS - /// Partial specialization for thread enabled, via gthreads.h. template<template <bool> class _PoolTp> - struct __common_pool_policy<_PoolTp, true> + struct __common_pool_base<_PoolTp, true> + : public __common_pool<_PoolTp, true> { - typedef _PoolTp<true> pool_type; + using __common_pool<_PoolTp, true>::_S_get_pool; - template<typename _Tp1, template <bool> class _PoolTp1 = _PoolTp, - bool _Thread1 = true> - struct _M_rebind - { typedef __common_pool_policy<_PoolTp1, _Thread1> other; }; - - static pool_type& - _S_get_pool() - { - static pool_type _S_pool; - return _S_pool; - } + static void + _S_initialize() + { _S_get_pool()._M_initialize_once(); } static void - _S_initialize_once() + _S_initialize_once() { static bool __init; if (__builtin_expect(__init == false, false)) { - _S_get_pool()._M_initialize_once(_S_initialize); + if (__gthread_active_p()) + { + // On some platforms, __gthread_once_t is an aggregate. + static __gthread_once_t __once = __GTHREAD_ONCE_INIT; + __gthread_once(&__once, _S_initialize); + } + else + _S_get_pool()._M_initialize_once(); __init = true; } } - - private: - static void - _S_destroy_thread_key(void* __freelist_pos) - { _S_get_pool()._M_destroy_thread_key(__freelist_pos); } - - static void - _S_initialize() - { _S_get_pool()._M_initialize(_S_destroy_thread_key); } - }; + }; #endif - - /// @brief Policy for individual __pool objects. - template<typename _Tp, template <bool> class _PoolTp, bool _Thread> - struct __per_type_pool_policy; - - /// Partial specialization for single thread. - template<typename _Tp, template <bool> class _PoolTp> - struct __per_type_pool_policy<_Tp, _PoolTp, false> + /// @brief Policy for shared __pool objects. + template<template <bool> class _PoolTp, bool _Thread> + struct __common_pool_policy : public __common_pool_base<_PoolTp, _Thread> { - typedef _Tp value_type; - typedef _PoolTp<false> pool_type; - template<typename _Tp1, template <bool> class _PoolTp1 = _PoolTp, - bool _Thread1 = false> + bool _Thread1 = _Thread> struct _M_rebind - { typedef __per_type_pool_policy<_Tp1, _PoolTp1, _Thread1> other; }; + { typedef __common_pool_policy<_PoolTp1, _Thread1> other; }; + using __common_pool_base<_PoolTp, _Thread>::_S_get_pool; + using __common_pool_base<_PoolTp, _Thread>::_S_initialize_once; + }; + + + template<typename _Tp, template <bool> class _PoolTp, bool _Thread> + struct __per_type_pool + { + typedef _Tp value_type; + typedef _PoolTp<_Thread> pool_type; + static pool_type& _S_get_pool() { // Sane defaults for the _PoolTp. typedef typename pool_type::_Block_record _Block_record; - const static size_t __align = (__alignof__(_Tp) >= sizeof(_Block_record) - ? __alignof__(_Tp) - : sizeof(_Block_record)); + const static size_t __a = (__alignof__(_Tp) >= sizeof(_Block_record) + ? __alignof__(_Tp) : sizeof(_Block_record)); typedef typename __pool_base::_Tune _Tune; - static _Tune _S_tune(__align, sizeof(_Tp) * 64, - sizeof(_Tp) * 2 >= __align ? sizeof(_Tp) * 2 - : __align, + static _Tune _S_tune(__a, sizeof(_Tp) * 64, + sizeof(_Tp) * 2 >= __a ? sizeof(_Tp) * 2 : __a, sizeof(_Tp) * size_t(_Tune::_S_chunk_size), _Tune::_S_max_threads, _Tune::_S_freelist_headroom, @@ -510,10 +478,20 @@ namespace __gnu_cxx static pool_type _S_pool(_S_tune); return _S_pool; } + }; + + template<typename _Tp, template <bool> class _PoolTp, bool _Thread> + struct __per_type_pool_base; + + template<typename _Tp, template <bool> class _PoolTp> + struct __per_type_pool_base<_Tp, _PoolTp, false> + : public __per_type_pool<_Tp, _PoolTp, false> + { + using __per_type_pool<_Tp, _PoolTp, false>::_S_get_pool; static void _S_initialize_once() - { + { static bool __init; if (__builtin_expect(__init == false, false)) { @@ -523,39 +501,16 @@ namespace __gnu_cxx } }; -#ifdef __GTHREADS - /// Partial specialization for thread enabled, via gthreads.h. - template<typename _Tp, template <bool> class _PoolTp> - struct __per_type_pool_policy<_Tp, _PoolTp, true> + #ifdef __GTHREADS + template<typename _Tp, template <bool> class _PoolTp> + struct __per_type_pool_base<_Tp, _PoolTp, true> + : public __per_type_pool<_Tp, _PoolTp, true> { - typedef _Tp value_type; - typedef _PoolTp<true> pool_type; + using __per_type_pool<_Tp, _PoolTp, true>::_S_get_pool; - template<typename _Tp1, template <bool> class _PoolTp1 = _PoolTp, - bool _Thread1 = true> - struct _M_rebind - { typedef __per_type_pool_policy<_Tp1, _PoolTp1, _Thread1> other; }; - - static pool_type& - _S_get_pool() - { - // Sane defaults for the _PoolTp. - typedef typename pool_type::_Block_record _Block_record; - const static size_t __align = (__alignof__(_Tp) >= sizeof(_Block_record) - ? __alignof__(_Tp) - : sizeof(_Block_record)); - - typedef typename __pool_base::_Tune _Tune; - static _Tune _S_tune(__align, sizeof(_Tp) * 64, - sizeof(_Tp) * 2 >= __align ? sizeof(_Tp) * 2 - : __align, - sizeof(_Tp) * size_t(_Tune::_S_chunk_size), - _Tune::_S_max_threads, - _Tune::_S_freelist_headroom, - getenv("GLIBCXX_FORCE_NEW") ? true : false); - static pool_type _S_pool(_S_tune); - return _S_pool; - } + static void + _S_initialize() + { _S_get_pool()._M_initialize_once(); } static void _S_initialize_once() @@ -563,22 +518,35 @@ namespace __gnu_cxx static bool __init; if (__builtin_expect(__init == false, false)) { - _S_get_pool()._M_initialize_once(_S_initialize); + if (__gthread_active_p()) + { + // On some platforms, __gthread_once_t is an aggregate. + static __gthread_once_t __once = __GTHREAD_ONCE_INIT; + __gthread_once(&__once, _S_initialize); + } + else + _S_get_pool()._M_initialize_once(); __init = true; } } - - private: - static void - _S_destroy_thread_key(void* __freelist_pos) - { _S_get_pool()._M_destroy_thread_key(__freelist_pos); } - - static void - _S_initialize() - { _S_get_pool()._M_initialize(_S_destroy_thread_key); } }; #endif + /// @brief Policy for individual __pool objects. + template<typename _Tp, template <bool> class _PoolTp, bool _Thread> + struct __per_type_pool_policy + : public __per_type_pool_base<_Tp, _PoolTp, _Thread> + { + template<typename _Tp1, template <bool> class _PoolTp1 = _PoolTp, + bool _Thread1 = _Thread> + struct _M_rebind + { typedef __per_type_pool_policy<_Tp1, _PoolTp1, _Thread1> other; }; + + using __per_type_pool_base<_Tp, _PoolTp, _Thread>::_S_get_pool; + using __per_type_pool_base<_Tp, _PoolTp, _Thread>::_S_initialize_once; + }; + + /// @brief Base class for _Tp dependent member functions. template<typename _Tp> class __mt_alloc_base diff --git a/libstdc++-v3/src/mt_allocator.cc b/libstdc++-v3/src/mt_allocator.cc index 8716191..1f4ec3f 100644 --- a/libstdc++-v3/src/mt_allocator.cc +++ b/libstdc++-v3/src/mt_allocator.cc @@ -1,8 +1,8 @@ // Allocator details. -// Copyright (C) 2004 Free Software Foundation, Inc. +// Copyright (C) 2004, 2005 Free Software Foundation, Inc. // -// This file is part of the GNU ISO C++ Librarbooly. This library is free +// This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the // terms of the GNU General Public License as published by the // Free Software Foundation; either version 2, or (at your option) @@ -37,10 +37,42 @@ namespace __gnu_internal { +#ifdef __GTHREADS + struct __freelist + { + typedef __gnu_cxx::__pool<true>::_Thread_record _Thread_record; + _Thread_record* _M_thread_freelist; + _Thread_record* _M_thread_freelist_array; + size_t _M_max_threads; + __gthread_key_t _M_key; + + ~__freelist() + { + if (_M_thread_freelist_array) + { + __gthread_key_delete(_M_key); + ::operator delete(static_cast<void*>(_M_thread_freelist_array)); + } + } + }; + + // Ensure freelist is constructed first. + static __freelist freelist; static __glibcxx_mutex_define_initialized(freelist_mutex); -#ifdef __GTHREADS - __gthread_key_t freelist_key; + static void + _M_destroy_thread_key(void* __id) + { + // Return this thread id record to front of thread_freelist. + __gnu_cxx::lock sentry(__gnu_internal::freelist_mutex); + size_t _M_id = reinterpret_cast<size_t>(__id); + + using namespace __gnu_internal; + typedef __gnu_cxx::__pool<true>::_Thread_record _Thread_record; + _Thread_record* __tr = &freelist._M_thread_freelist_array[_M_id - 1]; + __tr->_M_next = freelist._M_thread_freelist; + freelist._M_thread_freelist = __tr; + } #endif } @@ -171,6 +203,7 @@ namespace __gnu_cxx } _M_init = true; } + #ifdef __GTHREADS void @@ -194,7 +227,6 @@ namespace __gnu_cxx ::operator delete(__bin._M_used); ::operator delete(__bin._M_mutex); } - ::operator delete(_M_thread_freelist_initial); } else { @@ -386,8 +418,8 @@ namespace __gnu_cxx return reinterpret_cast<char*>(__block) + __options._M_align; } - void - __pool<true>::_M_initialize(__destroy_handler __d) + void + __pool<true>::_M_initialize() { // _M_force_new must not change after the first allocate(), // which in turn calls this method, so if it's false, it's false @@ -397,7 +429,7 @@ namespace __gnu_cxx _M_init = true; return; } - + // Create the bins. // Calculate the number of bins required based on _M_max_bytes. // _M_bin_size is statically-initialized to one. @@ -433,29 +465,70 @@ namespace __gnu_cxx // directly and have no need for this. if (__gthread_active_p()) { - const size_t __k = sizeof(_Thread_record) * _M_options._M_max_threads; - __v = ::operator new(__k); - _M_thread_freelist = static_cast<_Thread_record*>(__v); - _M_thread_freelist_initial = __v; - - // NOTE! The first assignable thread id is 1 since the - // global pool uses id 0 - size_t __i; - for (__i = 1; __i < _M_options._M_max_threads; ++__i) - { - _Thread_record& __tr = _M_thread_freelist[__i - 1]; - __tr._M_next = &_M_thread_freelist[__i]; - __tr._M_id = __i; - } - - // Set last record. - _M_thread_freelist[__i - 1]._M_next = NULL; - _M_thread_freelist[__i - 1]._M_id = __i; - - // Initialize per thread key to hold pointer to - // _M_thread_freelist. - __gthread_key_create(&__gnu_internal::freelist_key, __d); - + { + __gnu_cxx::lock sentry(__gnu_internal::freelist_mutex); + + if (!__gnu_internal::freelist._M_thread_freelist_array + || __gnu_internal::freelist._M_max_threads + < _M_options._M_max_threads) + { + const size_t __k = sizeof(_Thread_record) + * _M_options._M_max_threads; + __v = ::operator new(__k); + _Thread_record* _M_thread_freelist + = 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 < _M_options._M_max_threads; ++__i) + { + _Thread_record& __tr = _M_thread_freelist[__i - 1]; + __tr._M_next = &_M_thread_freelist[__i]; + __tr._M_id = __i; + } + + // Set last record. + _M_thread_freelist[__i - 1]._M_next = NULL; + _M_thread_freelist[__i - 1]._M_id = __i; + + if (!__gnu_internal::freelist._M_thread_freelist_array) + { + // Initialize per thread key to hold pointer to + // _M_thread_freelist. + __gthread_key_create(&__gnu_internal::freelist._M_key, + __gnu_internal::_M_destroy_thread_key); + __gnu_internal::freelist._M_thread_freelist + = _M_thread_freelist; + } + else + { + _Thread_record* _M_old_freelist + = __gnu_internal::freelist._M_thread_freelist; + _Thread_record* _M_old_array + = __gnu_internal::freelist._M_thread_freelist_array; + __gnu_internal::freelist._M_thread_freelist + = &_M_thread_freelist[_M_old_freelist - _M_old_array]; + while (_M_old_freelist) + { + size_t next_id; + if (_M_old_freelist->_M_next) + next_id = _M_old_freelist->_M_next - _M_old_array; + else + next_id = __gnu_internal::freelist._M_max_threads; + _M_thread_freelist[_M_old_freelist->_M_id - 1]._M_next + = &_M_thread_freelist[next_id]; + _M_old_freelist = _M_old_freelist->_M_next; + } + ::operator delete(static_cast<void*>(_M_old_array)); + } + __gnu_internal::freelist._M_thread_freelist_array + = _M_thread_freelist; + __gnu_internal::freelist._M_max_threads + = _M_options._M_max_threads; + } + } + const size_t __max_threads = _M_options._M_max_threads + 1; for (size_t __n = 0; __n < _M_bin_size; ++__n) { @@ -514,23 +587,24 @@ namespace __gnu_cxx // returns it's id. if (__gthread_active_p()) { - void* v = __gthread_getspecific(__gnu_internal::freelist_key); - _Thread_record* __freelist_pos = static_cast<_Thread_record*>(v); - if (__freelist_pos == NULL) + void* v = __gthread_getspecific(__gnu_internal::freelist._M_key); + size_t _M_id = (size_t)v; + if (_M_id == 0) { - // Since _M_options._M_max_threads must be larger than - // the theoretical max number of threads of the OS the - // list can never be empty. { __gnu_cxx::lock sentry(__gnu_internal::freelist_mutex); - __freelist_pos = _M_thread_freelist; - _M_thread_freelist = _M_thread_freelist->_M_next; + if (__gnu_internal::freelist._M_thread_freelist) + { + _M_id = __gnu_internal::freelist._M_thread_freelist->_M_id; + __gnu_internal::freelist._M_thread_freelist + = __gnu_internal::freelist._M_thread_freelist->_M_next; + } } - - __gthread_setspecific(__gnu_internal::freelist_key, - static_cast<void*>(__freelist_pos)); + + __gthread_setspecific(__gnu_internal::freelist._M_key, + (void*)_M_id); } - return __freelist_pos->_M_id; + return _M_id >= _M_options._M_max_threads ? 0 : _M_id; } // Otherwise (no thread support or inactive) all requests are @@ -538,14 +612,169 @@ namespace __gnu_cxx return 0; } + // XXX GLIBCXX_ABI Deprecated + void + __pool<true>::_M_destroy_thread_key(void*) { } + + // XXX GLIBCXX_ABI Deprecated void - __pool<true>::_M_destroy_thread_key(void* __freelist_pos) + __pool<true>::_M_initialize(__destroy_handler) { - // Return this thread id record to front of thread_freelist. - __gnu_cxx::lock sentry(__gnu_internal::freelist_mutex); - _Thread_record* __tr = static_cast<_Thread_record*>(__freelist_pos); - __tr->_M_next = _M_thread_freelist; - _M_thread_freelist = __tr; + // _M_force_new must not change after the first allocate(), + // which in turn calls this method, so if it's false, it's false + // forever and we don't need to return here ever again. + if (_M_options._M_force_new) + { + _M_init = true; + return; + } + + // Create the bins. + // Calculate the number of bins required based on _M_max_bytes. + // _M_bin_size is statically-initialized to one. + size_t __bin_size = _M_options._M_min_bin; + while (_M_options._M_max_bytes > __bin_size) + { + __bin_size <<= 1; + ++_M_bin_size; + } + + // Setup the bin map for quick lookup of the relevant bin. + const size_t __j = (_M_options._M_max_bytes + 1) * sizeof(_Binmap_type); + _M_binmap = static_cast<_Binmap_type*>(::operator new(__j)); + _Binmap_type* __bp = _M_binmap; + _Binmap_type __bin_max = _M_options._M_min_bin; + _Binmap_type __bint = 0; + for (_Binmap_type __ct = 0; __ct <= _M_options._M_max_bytes; ++__ct) + { + if (__ct > __bin_max) + { + __bin_max <<= 1; + ++__bint; + } + *__bp++ = __bint; + } + + // Initialize _M_bin and its members. + void* __v = ::operator new(sizeof(_Bin_record) * _M_bin_size); + _M_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. + if (__gthread_active_p()) + { + { + __gnu_cxx::lock sentry(__gnu_internal::freelist_mutex); + + if (!__gnu_internal::freelist._M_thread_freelist_array + || __gnu_internal::freelist._M_max_threads + < _M_options._M_max_threads) + { + const size_t __k = sizeof(_Thread_record) + * _M_options._M_max_threads; + __v = ::operator new(__k); + _Thread_record* _M_thread_freelist + = 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 < _M_options._M_max_threads; ++__i) + { + _Thread_record& __tr = _M_thread_freelist[__i - 1]; + __tr._M_next = &_M_thread_freelist[__i]; + __tr._M_id = __i; + } + + // Set last record. + _M_thread_freelist[__i - 1]._M_next = NULL; + _M_thread_freelist[__i - 1]._M_id = __i; + + if (!__gnu_internal::freelist._M_thread_freelist_array) + { + // Initialize per thread key to hold pointer to + // _M_thread_freelist. + __gthread_key_create(&__gnu_internal::freelist._M_key, + __gnu_internal::_M_destroy_thread_key); + __gnu_internal::freelist._M_thread_freelist + = _M_thread_freelist; + } + else + { + _Thread_record* _M_old_freelist + = __gnu_internal::freelist._M_thread_freelist; + _Thread_record* _M_old_array + = __gnu_internal::freelist._M_thread_freelist_array; + __gnu_internal::freelist._M_thread_freelist + = &_M_thread_freelist[_M_old_freelist - _M_old_array]; + while (_M_old_freelist) + { + size_t next_id; + if (_M_old_freelist->_M_next) + next_id = _M_old_freelist->_M_next - _M_old_array; + else + next_id = __gnu_internal::freelist._M_max_threads; + _M_thread_freelist[_M_old_freelist->_M_id - 1]._M_next + = &_M_thread_freelist[next_id]; + _M_old_freelist = _M_old_freelist->_M_next; + } + ::operator delete(static_cast<void*>(_M_old_array)); + } + __gnu_internal::freelist._M_thread_freelist_array + = _M_thread_freelist; + __gnu_internal::freelist._M_max_threads + = _M_options._M_max_threads; + } + } + + const size_t __max_threads = _M_options._M_max_threads + 1; + for (size_t __n = 0; __n < _M_bin_size; ++__n) + { + _Bin_record& __bin = _M_bin[__n]; + __v = ::operator new(sizeof(_Block_record*) * __max_threads); + __bin._M_first = static_cast<_Block_record**>(__v); + + __bin._M_address = NULL; + + __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 + { + for (size_t __n = 0; __n < _M_bin_size; ++__n) + { + _Bin_record& __bin = _M_bin[__n]; + __v = ::operator new(sizeof(_Block_record*)); + __bin._M_first = static_cast<_Block_record**>(__v); + __bin._M_first[0] = NULL; + __bin._M_address = NULL; + } + } + _M_init = true; } #endif diff --git a/libstdc++-v3/testsuite/ext/mt_allocator/22309_thread.cc b/libstdc++-v3/testsuite/ext/mt_allocator/22309_thread.cc new file mode 100644 index 0000000..ce4024e --- /dev/null +++ b/libstdc++-v3/testsuite/ext/mt_allocator/22309_thread.cc @@ -0,0 +1,101 @@ +// { dg-require-sharedlib "" } +// { dg-do run { target *-*-linux* } } +// { dg-options "-g -O2 -pthread -ldl" { target *-*-linux* } } + +// Copyright (C) 2004, 2005 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2, or (at your option) +// any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING. If not, write to the Free +// Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +// USA. + +#include <dlfcn.h> +#include <pthread.h> +#include <cstdlib> +#include <stdexcept> + +void +check_dlopen(void*& h) +{ + dlerror(); + void* tmp = dlopen("./testsuite_shared.so", RTLD_LAZY); + if (!tmp) + { + try + { + // Throws std::logic_error on NULL string. + std::string error(dlerror()); + throw std::runtime_error(error); + } + catch (const std::logic_error&) + { } + } + h = tmp; +} + +void +check_dlsym(void*& h) +{ + dlerror(); + + typedef void (*function_type) (void); + function_type fn; + fn = reinterpret_cast<function_type>(dlsym(h, "foo")); + + try + { + std::string error(dlerror()); + throw std::runtime_error(error); + } + catch (const std::logic_error&) + { } + + fn(); +} + +void +check_dlclose(void*& h) +{ + dlerror(); + if (dlclose(h) != 0) + { + try + { + std::string error(dlerror()); + throw std::runtime_error(error); + } + catch (const std::logic_error&) + { } + } +} + +void* +tf(void* arg) +{ + void* h; + check_dlopen(h); + check_dlsym(h); + check_dlclose(h); + return 0; +} + +// libstdc++/22309 +int +main (void) +{ + pthread_t th; + pthread_create(&th, NULL, tf, NULL); + pthread_join(th, NULL); + return 0; +} diff --git a/libstdc++-v3/testsuite/lib/dg-options.exp b/libstdc++-v3/testsuite/lib/dg-options.exp index 05d2ff3..2ab8e42 100644 --- a/libstdc++-v3/testsuite/lib/dg-options.exp +++ b/libstdc++-v3/testsuite/lib/dg-options.exp @@ -44,3 +44,12 @@ proc dg-require-cxa-atexit { args } { } return } + +proc dg-require-sharedlib { args } { + if { ![ check_v3_target_sharedlib ] } { + upvar dg-do-what dg-do-what + set dg-do-what [list [lindex ${dg-do-what} 0] "N" "P"] + return + } + return +} diff --git a/libstdc++-v3/testsuite/lib/libstdc++.exp b/libstdc++-v3/testsuite/lib/libstdc++.exp index 1446d87..333d50c 100644 --- a/libstdc++-v3/testsuite/lib/libstdc++.exp +++ b/libstdc++-v3/testsuite/lib/libstdc++.exp @@ -14,7 +14,8 @@ # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. # Define callbacks and load other libraries. This file is loaded relatively @@ -79,6 +80,7 @@ proc v3-copy-files {srcfiles} { # Called once, during runtest.exp setup. proc libstdc++_init { testfile } { global env + global v3-sharedlib global srcdir blddir objdir tool_root_dir global cxx cxxflags global includes @@ -127,6 +129,15 @@ proc libstdc++_init { testfile } { } v3track gccdir 3 + # Look for shared library. (ie libstdc++.so.) + set v3-sharedlib 0 + set sharedlibdir [lookfor_file $blddir src/.libs/libstdc++.so] + if {$sharedlibdir != ""} { + set v3-sharedlib 1 + verbose -log "shared library support detected" + } + v3track v3-sharedlib 3 + # Compute what needs to be added to the existing LD_LIBRARY_PATH. if {$gccdir != ""} { set ld_library_path "" @@ -324,6 +335,7 @@ proc v3-build_support {} { global v3-threads global v3-test_objs global v3-symver + global v3-sharedlib # Figure out whether or not the library supports certain features. set v3-wchar_t 0 @@ -353,7 +365,7 @@ proc v3-build_support {} { # Build the support objects. set source_files \ - [list testsuite_abi.cc testsuite_allocator.cc testsuite_character.cc testsuite_hooks.cc] + [list testsuite_abi.cc testsuite_allocator.cc testsuite_character.cc testsuite_hooks.cc ] foreach f $source_files { set object_file [file rootname $f].o # Compile with "-w" so that warnings issued by the compiler @@ -365,6 +377,27 @@ proc v3-build_support {} { } append v3-test_objs "$object_file " } + + # Build the shared support objects. + if { ${v3-sharedlib} == 1 } { + set source_files \ + [list testsuite_shared.cc] + foreach f $source_files { + set object_file [file rootname $f].so + # Compile with "-w" so that warnings issued by the compiler + # do not prevent compilation. + if { [v3_target_compile $srcdir/$f $object_file "executable" \ + [list "incdir=$srcdir" "additional_flags=-w -shared -fPIC -DPIC"]] + != "" } { + error "could not compile $f" + } + } + } +} + +proc check_v3_target_sharedlib { } { + global v3-sharedlib + return ${v3-sharedlib} } proc check_v3_target_namedlocale { } { @@ -491,27 +524,27 @@ proc check_v3_target_cxa_atexit { } { puts $f "static unsigned int count;" puts $f "struct X" puts $f "{" - puts $f "X() { count = 1; }" - puts $f "~X()" - puts $f "{" - puts $f " if (count != 3)" - puts $f " exit(1);" - puts $f " count = 4;" - puts $f "}" + puts $f " X() { count = 1; }" + puts $f " ~X()" + puts $f " {" + puts $f " if (count != 3)" + puts $f " exit(1);" + puts $f " count = 4;" + puts $f " }" puts $f "};" puts $f "void f()" puts $f "{" - puts $f "static X x;" + puts $f " static X x;" puts $f "}" puts $f "struct Y" puts $f "{" - puts $f "Y() { f(); count = 2; }" - puts $f "~Y()" - puts $f "{" - puts $f "if (count != 2)" - puts $f " exit(1);" - puts $f "count = 3;" - puts $f "}" + puts $f " Y() { f(); count = 2; }" + puts $f " ~Y()" + puts $f " {" + puts $f " if (count != 2)" + puts $f " exit(1);" + puts $f " count = 3;" + puts $f " }" puts $f "};" puts $f "Y y;" puts $f "int main()" diff --git a/libstdc++-v3/testsuite/testsuite_shared.cc b/libstdc++-v3/testsuite/testsuite_shared.cc new file mode 100644 index 0000000..a829fb4 --- /dev/null +++ b/libstdc++-v3/testsuite/testsuite_shared.cc @@ -0,0 +1,36 @@ +// Copyright (C) 2004, 2005 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2, or (at your option) +// any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING. If not, write to the Free +// Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +// USA. + +#include <string> +#include <ext/mt_allocator.h> + +// libstdc++/22309 +extern "C" void +foo() +{ + typedef char value_t; + + typedef __gnu_cxx::__common_pool_policy<__gnu_cxx::__pool, true> policy_t; + typedef __gnu_cxx::__mt_alloc<value_t, policy_t> allocator_t; + + typedef std::char_traits<value_t> traits_t; + typedef std::basic_string<value_t, traits_t, allocator_t> string_t; + + string_t s; + s += "west beach, indiana dunes"; +} |