[libc++] Make std::lock_guard available with _LIBCPP_HAS_NO_THREADS (#98717)

This change makes `std::lock_guard` available when
`_LIBCPP_HAS_NO_THREADS` is set. This class is generic and doesn't
require threading support, and is regularly used even in environments
where threading isn't available like embedded.

fixes #89891

---------

Co-authored-by: Louis Dionne <ldionne.2@gmail.com>
This commit is contained in:
Petr Hosek 2024-07-16 21:58:13 -07:00 committed by GitHub
parent 9e9924cc2e
commit 6192f458f4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 113 additions and 114 deletions

View File

@ -16,8 +16,6 @@
# pragma GCC system_header
#endif
#ifndef _LIBCPP_HAS_NO_THREADS
_LIBCPP_BEGIN_NAMESPACE_STD
template <class _Mutex>
@ -47,6 +45,4 @@ _LIBCPP_CTAD_SUPPORTED_FOR_TYPE(lock_guard);
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP_HAS_NO_THREADS
#endif // _LIBCPP___MUTEX_LOCK_GUARD_H

View File

@ -15,8 +15,6 @@
# pragma GCC system_header
#endif
#ifndef _LIBCPP_HAS_NO_THREADS
_LIBCPP_BEGIN_NAMESPACE_STD
struct _LIBCPP_EXPORTED_FROM_ABI defer_lock_t {
@ -31,18 +29,16 @@ struct _LIBCPP_EXPORTED_FROM_ABI adopt_lock_t {
explicit adopt_lock_t() = default;
};
# if _LIBCPP_STD_VER >= 17
#if _LIBCPP_STD_VER >= 17
inline constexpr defer_lock_t defer_lock = defer_lock_t();
inline constexpr try_to_lock_t try_to_lock = try_to_lock_t();
inline constexpr adopt_lock_t adopt_lock = adopt_lock_t();
# elif !defined(_LIBCPP_CXX03_LANG)
#elif !defined(_LIBCPP_CXX03_LANG)
constexpr defer_lock_t defer_lock = defer_lock_t();
constexpr try_to_lock_t try_to_lock = try_to_lock_t();
constexpr adopt_lock_t adopt_lock = adopt_lock_t();
# endif
#endif
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP_HAS_NO_THREADS
#endif // _LIBCPP___MUTEX_TAG_TYPES_H

View File

@ -14,13 +14,6 @@
#include <mutex>
int main(int, char**)
{
std::mutex m0;
std::mutex m1;
std::lock_guard<std::mutex> lg0(m0);
std::lock_guard<std::mutex> lg(m1);
lg = lg0;
#include "types.h"
return 0;
}
static_assert(!std::is_copy_assignable<std::lock_guard<MyMutex> >::value, "");

View File

@ -14,11 +14,6 @@
#include <mutex>
int main(int, char**)
{
std::mutex m;
std::lock_guard<std::mutex> lg0(m);
std::lock_guard<std::mutex> lg(lg0);
#include "types.h"
return 0;
}
static_assert(!std::is_copy_constructible<std::lock_guard<MyMutex> >::value, "");

View File

@ -5,8 +5,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// UNSUPPORTED: no-threads
// UNSUPPORTED: c++03
// <mutex>
@ -16,28 +15,18 @@
// lock_guard(mutex_type& m, adopt_lock_t);
#include <mutex>
#include <cstdlib>
#include <cassert>
#include "make_test_thread.h"
#include "test_macros.h"
std::mutex m;
void do_try_lock() {
assert(m.try_lock() == false);
}
#include "types.h"
int main(int, char**) {
MyMutex m;
{
m.lock();
std::lock_guard<std::mutex> lg(m, std::adopt_lock);
std::thread t = support::make_test_thread(do_try_lock);
t.join();
std::lock_guard<MyMutex> lg(m, std::adopt_lock);
assert(m.locked);
}
m.lock();
m.unlock();
assert(!m.locked);
return 0;
}

View File

@ -6,20 +6,25 @@
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: no-threads
// <mutex>
// template <class Mutex> class lock_guard;
// explicit lock_guard(mutex_type& m);
#include <cassert>
#include <mutex>
#include <type_traits>
int main(int, char**)
{
std::mutex m;
std::lock_guard<std::mutex> lg = m; // expected-error{{no viable conversion}}
#include "types.h"
int main(int, char**) {
MyMutex m;
assert(!m.locked);
std::lock_guard<MyMutex> lg(m);
assert(m.locked);
static_assert(!std::is_convertible<MyMutex, std::lock_guard<MyMutex> >::value, "constructor must be explicit");
return 0;
}

View File

@ -6,24 +6,24 @@
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: no-threads
// UNSUPPORTED: c++03, c++11, c++14
// <mutex>
// lock_guard
// template <class Mutex> class lock_guard;
// Make sure that the implicitly-generated CTAD works.
#include <mutex>
#include "test_macros.h"
#include "types.h"
int main(int, char**) {
std::mutex mutex;
MyMutex m;
{
std::lock_guard lock(mutex);
ASSERT_SAME_TYPE(decltype(lock), std::lock_guard<std::mutex>);
std::lock_guard lg(m);
ASSERT_SAME_TYPE(decltype(lg), std::lock_guard<MyMutex>);
}
return 0;

View File

@ -1,49 +0,0 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// UNSUPPORTED: no-threads
// <mutex>
// template <class Mutex> class lock_guard;
// explicit lock_guard(mutex_type& m);
// template<class _Mutex> lock_guard(lock_guard<_Mutex>)
// -> lock_guard<_Mutex>; // C++17
#include <mutex>
#include <cstdlib>
#include <cassert>
#include "make_test_thread.h"
#include "test_macros.h"
std::mutex m;
void do_try_lock() {
assert(m.try_lock() == false);
}
int main(int, char**) {
{
std::lock_guard<std::mutex> lg(m);
std::thread t = support::make_test_thread(do_try_lock);
t.join();
}
m.lock();
m.unlock();
#if TEST_STD_VER >= 17
std::lock_guard lg(m);
static_assert((std::is_same<decltype(lg), std::lock_guard<decltype(m)>>::value), "" );
#endif
return 0;
}

View File

@ -0,0 +1,49 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: no-threads
// UNSUPPORTED: c++03
// Test the interoperation of std::lock_guard with std::mutex, since that is such
// a common use case.
#include <cassert>
#include <mutex>
#include <type_traits>
#include <functional>
#include "make_test_thread.h"
#include "test_macros.h"
void do_try_lock(std::mutex& m) { assert(m.try_lock() == false); }
int main(int, char**) {
{
std::mutex m;
{
std::lock_guard<std::mutex> lg(m);
std::thread t = support::make_test_thread(do_try_lock, std::ref(m));
t.join();
}
// This should work because the lock_guard unlocked the mutex when it was destroyed above.
m.lock();
m.unlock();
}
// Test CTAD
#if TEST_STD_VER >= 17
{
std::mutex m;
std::lock_guard lg(m);
static_assert(std::is_same<decltype(lg), std::lock_guard<std::mutex>>::value, "");
}
#endif
return 0;
}

View File

@ -5,8 +5,6 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// UNSUPPORTED: no-threads
// <mutex>
@ -21,12 +19,6 @@
#include <mutex>
#include <type_traits>
#include "test_macros.h"
#include "types.h"
int main(int, char**)
{
static_assert((std::is_same<std::lock_guard<std::mutex>::mutex_type,
std::mutex>::value), "");
return 0;
}
static_assert(std::is_same<std::lock_guard<MyMutex>::mutex_type, MyMutex>::value, "");

View File

@ -0,0 +1,33 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef TEST_STD_THREAD_THREAD_MUTEX_THREAD_LOCK_THREAD_LOCK_GUARD_TYPES_H
#define TEST_STD_THREAD_THREAD_MUTEX_THREAD_LOCK_THREAD_LOCK_GUARD_TYPES_H
#include <cassert>
struct MyMutex {
bool locked = false;
MyMutex() = default;
~MyMutex() { assert(!locked); }
void lock() {
assert(!locked);
locked = true;
}
void unlock() {
assert(locked);
locked = false;
}
MyMutex(MyMutex const&) = delete;
MyMutex& operator=(MyMutex const&) = delete;
};
#endif // TEST_STD_THREAD_THREAD_MUTEX_THREAD_LOCK_THREAD_LOCK_GUARD_TYPES_H