diff options
author | Jonathan Wakely <jwakely@redhat.com> | 2015-09-29 13:54:05 +0100 |
---|---|---|
committer | Jonathan Wakely <redi@gcc.gnu.org> | 2015-09-29 13:54:05 +0100 |
commit | ce535a9685b11c846560cc0f9f4dded1ca558efc (patch) | |
tree | 1c41b68da533870ce3a44a9dd4a934252561bfbf | |
parent | c357b903daa3f831a34541a9d99469ccce226d54 (diff) | |
download | gcc-ce535a9685b11c846560cc0f9f4dded1ca558efc.zip gcc-ce535a9685b11c846560cc0f9f4dded1ca558efc.tar.gz gcc-ce535a9685b11c846560cc0f9f4dded1ca558efc.tar.bz2 |
Reduce space and time overhead of std::thread
PR libstdc++/65393
* config/abi/pre/gnu.ver: Export new symbols.
* include/std/thread (thread::_State, thread::_State_impl): New types.
(thread::_M_start_thread): Add overload taking unique_ptr<_State>.
(thread::_M_make_routine): Remove.
(thread::_S_make_state): Add.
(thread::_Impl_base, thread::_Impl, thread::_M_start_thread)
[_GLIBCXX_THREAD_ABI_COMPAT] Only declare conditionally.
* src/c++11/thread.cc (execute_native_thread_routine): Rename to
execute_native_thread_routine_compat and re-define to use _State.
(thread::_State::~_State()): Define.
(thread::_M_make_thread): Define new overload.
(thread::_M_make_thread) [_GLIBCXX_THREAD_ABI_COMPAT]: Only define old
overloads conditionally.
From-SVN: r228242
-rw-r--r-- | libstdc++-v3/ChangeLog | 17 | ||||
-rw-r--r-- | libstdc++-v3/config/abi/pre/gnu.ver | 5 | ||||
-rw-r--r-- | libstdc++-v3/include/std/thread | 92 | ||||
-rw-r--r-- | libstdc++-v3/src/c++11/thread.cc | 47 |
4 files changed, 117 insertions, 44 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 6b2738f..ad951e2 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,20 @@ +2015-09-29 Jonathan Wakely <jwakely@redhat.com> + + PR libstdc++/65393 + * config/abi/pre/gnu.ver: Export new symbols. + * include/std/thread (thread::_State, thread::_State_impl): New types. + (thread::_M_start_thread): Add overload taking unique_ptr<_State>. + (thread::_M_make_routine): Remove. + (thread::_S_make_state): Add. + (thread::_Impl_base, thread::_Impl, thread::_M_start_thread) + [_GLIBCXX_THREAD_ABI_COMPAT] Only declare conditionally. + * src/c++11/thread.cc (execute_native_thread_routine): Rename to + execute_native_thread_routine_compat and re-define to use _State. + (thread::_State::~_State()): Define. + (thread::_M_make_thread): Define new overload. + (thread::_M_make_thread) [_GLIBCXX_THREAD_ABI_COMPAT]: Only define old + overloads conditionally. + 2015-09-28 Jonathan Wakely <jwakely@redhat.com> * include/std/condition_variable (condition_variable::wait): Add diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver index d42cd37..08d9bc6 100644 --- a/libstdc++-v3/config/abi/pre/gnu.ver +++ b/libstdc++-v3/config/abi/pre/gnu.ver @@ -1870,6 +1870,11 @@ GLIBCXX_3.4.22 { # std::uncaught_exceptions() _ZSt19uncaught_exceptionsv; + # std::thread::_State::~_State() + _ZT[ISV]NSt6thread6_StateE; + _ZNSt6thread6_StateD[012]Ev; + _ZNSt6thread15_M_start_threadESt10unique_ptrINS_6_StateESt14default_deleteIS1_EEPFvvE; + } GLIBCXX_3.4.21; # Symbols in the support library (libsupc++) have their own tag. diff --git a/libstdc++-v3/include/std/thread b/libstdc++-v3/include/std/thread index ebbda62..c67ec46 100644 --- a/libstdc++-v3/include/std/thread +++ b/libstdc++-v3/include/std/thread @@ -60,9 +60,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION class thread { public: + // Abstract base class for types that wrap arbitrary functors to be + // invoked in the new thread of execution. + struct _State + { + virtual ~_State(); + virtual void _M_run() = 0; + }; + using _State_ptr = unique_ptr<_State>; + typedef __gthread_t native_handle_type; - struct _Impl_base; - typedef shared_ptr<_Impl_base> __shared_base_type; /// thread::id class id @@ -92,29 +99,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION operator<<(basic_ostream<_CharT, _Traits>& __out, thread::id __id); }; - // Simple base type that the templatized, derived class containing - // an arbitrary functor can be converted to and called. - struct _Impl_base - { - __shared_base_type _M_this_ptr; - - inline virtual ~_Impl_base(); - - virtual void _M_run() = 0; - }; - - template<typename _Callable> - struct _Impl : public _Impl_base - { - _Callable _M_func; - - _Impl(_Callable&& __f) : _M_func(std::forward<_Callable>(__f)) - { } - - void - _M_run() { _M_func(); } - }; - private: id _M_id; @@ -133,16 +117,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION thread(_Callable&& __f, _Args&&... __args) { #ifdef GTHR_ACTIVE_PROXY - // Create a reference to pthread_create, not just the gthr weak symbol - _M_start_thread(_M_make_routine(std::__bind_simple( - std::forward<_Callable>(__f), - std::forward<_Args>(__args)...)), - reinterpret_cast<void(*)()>(&pthread_create)); + // Create a reference to pthread_create, not just the gthr weak symbol. + auto __depend = reinterpret_cast<void(*)()>(&pthread_create); #else - _M_start_thread(_M_make_routine(std::__bind_simple( - std::forward<_Callable>(__f), - std::forward<_Args>(__args)...))); + auto __depend = nullptr; #endif + _M_start_thread(_S_make_state( + std::__bind_simple(std::forward<_Callable>(__f), + std::forward<_Args>(__args)...)), + __depend); } ~thread() @@ -190,22 +173,47 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION hardware_concurrency() noexcept; private: - void - _M_start_thread(__shared_base_type, void (*)()); + template<typename _Callable> + struct _State_impl : public _State + { + _Callable _M_func; + + _State_impl(_Callable&& __f) : _M_func(std::forward<_Callable>(__f)) + { } + + void + _M_run() { _M_func(); } + }; void - _M_start_thread(__shared_base_type); + _M_start_thread(_State_ptr, void (*)()); template<typename _Callable> - shared_ptr<_Impl<_Callable>> - _M_make_routine(_Callable&& __f) + static _State_ptr + _S_make_state(_Callable&& __f) { - // Create and allocate full data structure, not base. - return std::make_shared<_Impl<_Callable>>(std::forward<_Callable>(__f)); + using _Impl = _State_impl<_Callable>; + return _State_ptr{new _Impl{std::forward<_Callable>(__f)}}; } - }; +#if _GLIBCXX_THREAD_ABI_COMPAT + public: + struct _Impl_base; + typedef shared_ptr<_Impl_base> __shared_base_type; + struct _Impl_base + { + __shared_base_type _M_this_ptr; + virtual ~_Impl_base() = default; + virtual void _M_run() = 0; + }; - inline thread::_Impl_base::~_Impl_base() = default; + private: + void + _M_start_thread(__shared_base_type, void (*)()); + + void + _M_start_thread(__shared_base_type); +#endif + }; inline void swap(thread& __x, thread& __y) noexcept diff --git a/libstdc++-v3/src/c++11/thread.cc b/libstdc++-v3/src/c++11/thread.cc index 906cafa..e116afa 100644 --- a/libstdc++-v3/src/c++11/thread.cc +++ b/libstdc++-v3/src/c++11/thread.cc @@ -23,6 +23,7 @@ // <http://www.gnu.org/licenses/>. +#define _GLIBCXX_THREAD_ABI_COMPAT 1 #include <thread> #include <system_error> #include <cerrno> @@ -75,8 +76,33 @@ namespace std _GLIBCXX_VISIBILITY(default) extern "C" void* execute_native_thread_routine(void* __p) { + thread::_State_ptr __t{ static_cast<thread::_State*>(__p) }; + + __try + { + __t->_M_run(); + } + __catch(const __cxxabiv1::__forced_unwind&) + { + __throw_exception_again; + } + __catch(...) + { + std::terminate(); + } + + return nullptr; + } + +#if _GLIBCXX_THREAD_ABI_COMPAT + extern "C" void* + execute_native_thread_routine_compat(void* __p) + { thread::_Impl_base* __t = static_cast<thread::_Impl_base*>(__p); thread::__shared_base_type __local; + // Now that a new thread has been created we can transfer ownership of + // the thread state to a local object, breaking the reference cycle + // created in thread::_M_start_thread. __local.swap(__t->_M_this_ptr); __try @@ -94,10 +120,13 @@ namespace std _GLIBCXX_VISIBILITY(default) return nullptr; } +#endif } _GLIBCXX_BEGIN_NAMESPACE_VERSION + thread::_State::~_State() = default; + void thread::join() { @@ -127,6 +156,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } void + thread::_M_start_thread(_State_ptr state, void (*)()) + { + const int err = __gthread_create(&_M_id._M_thread, + &execute_native_thread_routine, + state.get()); + if (err) + __throw_system_error(err); + state.release(); + } + +#if _GLIBCXX_THREAD_ABI_COMPAT + void thread::_M_start_thread(__shared_base_type __b) { if (!__gthread_active_p()) @@ -144,15 +185,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION thread::_M_start_thread(__shared_base_type __b, void (*)()) { auto ptr = __b.get(); + // Create a reference cycle that will be broken in the new thread. ptr->_M_this_ptr = std::move(__b); int __e = __gthread_create(&_M_id._M_thread, - &execute_native_thread_routine, ptr); + &execute_native_thread_routine_compat, ptr); if (__e) { - ptr->_M_this_ptr.reset(); + ptr->_M_this_ptr.reset(); // break reference cycle, destroying *ptr. __throw_system_error(__e); } } +#endif unsigned int thread::hardware_concurrency() noexcept |