This is a minor refactoring for readability. Tested x86_64-linux and powerpc-aix. Committed to trunk.
commit 9f925f3b198e210e0d124a3c69fae034f429942f Author: Jonathan Wakely <jwak...@redhat.com> Date: Tue Nov 3 19:42:07 2020 libstdc++: Refactor std::call_once internals This separates the definition of std::__call_proxy into two funcions, one for TLS and one for non-TLS, to make them easier to read. It also replaces the __get_once_functor_lock_ptr() internal helper with a new set_lock_ptr(unique_lock<mutex>*) function so that __once_proxy doesn't need to call it twice. libstdc++-v3/ChangeLog: * src/c++11/mutex.cc [_GLIBCXX_HAVE_TLS] (__once_proxy): Define separately for TLS targets. [!_GLIBCXX_HAVE_TLS] (__get_once_functor_lock_ptr): Replace with ... (set_lock_ptr): ... this. Set new value and return previous value. [!_GLIBCXX_HAVE_TLS] (__set_once_functor_lock_ptr): Adjust to use set_lock_ptr. [!_GLIBCXX_HAVE_TLS] (__once_proxy): Likewise. diff --git a/libstdc++-v3/src/c++11/mutex.cc b/libstdc++-v3/src/c++11/mutex.cc index 286f77f9a454..4d42bed8ecc9 100644 --- a/libstdc++-v3/src/c++11/mutex.cc +++ b/libstdc++-v3/src/c++11/mutex.cc @@ -84,18 +84,6 @@ std::once_flag::_M_finish(bool returning) noexcept #endif // ! FUTEX -#ifndef _GLIBCXX_HAVE_TLS -namespace -{ - inline std::unique_lock<std::mutex>*& - __get_once_functor_lock_ptr() - { - static std::unique_lock<std::mutex>* __once_functor_lock_ptr = 0; - return __once_functor_lock_ptr; - } -} -#endif - namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -103,9 +91,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #ifdef _GLIBCXX_HAVE_TLS __thread void* __once_callable; __thread void (*__once_call)(); -#else + + extern "C" void __once_proxy() + { + // The caller stored a function pointer in __once_call. If it requires + // any state, it gets it from __once_callable. + __once_call(); + } + +#else // ! TLS + // Explicit instantiation due to -fno-implicit-instantiation. template class function<void()>; + function<void()> __once_functor; mutex& @@ -115,11 +113,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return once_mutex; } +namespace +{ + // Store ptr in a global variable and return the previous value. + inline unique_lock<mutex>* + set_lock_ptr(unique_lock<mutex>* ptr) + { + static unique_lock<mutex>* __once_functor_lock_ptr = nullptr; + return std::__exchange(__once_functor_lock_ptr, ptr); + } +} + // code linked against ABI 3.4.12 and later uses this void __set_once_functor_lock_ptr(unique_lock<mutex>* __ptr) { - __get_once_functor_lock_ptr() = __ptr; + (void) set_lock_ptr(__ptr); } // unsafe - retained for compatibility with ABI 3.4.11 @@ -129,26 +138,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static unique_lock<mutex> once_functor_lock(__get_once_mutex(), defer_lock); return once_functor_lock; } -#endif - extern "C" + // This is called via pthread_once while __get_once_mutex() is locked. + extern "C" void + __once_proxy() { - void __once_proxy() + // Get the callable out of the global functor. + function<void()> callable = std::move(__once_functor); + + // Then unlock the global mutex + if (unique_lock<mutex>* lock = set_lock_ptr(nullptr)) { -#ifndef _GLIBCXX_HAVE_TLS - function<void()> __once_call = std::move(__once_functor); - if (unique_lock<mutex>* __lock = __get_once_functor_lock_ptr()) - { - // caller is using new ABI and provided lock ptr - __get_once_functor_lock_ptr() = 0; - __lock->unlock(); - } - else - __get_once_functor_lock().unlock(); // global lock -#endif - __once_call(); + // Caller is using the new ABI and provided a pointer to its lock. + lock->unlock(); } + else + __get_once_functor_lock().unlock(); // global lock + + // Finally, invoke the callable. + callable(); } +#endif // ! TLS _GLIBCXX_END_NAMESPACE_VERSION } // namespace std