[libcxx-commits] [libcxx] [libc++] Refactor the std::unique_lock tests (PR #102151)

Nikolas Klauser via libcxx-commits libcxx-commits at lists.llvm.org
Wed Aug 21 01:39:38 PDT 2024


https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/102151

>From c09b16ef103e7f9953c302497ff271aa940a16db Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Tue, 6 Aug 2024 16:18:01 +0200
Subject: [PATCH] [libc++] Refactor the std::unique_lock tests

---
 ...ass.cpp => implicit_ctad.compile.pass.cpp} | 14 +--
 .../thread.lock.unique/mutex.pass.cpp         | 67 ++++++++++++++
 .../copy_assign.compile.pass.cpp              |  4 +-
 .../copy_ctor.compile.pass.cpp                |  4 +-
 .../thread.lock.unique.cons/default.pass.cpp  |  9 +-
 .../move_assign.pass.cpp                      | 41 +++------
 .../move_ctor.pass.cpp                        | 39 ++++----
 .../thread.lock.unique.cons/mutex.pass.cpp    | 44 ++--------
 .../mutex_adopt_lock.pass.cpp                 | 30 ++-----
 .../mutex_defer_lock.pass.cpp                 | 31 +++----
 .../mutex_duration.pass.cpp                   | 79 +++++------------
 .../mutex_time_point.pass.cpp                 | 80 +++++------------
 .../mutex_try_to_lock.pass.cpp                | 72 +++++----------
 .../thread.lock.unique.locking/lock.pass.cpp  | 81 ++++++-----------
 .../try_lock.pass.cpp                         | 41 +++++----
 .../try_lock_for.pass.cpp                     | 43 +++++----
 .../try_lock_until.pass.cpp                   | 39 ++++----
 .../unlock.pass.cpp                           | 26 ++++--
 .../member_swap.pass.cpp                      | 26 ++++--
 .../nonmember_swap.pass.cpp                   | 26 ++++--
 .../thread.lock.unique.mod/release.pass.cpp   | 33 +++----
 .../thread.lock.unique.obs/mutex.pass.cpp     | 21 +++--
 .../thread.lock.unique.obs/op_bool.pass.cpp   | 24 ++---
 .../thread.lock.unique.obs/owns_lock.pass.cpp | 21 +++--
 .../thread.lock.unique/types.compile.pass.cpp |  5 +-
 .../thread.lock/thread.lock.unique/types.h    | 88 -------------------
 libcxx/test/support/checking_mutex.h          | 80 +++++++++++++++++
 27 files changed, 501 insertions(+), 567 deletions(-)
 rename libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/{implicit_ctad.pass.cpp => implicit_ctad.compile.pass.cpp} (71%)
 create mode 100644 libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/mutex.pass.cpp
 delete mode 100644 libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/types.h
 create mode 100644 libcxx/test/support/checking_mutex.h

diff --git a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/implicit_ctad.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/implicit_ctad.compile.pass.cpp
similarity index 71%
rename from libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/implicit_ctad.pass.cpp
rename to libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/implicit_ctad.compile.pass.cpp
index 8c7ca4279eead0..cc94c5704327fe 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/implicit_ctad.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/implicit_ctad.compile.pass.cpp
@@ -16,15 +16,7 @@
 
 #include <mutex>
 
-#include "test_macros.h"
-#include "types.h"
+#include "checking_mutex.h"
 
-int main(int, char**) {
-  MyMutex mutex;
-  {
-    std::unique_lock lock(mutex);
-    ASSERT_SAME_TYPE(decltype(lock), std::unique_lock<MyMutex>);
-  }
-
-  return 0;
-}
+checking_mutex mux;
+static_assert(std::is_same_v<std::unique_lock<checking_mutex>, decltype(std::unique_lock{mux})>);
diff --git a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/mutex.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/mutex.pass.cpp
new file mode 100644
index 00000000000000..1879bb836ca661
--- /dev/null
+++ b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/mutex.pass.cpp
@@ -0,0 +1,67 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <mutex>
+
+// Make sure std::unique_lock works with std::mutex as expected.
+
+#include <atomic>
+#include <cassert>
+#include <mutex>
+
+#include "make_test_thread.h"
+
+std::atomic<bool> keep_waiting;
+std::atomic<bool> child_thread_locked;
+std::mutex mux;
+bool main_thread_unlocked  = false;
+bool child_thread_unlocked = false;
+
+void lock_thread() {
+  std::unique_lock<std::mutex> lock(mux);
+  assert(main_thread_unlocked);
+  main_thread_unlocked  = false;
+  child_thread_unlocked = true;
+}
+
+void try_lock_thread() {
+  std::unique_lock<std::mutex> lock(mux, std::try_to_lock_t());
+  assert(lock.owns_lock());
+  child_thread_locked = true;
+
+  while (keep_waiting)
+    std::this_thread::sleep_for(std::chrono::milliseconds(10));
+
+  child_thread_unlocked = true;
+}
+
+int main(int, char**) {
+  {
+    mux.lock();
+    std::thread t        = support::make_test_thread(lock_thread);
+    main_thread_unlocked = true;
+    mux.unlock();
+    t.join();
+    assert(child_thread_unlocked);
+  }
+
+  {
+    child_thread_unlocked = false;
+    child_thread_locked   = false;
+    keep_waiting          = true;
+    std::thread t         = support::make_test_thread(try_lock_thread);
+    while (!child_thread_locked)
+      std::this_thread::sleep_for(std::chrono::milliseconds(10));
+    assert(!mux.try_lock());
+    keep_waiting = false;
+    t.join();
+    assert(child_thread_unlocked);
+  }
+
+  return 0;
+}
diff --git a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/copy_assign.compile.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/copy_assign.compile.pass.cpp
index 9ab8369637cdc5..c0cb7d4ddd27a6 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/copy_assign.compile.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/copy_assign.compile.pass.cpp
@@ -14,6 +14,6 @@
 
 #include <mutex>
 
-#include "../types.h"
+#include "checking_mutex.h"
 
-static_assert(!std::is_copy_assignable<std::lock_guard<MyMutex> >::value, "");
+static_assert(!std::is_copy_assignable<std::lock_guard<checking_mutex> >::value, "");
diff --git a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/copy_ctor.compile.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/copy_ctor.compile.pass.cpp
index e846061f5fbd08..2846b24125e784 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/copy_ctor.compile.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/copy_ctor.compile.pass.cpp
@@ -14,6 +14,6 @@
 
 #include <mutex>
 
