diff options
author | Jonathan Wakely <jwakely@redhat.com> | 2020-11-03 19:42:07 +0000 |
---|---|---|
committer | Jonathan Wakely <jwakely@redhat.com> | 2020-11-03 20:03:16 +0000 |
commit | 9f925f3b198e210e0d124a3c69fae034f429942f (patch) | |
tree | 8663060c9f3a8a645958c05d730dcaa2702c089b /libstdc++-v3/src | |
parent | ed7f9957bbb5e899099e1ef0e5f6234c453ef7da (diff) |
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.
Diffstat (limited to 'libstdc++-v3/src')
-rw-r--r-- | libstdc++-v3/src/c++11/mutex.cc | 68 |
1 files changed, 39 insertions, 29 deletions
diff --git a/libstdc++-v3/src/c++11/mutex.cc b/libstdc++-v3/src/c++11/mutex.cc index 286f77f9a45..4d42bed8ecc 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 |