diff --git a/libcxx/src/memory.cpp b/libcxx/src/memory.cpp --- a/libcxx/src/memory.cpp +++ b/libcxx/src/memory.cpp @@ -149,12 +149,23 @@ void __sp_mut::lock() noexcept { + // The __sp_mut class should only be used for the shared_ptr overloads of + // std::atomic_... functions. Ownership of __sp_mut is always released + // before the end of any of these overloads, and none of them spawn new + // threads. Thus, there is no danger of one thread calling __sp_mut::lock + // and skipping acquisition of __lx followed by another thread calling it + // (and acquiring __lx) before the first thread calls __sp_mut::unlock. + // + // We can't acquire the mutex when the threading API is disabled. Since we + // don't need to acquire it when single-threaded anyways, we just don't + // bother aquiring the mutex unless we're multi-threaded (and thus the + // threading API is enabled). + if (!__libcpp_might_have_multiple_threads()) + return; auto m = static_cast<__libcpp_mutex_t*>(__lx); unsigned count = 0; - while (!__libcpp_mutex_trylock(m)) - { - if (++count > 16) - { + while (!__libcpp_mutex_trylock(m)) { + if (++count > 16) { __libcpp_mutex_lock(m); break; } @@ -165,6 +176,9 @@ void __sp_mut::unlock() noexcept { + // See comment in __sp_mut::lock() for discussion of why this is safe. + if (!__libcpp_might_have_multiple_threads()) + return; __libcpp_mutex_unlock(static_cast<__libcpp_mutex_t*>(__lx)); }