-#include "../types.h"
+#include "checking_mutex.h"
 
-static_assert(!std::is_copy_constructible<std::lock_guard<MyMutex> >::value, "");
+static_assert(!std::is_copy_constructible<std::lock_guard<checking_mutex> >::value, "");
diff --git a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/default.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/default.pass.cpp
index 6fc4f7f23ced3a..f6ca534de42fe9 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/default.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/default.pass.cpp
@@ -14,12 +14,17 @@
 
 #include <cassert>
 #include <mutex>
+#include <type_traits>
 
+#include "checking_mutex.h"
 #include "test_macros.h"
-#include "../types.h"
+
+#if TEST_STD_VER >= 11
+static_assert(std::is_nothrow_default_constructible<std::unique_lock<checking_mutex>>::value, "");
+#endif
 
 int main(int, char**) {
-  std::unique_lock<MyMutex> ul;
+  std::unique_lock<checking_mutex> ul;
   assert(!ul.owns_lock());
   assert(ul.mutex() == nullptr);
 
diff --git a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/move_assign.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/move_assign.pass.cpp
index 9563fdebd3e060..588d8332c4164b 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/move_assign.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/move_assign.pass.cpp
@@ -13,37 +13,24 @@
 // unique_lock& operator=(unique_lock&& u);
 
 #include <cassert>
+#include <memory>
 #include <mutex>
 
-#include "nasty_containers.h"
-#include "../types.h"
-#include "test_macros.h"
+#include "checking_mutex.h"
 
 int main(int, char**) {
-  {
-    typedef MyMutex M;
-    M m0;
-    M m1;
-    std::unique_lock<M> lk0(m0);
-    std::unique_lock<M> lk1(m1);
-    lk1 = std::move(lk0);
-    assert(lk1.mutex() == std::addressof(m0));
-    assert(lk1.owns_lock() == true);
-    assert(lk0.mutex() == nullptr);
-    assert(lk0.owns_lock() == false);
-  }
-  {
-    typedef nasty_mutex M;
-    M m0;
-    M m1;
-    std::unique_lock<M> lk0(m0);
-    std::unique_lock<M> lk1(m1);
-    lk1 = std::move(lk0);
-    assert(lk1.mutex() == std::addressof(m0));
-    assert(lk1.owns_lock() == true);
-    assert(lk0.mutex() == nullptr);
-    assert(lk0.owns_lock() == false);
-  }
+  checking_mutex m0;
+  checking_mutex m1;
+  std::unique_lock<checking_mutex> lk0(m0);
+  std::unique_lock<checking_mutex> lk1(m1);
+
+  auto& result = (lk1 = std::move(lk0));
+
+  assert(&result == &lk1);
+  assert(lk1.mutex() == std::addressof(m0));
+  assert(lk1.owns_lock());
+  assert(lk0.mutex() == nullptr);
+  assert(!lk0.owns_lock());
 
   return 0;
 }
diff --git a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/move_ctor.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/move_ctor.pass.cpp
index 08f6fc8410e25e..7dab92ab69d987 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/move_ctor.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/move_ctor.pass.cpp
@@ -5,8 +5,6 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
-//
-// UNSUPPORTED: c++03
 
 // <mutex>
 
@@ -15,33 +13,26 @@
 // unique_lock(unique_lock&& u);
 
 #include <cassert>
+#include <memory>
 #include <mutex>
+#include <type_traits>
 
-#include "nasty_containers.h"
-#include "../types.h"
+#include "checking_mutex.h"
 #include "test_macros.h"
 
+#if TEST_STD_VER >= 11
+static_assert(std::is_nothrow_move_constructible<std::unique_lock<checking_mutex>>::value, "");
+#endif
+
 int main(int, char**) {
-  {
-    typedef MyMutex M;
-    M m;
-    std::unique_lock<M> lk0(m);
-    std::unique_lock<M> lk = std::move(lk0);
-    assert(lk.mutex() == std::addressof(m));
-    assert(lk.owns_lock() == true);
-    assert(lk0.mutex() == nullptr);
-    assert(lk0.owns_lock() == false);
-  }
-  {
-    typedef nasty_mutex M;
-    M m;
-    std::unique_lock<M> lk0(m);
-    std::unique_lock<M> lk = std::move(lk0);
-    assert(lk.mutex() == std::addressof(m));
-    assert(lk.owns_lock() == true);
-    assert(lk0.mutex() == nullptr);
-    assert(lk0.owns_lock() == false);
-  }
+  checking_mutex m;
+  std::unique_lock<checking_mutex> lk0(m);
+  std::unique_lock<checking_mutex> lk = std::move(lk0);
+
+  assert(lk.mutex() == std::addressof(m));
+  assert(lk.owns_lock());
+  assert(lk0.mutex() == nullptr);
+  assert(!lk0.owns_lock());
 
   return 0;
 }
diff --git a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/mutex.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/mutex.pass.cpp
index 2be25748e903b0..31f15deec0cfaf 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/mutex.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/mutex.pass.cpp
@@ -5,9 +5,6 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
-//
-// UNSUPPORTED: no-threads
-// ALLOW_RETRIES: 2
 
 // <mutex>
 
@@ -19,45 +16,22 @@
 //     -> unique_lock<_Mutex>;  // C++17
 
 #include <cassert>
-#include <chrono>
-#include <cstdlib>
 #include <mutex>
-#include <thread>
 
-#include "make_test_thread.h"
+#include "checking_mutex.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();
-    time_point t1;
-    {
-    std::unique_lock<std::mutex> ul(m);
-    t1 = Clock::now();
-    }
-    ns d = t1 - t0 - ms(250);
-    assert(d < ms(50));  // within 50ms
-}
+int main(int, char**) {
+  checking_mutex mux;
 
-int main(int, char**)
-{
-    m.lock();
-    std::thread t = support::make_test_thread(f);
-    std::this_thread::sleep_for(ms(250));
-    m.unlock();
-    t.join();
+  {
+    std::unique_lock<checking_mutex> lock(mux);
+    assert(mux.current_state == checking_mutex::locked_via_lock);
+  }
+  assert(mux.current_state == checking_mutex::unlocked);
 
 #if TEST_STD_VER >= 17
-    std::unique_lock ul(m);
-    static_assert((std::is_same<decltype(ul), std::unique_lock<decltype(m)>>::value), "" );
+  static_assert(std::is_same_v<std::unique_lock<checking_mutex>, decltype(std::unique_lock{mux})>, "");
 #endif
 
   return 0;
diff --git a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/mutex_adopt_lock.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/mutex_adopt_lock.pass.cpp
index 28cc43853180e6..14db741fa4adc3 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/mutex_adopt_lock.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/mutex_adopt_lock.pass.cpp
@@ -5,8 +5,6 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
-//
-// UNSUPPORTED: c++03
 
 // <mutex>
 
@@ -15,29 +13,19 @@
 // unique_lock(mutex_type& m, adopt_lock_t);
 
 #include <cassert>
+#include <memory>
 #include <mutex>
 
-#include "nasty_containers.h"
-#include "../types.h"
-#include "test_macros.h"
+#include "checking_mutex.h"
 
 int main(int, char**) {
-  {
-    typedef MyMutex M;
-    M m;
-    m.lock();
-    std::unique_lock<M> lk(m, std::adopt_lock);
-    assert(lk.mutex() == std::addressof(m));
-    assert(lk.owns_lock() == true);
-  }
-  {
-    typedef nasty_mutex M;
-    M m;
-    m.lock();
-    std::unique_lock<M> lk(m, std::adopt_lock);
-    assert(lk.mutex() == std::addressof(m));
-    assert(lk.owns_lock() == true);
-  }
+  checking_mutex m;
+  m.lock();
+  m.last_try = checking_mutex::none;
+  std::unique_lock<checking_mutex> lk(m, std::adopt_lock_t());
+  assert(m.last_try == checking_mutex::none);
+  assert(lk.mutex() == std::addressof(m));
+  assert(lk.owns_lock());
 
   return 0;
 }
diff --git a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/mutex_defer_lock.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/mutex_defer_lock.pass.cpp
index 96a9afbc9438c4..4335892dd28477 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/mutex_defer_lock.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/mutex_defer_lock.pass.cpp
@@ -5,8 +5,6 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
-//
-// UNSUPPORTED: c++03
 
 // <mutex>
 
@@ -15,27 +13,24 @@
 // unique_lock(mutex_type& m, defer_lock_t);
 
 #include <cassert>
+#include <memory>
 #include <mutex>
+#include <type_traits>
 
-#include "nasty_containers.h"
-#include "../types.h"
+#include "checking_mutex.h"
 #include "test_macros.h"
 
+#if TEST_STD_VER >= 11
+static_assert(
+    std::is_nothrow_constructible<std::unique_lock<checking_mutex>, checking_mutex&, std::defer_lock_t>::value, "");
+#endif
+
 int main(int, char**) {
-  {
-    typedef MyMutex M;
-    M m;
-    std::unique_lock<M> lk(m, std::defer_lock);
-    assert(lk.mutex() == std::addressof(m));
-    assert(lk.owns_lock() == false);
-  }
-  {
-    typedef nasty_mutex M;
-    M m;
-    std::unique_lock<M> lk(m, std::defer_lock);
-    assert(lk.mutex() == std::addressof(m));
-    assert(lk.owns_lock() == false);
-  }
+  checking_mutex m;
+  std::unique_lock<checking_mutex> lk(m, std::defer_lock_t());
+  assert(m.last_try == checking_mutex::none);
+  assert(lk.mutex() == std::addressof(m));
+  assert(lk.owns_lock() == false);
 
   return 0;
 }
diff --git a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/mutex_duration.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/mutex_duration.pass.cpp
index 4bfabab919f177..624b99623d6be7 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/mutex_duration.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/mutex_duration.pass.cpp
@@ -5,69 +5,36 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
-//
-// UNSUPPORTED: no-threads
-// ALLOW_RETRIES: 2
 
 // <mutex>
 
-// class timed_mutex;
-
 // template <class Rep, class Period>
-//   unique_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time);
+// unique_lock::unique_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time);
 
-#include <mutex>
-#include <thread>
-#include <cstdlib>
 #include <cassert>
+#include <chrono>
+#include <mutex>
 
-#include "make_test_thread.h"
-#include "test_macros.h"
-
-std::timed_mutex m;
-
-typedef std::chrono::steady_clock Clock;
-typedef Clock::time_point time_point;
-typedef Clock::duration duration;
-typedef std::chrono::milliseconds ms;
-typedef std::chrono::nanoseconds ns;
-
-void f1()
-{
-    time_point t0 = Clock::now();
-    std::unique_lock<std::timed_mutex> lk(m, ms(300));
-    assert(lk.owns_lock() == true);
-    time_point t1 = Clock::now();
-    ns d = t1 - t0 - ms(250);
-    assert(d < ms(50));  // within 50ms
-}
-
-void f2()
-{
-    time_point t0 = Clock::now();
-    std::unique_lock<std::timed_mutex> lk(m, ms(250));
-    assert(lk.owns_lock() == false);
-    time_point t1 = Clock::now();
-    ns d = t1 - t0 - ms(250);
-    assert(d < ms(50));  // within 50ms
-}
-
-int main(int, char**)
-{
-    {
-        m.lock();
-        std::thread t = support::make_test_thread(f1);
-        std::this_thread::sleep_for(ms(250));
-        m.unlock();
-        t.join();
-    }
-    {
-        m.lock();
-        std::thread t = support::make_test_thread(f2);
-        std::this_thread::sleep_for(ms(300));
-        m.unlock();
-        t.join();
-    }
+#include "checking_mutex.h"
+
+int main(int, char**) {
+  checking_mutex mux;
+  { // check successful lock
+    mux.reject = false;
+    std::unique_lock<checking_mutex> lock(mux, std::chrono::seconds());
+    assert(mux.current_state == checking_mutex::locked_via_try_lock_for);
+    assert(lock.owns_lock());
+  }
+  assert(mux.current_state == checking_mutex::unlocked);
+
+  { // check unsuccessful lock
+    mux.reject = true;
+    std::unique_lock<checking_mutex> lock(mux, std::chrono::seconds());
+    assert(mux.current_state == checking_mutex::unlocked);
+    assert(mux.last_try == checking_mutex::locked_via_try_lock_for);
+    assert(!lock.owns_lock());
+  }
+  assert(mux.current_state == checking_mutex::unlocked);
 
   return 0;
 }
diff --git a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/mutex_time_point.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/mutex_time_point.pass.cpp
index b85bbace3233c1..93d322050476f6 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/mutex_time_point.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/mutex_time_point.pass.cpp
@@ -5,69 +5,37 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
-//
-// UNSUPPORTED: no-threads
-// ALLOW_RETRIES: 2
 
 // <mutex>
 
-// class timed_mutex;
-
 // template <class Clock, class Duration>
-//   unique_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time);
+// unique_lock::unique_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time);
 
-#include <mutex>
-#include <thread>
-#include <cstdlib>
 #include <cassert>
+#include <chrono>
+#include <mutex>
 
-#include "make_test_thread.h"
-#include "test_macros.h"
-
-std::timed_mutex m;
-
-typedef std::chrono::steady_clock Clock;
-typedef Clock::time_point time_point;
-typedef Clock::duration duration;
-typedef std::chrono::milliseconds ms;
-typedef std::chrono::nanoseconds ns;
-
-void f1()
-{
-    time_point t0 = Clock::now();
-    std::unique_lock<std::timed_mutex> lk(m, Clock::now() + ms(300));
-    assert(lk.owns_lock() == true);
-    time_point t1 = Clock::now();
-    ns d = t1 - t0 - ms(250);
-    assert(d < ns(50000000));  // within 50ms
-}
-
-void f2()
-{
-    time_point t0 = Clock::now();
-    std::unique_lock<std::timed_mutex> lk(m, Clock::now() + ms(250));
-    assert(lk.owns_lock() == false);
-    time_point t1 = Clock::now();
-    ns d = t1 - t0 - ms(250);
-    assert(d < ms(50));  // within 50ms
-}
-
-int main(int, char**)
-{
-    {
-        m.lock();
-        std::thread t = support::make_test_thread(f1);
-        std::this_thread::sleep_for(ms(250));
-        m.unlock();
-        t.join();
-    }
-    {
-        m.lock();
-        std::thread t = support::make_test_thread(f2);
-        std::this_thread::sleep_for(ms(300));
-        m.unlock();
-        t.join();
-    }
+#include "checking_mutex.h"
+
+int main(int, char**) {
+  checking_mutex mux;
+
+  { // check successful lock
+    mux.reject = false;
+    std::unique_lock<checking_mutex> lock(mux, std::chrono::time_point<std::chrono::system_clock>());
+    assert(mux.current_state == checking_mutex::locked_via_try_lock_until);
+    assert(lock.owns_lock());
+  }
+  assert(mux.current_state == checking_mutex::unlocked);
+
+  { // check unsuccessful lock
+    mux.reject = true;
+    std::unique_lock<checking_mutex> lock(mux, std::chrono::time_point<std::chrono::system_clock>());
+    assert(mux.current_state == checking_mutex::unlocked);
+    assert(mux.last_try == checking_mutex::locked_via_try_lock_until);
+    assert(!lock.owns_lock());
+  }
+  assert(mux.current_state == checking_mutex::unlocked);
 
   return 0;
 }
diff --git a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/mutex_try_to_lock.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/mutex_try_to_lock.pass.cpp
index 992d383dfa780d..e7af0fc34e7509 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/mutex_try_to_lock.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/mutex_try_to_lock.pass.cpp
@@ -6,10 +6,6 @@
 //
 //===----------------------------------------------------------------------===//
 
-// UNSUPPORTED: no-threads
-// UNSUPPORTED: c++03
-// ALLOW_RETRIES: 2
-
 // <mutex>
 
 // template <class Mutex> class unique_lock;
@@ -17,55 +13,29 @@
 // unique_lock(mutex_type& m, try_to_lock_t);
 
 #include <cassert>
-#include <chrono>
-#include <cstdlib>
 #include <mutex>
-#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();
-    {
-        std::unique_lock<std::mutex> lk(m, std::try_to_lock);
-        assert(lk.owns_lock() == false);
-    }
-    {
-        std::unique_lock<std::mutex> lk(m, std::try_to_lock);
-        assert(lk.owns_lock() == false);
-    }
-    {
-        std::unique_lock<std::mutex> lk(m, std::try_to_lock);
-        assert(lk.owns_lock() == false);
-    }
-    while (true)
-    {
-        std::unique_lock<std::mutex> lk(m, std::try_to_lock);
-        if (lk.owns_lock())
-            break;
-    }
-    time_point t1 = Clock::now();
-    ns d = t1 - t0 - ms(250);
-    assert(d < ms(200));  // within 200ms
-}
 
-int main(int, char**)
-{
-    m.lock();
-    std::thread t = support::make_test_thread(f);
-    std::this_thread::sleep_for(ms(250));
-    m.unlock();
-    t.join();
+#include "checking_mutex.h"
+
+int main(int, char**) {
+  checking_mutex mux;
+
+  { // check successful lock
+    mux.reject = false;
+    std::unique_lock<checking_mutex> lock(mux, std::try_to_lock_t());
+    assert(mux.current_state == checking_mutex::locked_via_try_lock);
+    assert(lock.owns_lock());
+  }
+  assert(mux.current_state == checking_mutex::unlocked);
+
+  { // check successful lock
+    mux.reject = true;
+    std::unique_lock<checking_mutex> lock(mux, std::try_to_lock_t());
+    assert(mux.last_try == checking_mutex::locked_via_try_lock);
+    assert(mux.current_state == checking_mutex::unlocked);
+    assert(!lock.owns_lock());
+  }
+  assert(mux.current_state == checking_mutex::unlocked);
 
   return 0;
 }
diff --git a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.locking/lock.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.locking/lock.pass.cpp
index 6767e11a1f8b49..4be1eaa5e1b95f 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.locking/lock.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.locking/lock.pass.cpp
@@ -5,10 +5,6 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
-//
-// UNSUPPORTED: no-threads
-// UNSUPPORTED: c++03
-// ALLOW_RETRIES: 2
 
 // <mutex>
 
@@ -17,65 +13,42 @@
 // void lock();
 
 #include <cassert>
-#include <chrono>
-#include <cstdlib>
 #include <mutex>
 #include <system_error>
-#include <thread>
 
-#include "make_test_thread.h"
+#include "checking_mutex.h"
 #include "test_macros.h"
 
-std::mutex m;
+int main(int, char**) {
+  checking_mutex mux;
+  std::unique_lock<checking_mutex> lk(mux, std::defer_lock_t());
+  assert(mux.last_try == checking_mutex::none);
+  lk.lock();
+  assert(mux.current_state == checking_mutex::locked_via_lock);
+  mux.last_try = checking_mutex::none;
 
-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;
+#ifndef TEST_HAS_NO_EXCEPTIONS
+  try {
+    mux.last_try = checking_mutex::none;
+    lk.lock();
+    assert(false);
+  } catch (std::system_error& e) {
+    assert(mux.last_try == checking_mutex::none);
+    assert(e.code() == std::errc::resource_deadlock_would_occur);
+  }
 
-void f()
-{
-    std::unique_lock<std::mutex> lk(m, std::defer_lock);
-    time_point t0 = Clock::now();
+  lk.unlock();
+  lk.release();
+
+  try {
+    mux.last_try = checking_mutex::none;
     lk.lock();
-    time_point t1 = Clock::now();
-    assert(lk.owns_lock() == true);
-    ns d = t1 - t0 - ms(250);
-    assert(d < ms(25));  // within 25ms
-#ifndef TEST_HAS_NO_EXCEPTIONS
-    try
-    {
-        lk.lock();
-        assert(false);
-    }
-    catch (std::system_error& e)
-    {
-      assert(e.code() == std::errc::resource_deadlock_would_occur);
-    }
+    assert(false);
+  } catch (std::system_error& e) {
+    assert(mux.last_try == checking_mutex::none);
+    assert(e.code() == std::errc::operation_not_permitted);
+  }
 #endif
-    lk.unlock();
-    lk.release();
-#ifndef TEST_HAS_NO_EXCEPTIONS
-    try
-    {
-        lk.lock();
-        assert(false);
-    }
-    catch (std::system_error& e)
-    {
-      assert(e.code() == std::errc::operation_not_permitted);
-    }
-#endif
-}
-
-int main(int, char**)
-{
-    m.lock();
-    std::thread t = support::make_test_thread(f);
-    std::this_thread::sleep_for(ms(250));
-    m.unlock();
-    t.join();
 
   return 0;
 }
diff --git a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.locking/try_lock.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.locking/try_lock.pass.cpp
index 2ee5d3766eb18e..41a5957480556b 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.locking/try_lock.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.locking/try_lock.pass.cpp
@@ -5,9 +5,6 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
-//
-// UNSUPPORTED: c++03
-// ALLOW_RETRIES: 2
 
 // <mutex>
 
@@ -20,33 +17,43 @@
 #include <system_error>
 
 #include "test_macros.h"
-#include "../types.h"
-
-MyTimedMutex m;
+#include "checking_mutex.h"
 
 int main(int, char**) {
-  std::unique_lock<MyTimedMutex> lk(m, std::defer_lock);
-  assert(lk.try_lock() == true);
-  assert(m.try_lock_called == true);
-  assert(lk.owns_lock() == true);
+  checking_mutex mux;
+
+  std::unique_lock<checking_mutex> lock(mux, std::defer_lock_t());
+  assert(lock.try_lock());
+  assert(mux.current_state == checking_mutex::locked_via_try_lock);
+  assert(lock.owns_lock());
+
 #ifndef TEST_HAS_NO_EXCEPTIONS
   try {
-    TEST_IGNORE_NODISCARD lk.try_lock();
+    mux.last_try = checking_mutex::none;
+    TEST_IGNORE_NODISCARD lock.try_lock();
     assert(false);
   } catch (std::system_error& e) {
+    assert(mux.last_try == checking_mutex::none);
     assert(e.code() == std::errc::resource_deadlock_would_occur);
   }
 #endif
-  lk.unlock();
-  assert(lk.try_lock() == false);
-  assert(m.try_lock_called == false);
-  assert(lk.owns_lock() == false);
-  lk.release();
+
+  lock.unlock();
+  mux.reject = true;
+
+  assert(!lock.try_lock());
+  assert(mux.last_try == checking_mutex::locked_via_try_lock);
+
+  assert(!lock.owns_lock());
+  lock.release();
+
 #ifndef TEST_HAS_NO_EXCEPTIONS
   try {
-    TEST_IGNORE_NODISCARD lk.try_lock();
+    mux.last_try = checking_mutex::none;
+    (void)lock.try_lock();
     assert(false);
   } catch (std::system_error& e) {
+    assert(mux.last_try == checking_mutex::none);
     assert(e.code() == std::errc::operation_not_permitted);
   }
 #endif
diff --git a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.locking/try_lock_for.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.locking/try_lock_for.pass.cpp
index 603cc7b185620c..cfe81a8faf3386 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.locking/try_lock_for.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.locking/try_lock_for.pass.cpp
@@ -5,8 +5,6 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
-//
-// UNSUPPORTED: c++03
 
 // <mutex>
 
@@ -20,34 +18,47 @@
 #include <system_error>
 
 #include "test_macros.h"
-#include "../types.h"
-
-MyTimedMutex m;
+#include "checking_mutex.h"
 
 int main(int, char**) {
   using ms = std::chrono::milliseconds;
-  std::unique_lock<MyTimedMutex> lk(m, std::defer_lock);
-  assert(lk.try_lock_for(ms(5)) == true);
-  assert(m.try_lock_for_called == true);
-  assert(lk.owns_lock() == true);
+
+  checking_mutex mux;
+
+  std::unique_lock<checking_mutex> lock(mux, std::defer_lock_t());
+
+  assert(lock.try_lock_for(ms(5)));
+  assert(mux.current_state == checking_mutex::locked_via_try_lock_for);
+  assert(lock.owns_lock());
+
 #ifndef TEST_HAS_NO_EXCEPTIONS
   try {
-    TEST_IGNORE_NODISCARD lk.try_lock_for(ms(5));
+    mux.last_try = checking_mutex::none;
+    (void)lock.try_lock_for(ms(5));
+
     assert(false);
   } catch (std::system_error& e) {
+    assert(mux.last_try == checking_mutex::none);
     assert(e.code() == std::errc::resource_deadlock_would_occur);
   }
 #endif
-  lk.unlock();
-  assert(lk.try_lock_for(ms(5)) == false);
-  assert(m.try_lock_for_called == false);
-  assert(lk.owns_lock() == false);
-  lk.release();
+
+  lock.unlock();
+  mux.reject = true;
+  assert(!lock.try_lock_for(ms(5)));
+  assert(mux.last_try == checking_mutex::locked_via_try_lock_for);
+  assert(!lock.owns_lock());
+
+  lock.release();
+
 #ifndef TEST_HAS_NO_EXCEPTIONS
   try {
-    TEST_IGNORE_NODISCARD lk.try_lock_for(ms(5));
+    mux.last_try = checking_mutex::none;
+    (void)lock.try_lock_for(ms(5));
+
     assert(false);
   } catch (std::system_error& e) {
+    assert(mux.last_try == checking_mutex::none);
     assert(e.code() == std::errc::operation_not_permitted);
   }
 #endif
diff --git a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.locking/try_lock_until.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.locking/try_lock_until.pass.cpp
index 46ab95197311c0..bc261f681020f3 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.locking/try_lock_until.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.locking/try_lock_until.pass.cpp
@@ -5,8 +5,6 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
-//
-// UNSUPPORTED: c++03
 
 // <mutex>
 
@@ -20,35 +18,44 @@
 #include <mutex>
 #include <system_error>
 
+#include "checking_mutex.h"
 #include "test_macros.h"
-#include "../types.h"
-
-MyTimedMutex m;
 
 int main(int, char**) {
   typedef std::chrono::system_clock Clock;
-  std::unique_lock<MyTimedMutex> lk(m, std::defer_lock);
-  assert(lk.try_lock_until(Clock::now()) == true);
-  assert(m.try_lock_until_called == true);
-  assert(lk.owns_lock() == true);
+  checking_mutex mux;
+
+  std::unique_lock<checking_mutex> lock(mux, std::defer_lock_t());
+
+  assert(lock.try_lock_until(Clock::now()));
+  assert(mux.current_state == checking_mutex::locked_via_try_lock_until);
+  assert(lock.owns_lock());
+
 #ifndef TEST_HAS_NO_EXCEPTIONS
   try {
-    TEST_IGNORE_NODISCARD lk.try_lock_until(Clock::now());
+    mux.last_try = checking_mutex::none;
+    (void)lock.try_lock_until(Clock::now());
     assert(false);
   } catch (std::system_error& e) {
+    assert(mux.last_try == checking_mutex::none);
     assert(e.code() == std::errc::resource_deadlock_would_occur);
   }
 #endif
-  lk.unlock();
-  assert(lk.try_lock_until(Clock::now()) == false);
-  assert(m.try_lock_until_called == false);
-  assert(lk.owns_lock() == false);
-  lk.release();
+
+  lock.unlock();
+  mux.reject = true;
+  assert(!lock.try_lock_until(Clock::now()));
+  assert(mux.last_try == checking_mutex::locked_via_try_lock_until);
+  assert(lock.owns_lock() == false);
+  lock.release();
+
 #ifndef TEST_HAS_NO_EXCEPTIONS
   try {
-    TEST_IGNORE_NODISCARD lk.try_lock_until(Clock::now());
+    mux.last_try = checking_mutex::none;
+    (void)lock.try_lock_until(Clock::now());
     assert(false);
   } catch (std::system_error& e) {
+    assert(mux.last_try == checking_mutex::none);
     assert(e.code() == std::errc::operation_not_permitted);
   }
 #endif
diff --git a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.locking/unlock.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.locking/unlock.pass.cpp
index 97808f60f2e552..cfc44a6cd5d254 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.locking/unlock.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.locking/unlock.pass.cpp
@@ -17,28 +17,36 @@
 #include <system_error>
 
 #include "test_macros.h"
-#include "../types.h"
-
-MyMutex m;
+#include "checking_mutex.h"
 
 int main(int, char**) {
-  std::unique_lock<MyMutex> lk(m);
-  lk.unlock();
-  assert(lk.owns_lock() == false);
+  checking_mutex mux;
+  std::unique_lock<checking_mutex> lock(mux);
+  assert(mux.current_state == checking_mutex::locked_via_lock);
+  lock.unlock();
+  assert(mux.current_state == checking_mutex::unlocked);
+  assert(!lock.owns_lock());
+
 #ifndef TEST_HAS_NO_EXCEPTIONS
   try {
-    lk.unlock();
+    mux.last_try = checking_mutex::none;
+    lock.unlock();
     assert(false);
   } catch (std::system_error& e) {
+    assert(mux.last_try == checking_mutex::none);
     assert(e.code() == std::errc::operation_not_permitted);
   }
 #endif
-  lk.release();
+
+  lock.release();
+
 #ifndef TEST_HAS_NO_EXCEPTIONS
   try {
-    lk.unlock();
+    mux.last_try = checking_mutex::none;
+    lock.unlock();
     assert(false);
   } catch (std::system_error& e) {
+    assert(mux.last_try == checking_mutex::none);
     assert(e.code() == std::errc::operation_not_permitted);
   }
 #endif
diff --git a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.mod/member_swap.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.mod/member_swap.pass.cpp
index 361c85e0150597..e2ffbf4a23a9c5 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.mod/member_swap.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.mod/member_swap.pass.cpp
@@ -13,21 +13,29 @@
 // void swap(unique_lock& u);
 
 #include <cassert>
+#include <memory>
 #include <mutex>
 
+#include "checking_mutex.h"
 #include "test_macros.h"
-#include "../types.h"
 
-MyMutex m;
+#if TEST_STD_VER >= 11
+static_assert(
+    noexcept(std::declval<std::unique_lock<checking_mutex>&>().swap(std::declval<std::unique_lock<checking_mutex>&>())),
+    "");
+#endif
 
 int main(int, char**) {
-  std::unique_lock<MyMutex> lk1(m);
-  std::unique_lock<MyMutex> lk2;
-  lk1.swap(lk2);
-  assert(lk1.mutex() == nullptr);
-  assert(lk1.owns_lock() == false);
-  assert(lk2.mutex() == &m);
-  assert(lk2.owns_lock() == true);
+  checking_mutex mux;
+  std::unique_lock<checking_mutex> lock1(mux);
+  std::unique_lock<checking_mutex> lock2;
+
+  lock1.swap(lock2);
+
+  assert(lock1.mutex() == nullptr);
+  assert(!lock1.owns_lock());
+  assert(lock2.mutex() == std::addressof(mux));
+  assert(lock2.owns_lock() == true);
 
   return 0;
 }
diff --git a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.mod/nonmember_swap.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.mod/nonmember_swap.pass.cpp
index 5133032f6ae39e..3e89e6c66bf3e0 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.mod/nonmember_swap.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.mod/nonmember_swap.pass.cpp
@@ -14,21 +14,29 @@
 //   void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y);
 
 #include <cassert>
+#include <memory>
 #include <mutex>
 
+#include "checking_mutex.h"
 #include "test_macros.h"
-#include "../types.h"
 
-MyMutex m;
+#if TEST_STD_VER >= 11
+static_assert(noexcept(swap(std::declval<std::unique_lock<checking_mutex>&>(),
+                            std::declval<std::unique_lock<checking_mutex>&>())),
+              "");
+#endif
 
 int main(int, char**) {
-  std::unique_lock<MyMutex> lk1(m);
-  std::unique_lock<MyMutex> lk2;
-  swap(lk1, lk2);
-  assert(lk1.mutex() == nullptr);
-  assert(lk1.owns_lock() == false);
-  assert(lk2.mutex() == &m);
-  assert(lk2.owns_lock() == true);
+  checking_mutex mux;
+  std::unique_lock<checking_mutex> lock1(mux);
+  std::unique_lock<checking_mutex> lock2;
+
+  swap(lock1, lock2);
+
+  assert(lock1.mutex() == nullptr);
+  assert(!lock1.owns_lock());
+  assert(lock2.mutex() == std::addressof(mux));
+  assert(lock2.owns_lock() == true);
 
   return 0;
 }
diff --git a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.mod/release.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.mod/release.pass.cpp
index a726c8ccc060a1..a7724504a667c1 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.mod/release.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.mod/release.pass.cpp
@@ -13,27 +13,30 @@
 // mutex_type* release() noexcept;
 
 #include <cassert>
+#include <memory>
 #include <mutex>
 
+#include "checking_mutex.h"
 #include "test_macros.h"
-#include "../types.h"
 
-int MyCountingMutex::lock_count   = 0;
-int MyCountingMutex::unlock_count = 0;
-
-MyCountingMutex m;
+#if TEST_STD_VER >= 11
+static_assert(noexcept(std::declval<std::unique_lock<checking_mutex>&>().release()), "");
+#endif
 
 int main(int, char**) {
-  std::unique_lock<MyCountingMutex> lk(m);
-  assert(lk.mutex() == &m);
-  assert(lk.owns_lock() == true);
-  assert(MyCountingMutex::lock_count == 1);
-  assert(MyCountingMutex::unlock_count == 0);
-  assert(lk.release() == &m);
-  assert(lk.mutex() == nullptr);
-  assert(lk.owns_lock() == false);
-  assert(MyCountingMutex::lock_count == 1);
-  assert(MyCountingMutex::unlock_count == 0);
+  checking_mutex mux;
+  std::unique_lock<checking_mutex> lock(mux);
+  assert(lock.mutex() == std::addressof(mux));
+  assert(lock.owns_lock());
+
+  assert(mux.current_state == checking_mutex::locked_via_lock);
+
+  assert(lock.release() == std::addressof(mux));
+  assert(lock.mutex() == nullptr);
+  assert(!lock.owns_lock());
+  assert(mux.last_try == checking_mutex::locked_via_lock);
+  assert(mux.current_state == checking_mutex::locked_via_lock);
+  mux.unlock();
 
   return 0;
 }
diff --git a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.obs/mutex.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.obs/mutex.pass.cpp
index 72346e8c67e257..f00614015bbc3b 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.obs/mutex.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.obs/mutex.pass.cpp
@@ -13,20 +13,25 @@
 // mutex_type *mutex() const;
 
 #include <cassert>
+#include <memory>
 #include <mutex>
 
+#include "checking_mutex.h"
 #include "test_macros.h"
-#include "../types.h"
 
-MyMutex m;
+#if TEST_STD_VER >= 11
+static_assert(noexcept(std::declval<std::unique_lock<checking_mutex>&>().mutex()), "");
+#endif
 
 int main(int, char**) {
-  std::unique_lock<MyMutex> lk0;
-  assert(lk0.mutex() == nullptr);
-  std::unique_lock<MyMutex> lk1(m);
-  assert(lk1.mutex() == &m);
-  lk1.unlock();
-  assert(lk1.mutex() == &m);
+  checking_mutex mux;
+  const std::unique_lock<checking_mutex> lock0; // Make sure `mutex()` is `const`
+  static_assert(std::is_same<decltype(lock0.mutex()), checking_mutex*>::value, "");
+  assert(lock0.mutex() == nullptr);
+  std::unique_lock<checking_mutex> lock1(mux);
+  assert(lock1.mutex() == std::addressof(mux));
+  lock1.unlock();
+  assert(lock1.mutex() == std::addressof(mux));
 
   return 0;
 }
diff --git a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.obs/op_bool.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.obs/op_bool.pass.cpp
index 3759302a483eb2..3542a40d25d39e 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.obs/op_bool.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.obs/op_bool.pass.cpp
@@ -16,21 +16,25 @@
 #include <mutex>
 #include <type_traits>
 
+#include "checking_mutex.h"
 #include "test_macros.h"
-#include "../types.h"
 
-MyMutex m;
+#if TEST_STD_VER >= 11
+static_assert(noexcept(static_cast<bool>(std::declval<std::unique_lock<checking_mutex>&>())), "");
+#endif
 
 int main(int, char**) {
-  static_assert(std::is_constructible<bool, std::unique_lock<MyMutex> >::value, "");
-  static_assert(!std::is_convertible<std::unique_lock<MyMutex>, bool>::value, "");
-
-  std::unique_lock<MyMutex> lk0;
-  assert(static_cast<bool>(lk0) == false);
-  std::unique_lock<MyMutex> lk1(m);
-  assert(static_cast<bool>(lk1) == true);
+  static_assert(std::is_constructible<bool, std::unique_lock<checking_mutex> >::value, "");
+  static_assert(!std::is_convertible<std::unique_lock<checking_mutex>, bool>::value, "");
+
+  checking_mutex mux;
+  const std::unique_lock<checking_mutex> lk0; // Make sure `operator bool()` is `const`
+  assert(!static_cast<bool>(lk0));
+  std::unique_lock<checking_mutex> lk1(mux);
+  assert(static_cast<bool>(lk1));
   lk1.unlock();
-  assert(static_cast<bool>(lk1) == false);
+  assert(!static_cast<bool>(lk1));
+
   ASSERT_NOEXCEPT(static_cast<bool>(lk0));
 
   return 0;
diff --git a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.obs/owns_lock.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.obs/owns_lock.pass.cpp
index 163942786323af..11a674a55392fe 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.obs/owns_lock.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.obs/owns_lock.pass.cpp
@@ -15,18 +15,23 @@
 #include <cassert>
 #include <mutex>
 
+#include "checking_mutex.h"
 #include "test_macros.h"
-#include "../types.h"
 
-MyMutex m;
+#if TEST_STD_VER >= 11
+static_assert(noexcept(std::declval<std::unique_lock<checking_mutex>&>().owns_lock()), "");
+#endif
 
 int main(int, char**) {
-  std::unique_lock<MyMutex> lk0;
-  assert(lk0.owns_lock() == false);
-  std::unique_lock<MyMutex> lk1(m);
-  assert(lk1.owns_lock() == true);
-  lk1.unlock();
-  assert(lk1.owns_lock() == false);
+  {
+    checking_mutex mux;
+    const std::unique_lock<checking_mutex> lock0; // Make sure `owns_lock()` is `const`
+    assert(!lock0.owns_lock());
+    std::unique_lock<checking_mutex> lock1(mux);
+    assert(lock1.owns_lock());
+    lock1.unlock();
+    assert(!lock1.owns_lock());
+  }
 
   return 0;
 }
diff --git a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/types.compile.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/types.compile.pass.cpp
index 312863ae8e743a..56055788965d53 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/types.compile.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/types.compile.pass.cpp
@@ -19,7 +19,6 @@
 #include <mutex>
 #include <type_traits>
 
-#include "test_macros.h"
-#include "types.h"
+#include "checking_mutex.h"
 
-static_assert((std::is_same<std::unique_lock<MyMutex>::mutex_type, MyMutex>::value), "");
+static_assert(std::is_same<std::unique_lock<checking_mutex>::mutex_type, checking_mutex>::value, "");
diff --git a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/types.h b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/types.h
deleted file mode 100644
index 15a1a531487f50..00000000000000
--- a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/types.h
+++ /dev/null
@@ -1,88 +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
-//
-//===----------------------------------------------------------------------===//
-
-#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>
-#include <chrono>
-
-struct MyMutex {
-  bool locked = false;
-
-  MyMutex() = default;
-  ~MyMutex() { assert(!locked); }
-
-  void lock() {
-    assert(!locked);
-    locked = true;
-  }
-
-  void unlock() {
-    assert(locked);
-    locked = false;
-  }
-
-  bool try_lock() {
-    if (locked)
-      return false;
-    lock();
-    return true;
-  }
-
-  template <class Rep, class Period>
-  bool try_lock_for(const std::chrono::duration<Rep, Period>& rel_time) {
-    using ms = std::chrono::milliseconds;
-    assert(rel_time == ms(5));
-    if (locked)
-      return false;
-    lock();
-    return true;
-  }
-
-  MyMutex(MyMutex const&)            = delete;
-  MyMutex& operator=(MyMutex const&) = delete;
-};
-
-struct MyTimedMutex {
-  using ms = std::chrono::milliseconds;
-
-  bool try_lock_called       = false;
-  bool try_lock_for_called   = false;
-  bool try_lock_until_called = false;
-
-  bool try_lock() {
-    try_lock_called = !try_lock_called;
-    return try_lock_called;
-  }
-
-  template <class Rep, class Period>
-  bool try_lock_for(const std::chrono::duration<Rep, Period>& rel_time) {
-    assert(rel_time == ms(5));
-    try_lock_for_called = !try_lock_for_called;
-    return try_lock_for_called;
-  }
-
-  template <class Clock, class Duration>
-  bool try_lock_until(const std::chrono::time_point<Clock, Duration>& abs_time) {
-    assert(Clock::now() - abs_time < ms(5));
-    try_lock_until_called = !try_lock_until_called;
-    return try_lock_until_called;
-  }
-
-  void unlock() {}
-};
-
-struct MyCountingMutex {
-  static int lock_count;
-  static int unlock_count;
-  void lock() { ++lock_count; }
-  void unlock() { ++unlock_count; }
-};
-
-#endif // TEST_STD_THREAD_THREAD_MUTEX_THREAD_LOCK_THREAD_LOCK_GUARD_TYPES_H
diff --git a/libcxx/test/support/checking_mutex.h b/libcxx/test/support/checking_mutex.h
new file mode 100644
index 00000000000000..1a635c32f29a6b
--- /dev/null
+++ b/libcxx/test/support/checking_mutex.h
@@ -0,0 +1,80 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_SUPPORT_CHECKING_MUTEX_H
+#define TEST_SUPPORT_CHECKING_MUTEX_H
+
+#include <cassert>
+#include <chrono>
+
+struct checking_mutex {
+  enum state {
+    locked_via_lock,
+    locked_via_try_lock,
+    locked_via_try_lock_for,
+    locked_via_try_lock_until,
+    unlocked,
+    none,
+  };
+
+  state current_state = unlocked;
+  state last_try      = none;
+  bool reject         = false;
+
+  checking_mutex()                      = default;
+  checking_mutex(const checking_mutex&) = delete;
+  ~checking_mutex() { assert(current_state == unlocked); }
+
+  void lock() {
+    assert(current_state == unlocked);
+    assert(!reject);
+    current_state = locked_via_lock;
+    last_try      = locked_via_lock;
+    reject        = true;
+  }
+
+  void unlock() {
+    assert(current_state != unlocked && current_state != none);
+    last_try      = unlocked;
+    current_state = unlocked;
+    reject        = false;
+  }
+
+  bool try_lock() {
+    last_try = locked_via_try_lock;
+    if (reject)
+      return false;
+    current_state = locked_via_try_lock;
+    return true;
+  }
+
+  template <class Rep, class Period>
+  bool try_lock_for(const std::chrono::duration<Rep, Period>&) {
+    last_try = locked_via_try_lock_for;
+    if (reject)
+      return false;
+    current_state = locked_via_try_lock_for;
+    return true;
+  }
+
+  template <class Clock, class Duration>
+  bool try_lock_until(const std::chrono::time_point<Clock, Duration>&) {
+    last_try = locked_via_try_lock_until;
+    if (reject)
+      return false;
+    current_state = locked_via_try_lock_until;
+    return true;
+  }
+
+  checking_mutex* operator&() = delete;
+
+  template <class T>
+  void operator,(const T&) = delete;
+};
+
+#endif // TEST_SUPPORT_CHECKING_MUTEX_H



More information about the libcxx-commits mailing list