From ce535a9685b11c846560cc0f9f4dded1ca558efc Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Tue, 29 Sep 2015 13:54:05 +0100 Subject: [PATCH] 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 --- libstdc++-v3/ChangeLog | 17 ++++++ libstdc++-v3/config/abi/pre/gnu.ver | 5 ++ libstdc++-v3/include/std/thread | 92 ++++++++++++++++------------- 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 6b2738f3aed..ad951e276d9 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,20 @@ +2015-09-29 Jonathan Wakely + + 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 * 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 d42cd37af66..08d9bc6c50e 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 ebbda62fa72..c67ec46123f 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 - 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(&pthread_create)); + // Create a reference to pthread_create, not just the gthr weak symbol. + auto __depend = reinterpret_cast(&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 + 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 - 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 906cafa735a..e116afa0ccb 100644 --- a/libstdc++-v3/src/c++11/thread.cc +++ b/libstdc++-v3/src/c++11/thread.cc @@ -23,6 +23,7 @@ // . +#define _GLIBCXX_THREAD_ABI_COMPAT 1 #include #include #include @@ -74,9 +75,34 @@ namespace std _GLIBCXX_VISIBILITY(default) { extern "C" void* execute_native_thread_routine(void* __p) + { + thread::_State_ptr __t{ static_cast(__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(__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() { @@ -126,6 +155,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_id = id(); } + 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) { @@ -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 -- 2.30.2