[libcxx-commits] [libcxx] [libc++] Refactor the tests for mutex, recursive mutex and their timed counterparts (PR #104852)
via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Aug 19 13:40:56 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libcxx
Author: Louis Dionne (ldionne)
<details>
<summary>Changes</summary>
---
Patch is 61.60 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/104852.diff
24 Files Affected:
- (renamed) libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/assign.compile.pass.cpp (+4-8)
- (renamed) libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/ctor.copy.compile.pass.cpp (+4-7)
- (renamed) libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/ctor.default.pass.cpp (+12-8)
- (modified) libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/lock.pass.cpp (+52-25)
- (modified) libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/try_lock.pass.cpp (+24-32)
- (renamed) libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.recursive/assign.compile.pass.cpp (+4-8)
- (renamed) libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.recursive/ctor.copy.compile.pass.cpp (+4-7)
- (renamed) libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.recursive/ctor.default.pass.cpp (+9-5)
- (modified) libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.recursive/lock.pass.cpp (+78-24)
- (modified) libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.recursive/try_lock.pass.cpp (+54-33)
- (renamed) libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.timedmutex.requirements/thread.timedmutex.class/assign.compile.pass.cpp (+4-8)
- (renamed) libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.timedmutex.requirements/thread.timedmutex.class/ctor.copy.compile.pass.cpp (+4-7)
- (renamed) libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.timedmutex.requirements/thread.timedmutex.class/ctor.default.pass.cpp (+7-4)
- (modified) libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.timedmutex.requirements/thread.timedmutex.class/lock.pass.cpp (+51-24)
- (modified) libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.timedmutex.requirements/thread.timedmutex.class/try_lock.pass.cpp (+23-31)
- (modified) libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.timedmutex.requirements/thread.timedmutex.class/try_lock_for.pass.cpp (+75-42)
- (modified) libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.timedmutex.requirements/thread.timedmutex.class/try_lock_until.pass.cpp (+75-42)
- (renamed) libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.timedmutex.requirements/thread.timedmutex.recursive/assign.compile.pass.cpp (+4-8)
- (renamed) libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.timedmutex.requirements/thread.timedmutex.recursive/ctor.copy.compile.pass.cpp (+4-7)
- (renamed) libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.timedmutex.requirements/thread.timedmutex.recursive/ctor.default.pass.cpp (+7-4)
- (modified) libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.timedmutex.requirements/thread.timedmutex.recursive/lock.pass.cpp (+78-24)
- (modified) libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.timedmutex.requirements/thread.timedmutex.recursive/try_lock.pass.cpp (+53-32)
- (modified) libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.timedmutex.requirements/thread.timedmutex.recursive/try_lock_for.pass.cpp (+104-44)
- (modified) libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.timedmutex.requirements/thread.timedmutex.recursive/try_lock_until.pass.cpp (+104-44)
``````````diff
diff --git a/libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/assign.compile.fail.cpp b/libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/assign.compile.pass.cpp
similarity index 80%
rename from libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/assign.compile.fail.cpp
rename to libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/assign.compile.pass.cpp
index ba09ed1a706ea7..5f5274a6c0027a 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/assign.compile.fail.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/assign.compile.pass.cpp
@@ -6,6 +6,8 @@
//
//===----------------------------------------------------------------------===//
+// UNSUPPORTED: no-threads
+
// <mutex>
// class mutex;
@@ -13,12 +15,6 @@
// mutex& operator=(const mutex&) = delete;
#include <mutex>
+#include <type_traits>
-int main(int, char**)
-{
- std::mutex m0;
- std::mutex m1;
- m1 = m0;
-
- return 0;
-}
+static_assert(!std::is_copy_assignable<std::mutex>::value, "");
diff --git a/libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/copy.compile.fail.cpp b/libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/ctor.copy.compile.pass.cpp
similarity index 79%
rename from libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/copy.compile.fail.cpp
rename to libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/ctor.copy.compile.pass.cpp
index 9edfb7267dee6f..74d0dfda41ad1b 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/copy.compile.fail.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/ctor.copy.compile.pass.cpp
@@ -6,6 +6,8 @@
//
//===----------------------------------------------------------------------===//
+// UNSUPPORTED: no-threads
+
// <mutex>
// class mutex;
@@ -13,11 +15,6 @@
// mutex(const mutex&) = delete;
#include <mutex>
+#include <type_traits>
-int main(int, char**)
-{
- std::mutex m0;
- std::mutex m1(m0);
-
- return 0;
-}
+static_assert(!std::is_copy_constructible<std::mutex>::value, "");
diff --git a/libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/default.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/ctor.default.pass.cpp
similarity index 64%
rename from libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/default.pass.cpp
rename to libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/ctor.default.pass.cpp
index d8115cd1bf3a08..7bda43087063af 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/default.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/ctor.default.pass.cpp
@@ -5,24 +5,28 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
-//
+
// UNSUPPORTED: no-threads
// <mutex>
// class mutex;
-// mutex();
+// mutex() noexcept;
#include <mutex>
+#include <cassert>
#include <type_traits>
-#include "test_macros.h"
+static_assert(std::is_nothrow_default_constructible<std::mutex>::value, "");
+
+int main(int, char**) {
+ // The mutex is unlocked after default construction
+ {
+ std::mutex m;
+ assert(m.try_lock());
+ m.unlock();
+ }
-int main(int, char**)
-{
- static_assert(std::is_nothrow_default_constructible<std::mutex>::value, "");
- std::mutex m;
- ((void)m);
return 0;
}
diff --git a/libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/lock.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/lock.pass.cpp
index b3e76cf886c4d4..e2bd2de84c33ce 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/lock.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/lock.pass.cpp
@@ -5,9 +5,9 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
-//
+
+// UNSUPPORTED: c++03
// UNSUPPORTED: no-threads
-// ALLOW_RETRIES: 2
// <mutex>
@@ -15,40 +15,67 @@
// void lock();
-#include <cassert>
-#include <chrono>
-#include <cstdlib>
#include <mutex>
+#include <atomic>
+#include <cassert>
#include <thread>
+#include <vector>
#include "make_test_thread.h"
-#include "test_macros.h"
-std::mutex m;
-
-typedef std::chrono::system_clock Clock;
-typedef Clock::time_point time_point;
-typedef Clock::duration duration;
-typedef std::chrono::milliseconds ms;
-typedef std::chrono::nanoseconds ns;
-
-void f()
-{
- time_point t0 = Clock::now();
+int main(int, char**) {
+ // Lock a mutex that is not locked yet. This should succeed.
+ {
+ std::mutex m;
m.lock();
- time_point t1 = Clock::now();
m.unlock();
- ns d = t1 - t0 - ms(250);
- assert(d < ms(50)); // within 50ms
-}
+ }
-int main(int, char**)
-{
+ // Lock a mutex that is already locked. This should block until it is unlocked.
+ {
+ std::atomic<bool> ready(false);
+ std::mutex m;
m.lock();
- std::thread t = support::make_test_thread(f);
- std::this_thread::sleep_for(ms(250));
+ std::atomic<bool> is_locked_from_main(true);
+
+ std::thread t = support::make_test_thread([&] {
+ ready = true;
+ m.lock();
+ assert(!is_locked_from_main);
+ m.unlock();
+ });
+
+ while (!ready)
+ /* spin */;
+
+ // We would rather signal this after we unlock, but that would create a race condition.
+ // We instead signal it before we unlock, which means that it's technically possible for
+ // the thread to take the lock while main is still holding it yet for the test to still pass.
+ is_locked_from_main = false;
m.unlock();
+
t.join();
+ }
+
+ // Make sure that at most one thread can acquire the mutex concurrently.
+ {
+ std::atomic<int> counter(0);
+ std::mutex mutex;
+
+ std::vector<std::thread> threads;
+ for (int i = 0; i != 10; ++i) {
+ threads.push_back(support::make_test_thread([&] {
+ mutex.lock();
+ counter++;
+ assert(counter == 1);
+ counter--;
+ mutex.unlock();
+ }));
+ }
+
+ for (auto& t : threads)
+ t.join();
+ }
return 0;
}
diff --git a/libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/try_lock.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/try_lock.pass.cpp
index bf3cb6530b3b94..db8b809c08d365 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/try_lock.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/try_lock.pass.cpp
@@ -5,9 +5,9 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
-//
+
+// UNSUPPORTED: c++03
// UNSUPPORTED: no-threads
-// ALLOW_RETRIES: 2
// <mutex>
@@ -15,44 +15,36 @@
// bool try_lock();
-#include <cassert>
-#include <chrono>
-#include <cstdlib>
#include <mutex>
+#include <cassert>
#include <thread>
#include "make_test_thread.h"
-#include "test_macros.h"
-
-std::mutex m;
-
-typedef std::chrono::system_clock Clock;
-typedef Clock::time_point time_point;
-typedef Clock::duration duration;
-typedef std::chrono::milliseconds ms;
-typedef std::chrono::nanoseconds ns;
-
-void f()
-{
- time_point t0 = Clock::now();
- assert(!m.try_lock());
- assert(!m.try_lock());
- assert(!m.try_lock());
- while(!m.try_lock())
- ;
- time_point t1 = Clock::now();
+
+int main(int, char**) {
+ // Try to lock a mutex that is not locked yet. This should succeed.
+ {
+ std::mutex m;
+ bool succeeded = m.try_lock();
+ assert(succeeded);
m.unlock();
- ns d = t1 - t0 - ms(250);
- assert(d < ms(200)); // within 200ms
-}
+ }
-int main(int, char**)
-{
+ // Try to lock a mutex that is already locked. This should fail.
+ {
+ std::mutex m;
m.lock();
- std::thread t = support::make_test_thread(f);
- std::this_thread::sleep_for(ms(250));
- m.unlock();
+
+ std::thread t = support::make_test_thread([&] {
+ for (int i = 0; i != 10; ++i) {
+ bool succeeded = m.try_lock();
+ assert(!succeeded);
+ }
+ });
t.join();
+ m.unlock();
+ }
+
return 0;
}
diff --git a/libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.recursive/assign.compile.fail.cpp b/libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.recursive/assign.compile.pass.cpp
similarity index 79%
rename from libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.recursive/assign.compile.fail.cpp
rename to libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.recursive/assign.compile.pass.cpp
index 0cf3c5bca1e1b4..fadd9a7cae28cc 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.recursive/assign.compile.fail.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.recursive/assign.compile.pass.cpp
@@ -6,6 +6,8 @@
//
//===----------------------------------------------------------------------===//
+// UNSUPPORTED: no-threads
+
// <mutex>
// class recursive_mutex;
@@ -13,12 +15,6 @@
// recursive_mutex& operator=(const recursive_mutex&) = delete;
#include <mutex>
+#include <type_traits>
-int main(int, char**)
-{
- std::recursive_mutex m0;
- std::recursive_mutex m1;
- m1 = m0;
-
- return 0;
-}
+static_assert(!std::is_copy_assignable<std::recursive_mutex>::value, "");
diff --git a/libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.recursive/copy.compile.fail.cpp b/libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.recursive/ctor.copy.compile.pass.cpp
similarity index 79%
rename from libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.recursive/copy.compile.fail.cpp
rename to libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.recursive/ctor.copy.compile.pass.cpp
index 454d7797373cac..bd63224f35d70c 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.recursive/copy.compile.fail.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.recursive/ctor.copy.compile.pass.cpp
@@ -6,6 +6,8 @@
//
//===----------------------------------------------------------------------===//
+// UNSUPPORTED: no-threads
+
// <mutex>
// class recursive_mutex;
@@ -13,11 +15,6 @@
// recursive_mutex(const recursive_mutex&) = delete;
#include <mutex>
+#include <type_traits>
-int main(int, char**)
-{
- std::recursive_mutex m0;
- std::recursive_mutex m1(m0);
-
- return 0;
-}
+static_assert(!std::is_copy_constructible<std::recursive_mutex>::value, "");
diff --git a/libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.recursive/default.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.recursive/ctor.default.pass.cpp
similarity index 75%
rename from libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.recursive/default.pass.cpp
rename to libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.recursive/ctor.default.pass.cpp
index 43dc38d7cab517..cd2694e8c43c8b 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.recursive/default.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.recursive/ctor.default.pass.cpp
@@ -5,7 +5,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
-//
+
// UNSUPPORTED: no-threads
// <mutex>
@@ -15,12 +15,16 @@
// recursive_mutex();
#include <mutex>
+#include <cassert>
+#include <type_traits>
-#include "test_macros.h"
-
-int main(int, char**)
-{
+int main(int, char**) {
+ // The mutex is unlocked after default construction
+ {
std::recursive_mutex m;
+ assert(m.try_lock());
+ m.unlock();
+ }
return 0;
}
diff --git a/libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.recursive/lock.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.recursive/lock.pass.cpp
index d9bff9b3cbda52..344667fa705d2c 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.recursive/lock.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.recursive/lock.pass.cpp
@@ -6,8 +6,8 @@
//
//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03
// UNSUPPORTED: no-threads
-// ALLOW_RETRIES: 2
// <mutex>
@@ -15,42 +15,96 @@
// void lock();
-#include <cassert>
-#include <chrono>
-#include <cstdlib>
#include <mutex>
+#include <atomic>
+#include <cassert>
#include <thread>
+#include <vector>
#include "make_test_thread.h"
-#include "test_macros.h"
-std::recursive_mutex m;
+bool is_lockable(std::recursive_mutex& m) {
+ bool did_lock;
+ std::thread t = support::make_test_thread([&] {
+ did_lock = m.try_lock();
+ if (did_lock)
+ m.unlock(); // undo side effects
+ });
+ t.join();
-typedef std::chrono::system_clock Clock;
-typedef Clock::time_point time_point;
-typedef Clock::duration duration;
-typedef std::chrono::milliseconds ms;
-typedef std::chrono::nanoseconds ns;
+ return did_lock;
+}
-void f()
-{
- time_point t0 = Clock::now();
- m.lock();
- time_point t1 = Clock::now();
+int main(int, char**) {
+ // Lock a mutex that is not locked yet. This should succeed.
+ {
+ std::recursive_mutex m;
m.lock();
m.unlock();
- m.unlock();
- ns d = t1 - t0 - ms(250);
- assert(d < ms(200)); // within 200ms
-}
+ }
+
+ // Lock a mutex that is already locked by this thread. This should succeed and the mutex should only
+ // be unlocked after a matching number of calls to unlock() on the same thread.
+ {
+ std::recursive_mutex m;
+ int lock_count = 0;
+ for (int i = 0; i != 10; ++i) {
+ m.lock();
+ ++lock_count;
+ }
+ while (lock_count != 0) {
+ assert(!is_lockable(m));
+ m.unlock();
+ --lock_count;
+ }
+ assert(is_lockable(m));
+ }
-int main(int, char**)
-{
+ // Lock a mutex that is already locked by another thread. This should block until it is unlocked.
+ {
+ std::atomic<bool> ready(false);
+ std::recursive_mutex m;
m.lock();
- std::thread t = support::make_test_thread(f);
- std::this_thread::sleep_for(ms(250));
+ std::atomic<bool> is_locked_from_main(true);
+
+ std::thread t = support::make_test_thread([&] {
+ ready = true;
+ m.lock();
+ assert(!is_locked_from_main);
+ m.unlock();
+ });
+
+ while (!ready)
+ /* spin */;
+
+ // We would rather signal this after we unlock, but that would create a race condition.
+ // We instead signal it before we unlock, which means that it's technically possible for
+ // the thread to take the lock while main is still holding it yet for the test to still pass.
+ is_locked_from_main = false;
m.unlock();
+
t.join();
+ }
+
+ // Make sure that at most one thread can acquire the mutex concurrently.
+ {
+ std::atomic<int> counter(0);
+ std::recursive_mutex mutex;
+
+ std::vector<std::thread> threads;
+ for (int i = 0; i != 10; ++i) {
+ threads.push_back(support::make_test_thread([&] {
+ mutex.lock();
+ counter++;
+ assert(counter == 1);
+ counter--;
+ mutex.unlock();
+ }));
+ }
+
+ for (auto& t : threads)
+ t.join();
+ }
return 0;
}
diff --git a/libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.recursive/try_lock.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.recursive/try_lock.pass.cpp
index 1247c1ce1ba5fd..96073eb345306d 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.recursive/try_lock.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.recursive/try_lock.pass.cpp
@@ -5,9 +5,9 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
-//
+
+// UNSUPPORTED: c++03
// UNSUPPORTED: no-threads
-// ALLOW_RETRIES: 2
// <mutex>
@@ -15,46 +15,67 @@
// bool try_lock();
+#include <mutex>
+#include <atomic>
#include <cassert>
#include <chrono>
-#include <cstdlib>
-#include <mutex>
#include <thread>
#include "make_test_thread.h"
-#include "test_macros.h"
-
-std::recursive_mutex m;
-
-typedef std::chrono::system_clock Clock;
-typedef Clock::time_point time_point;
-typedef Clock::duration duration;
-typedef std::chrono::milliseconds ms;
-typedef std::chrono::nanoseconds ns;
-
-void f()
-{
- time_point t0 = Clock::now();
- assert(!m.try_lock());
- assert(!m.try_lock());
- assert(!m.try_lock());
- while(!m.try_lock())
- ;
- time_point t1 = Clock::now();
- assert(m.try_lock());
- m.unlock();
- m.unlock();
- ns d = t1 - t0 - ms(250);
- assert(d < ms(200)); // within 200ms
+
+bool is_lockable(std::recursive_mutex& m) {
+ bool did_lock;
+ std::thread t = support::make_test_thread([&] {
+ did_lock = m.try_lock();
+ if (did_lock)
+ m.unlock(); // undo side effects
+ });
+ t.join();
+
+ return did_lock;
}
-int main(int, char**)
-{
- m.lock();
- std::thread t = support::make_test_thread(f);
- std::this_thread::sleep_for(ms(250));
+int main(int, char**) {
+ // Try to lock a mutex that is not locked yet. This should succeed.
+ {
+ std::recursive_mutex m;
+ bool succeeded = m.try_lock();
+ assert(succeeded);
m.unlock();
+ }
+
+ // Try to lock a mutex that is already locked by this thread. This should succeed and the mutex should only
+ // be unlocked after a matching number of calls to unlock() on the same thread.
+ {
+ std::recursive_mutex m;
+ int lock_count = 0;
+ for (int i = 0; i != 10; ++i) {
+ assert(m.try_lock());
+ ++lock_count;
+ }
+ while (lock_count != 0) {
+ assert(!is_lockable(m));
+ m.unlock();
+ --lock_c...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/104852
More information about the libcxx-commits
mailing list