1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9// UNSUPPORTED: c++03
10// UNSUPPORTED: no-threads
11
12// <mutex>
13
14// class recursive_timed_mutex;
15
16// void lock();
17
18#include <mutex>
19#include <atomic>
20#include <cassert>
21#include <thread>
22#include <vector>
23
24#include "make_test_thread.h"
25
26bool is_lockable(std::recursive_timed_mutex& m) {
27 bool did_lock;
28 std::thread t = support::make_test_thread([&] {
29 did_lock = m.try_lock();
30 if (did_lock)
31 m.unlock(); // undo side effects
32 });
33 t.join();
34
35 return did_lock;
36}
37
38int main(int, char**) {
39 // Lock a mutex that is not locked yet. This should succeed.
40 {
41 std::recursive_timed_mutex m;
42 m.lock();
43 m.unlock();
44 }
45
46 // Lock a mutex that is already locked by this thread. This should succeed and the mutex should only
47 // be unlocked after a matching number of calls to unlock() on the same thread.
48 {
49 std::recursive_timed_mutex m;
50 int lock_count = 0;
51 for (int i = 0; i != 10; ++i) {
52 m.lock();
53 ++lock_count;
54 }
55 while (lock_count != 0) {
56 assert(!is_lockable(m));
57 m.unlock();
58 --lock_count;
59 }
60 assert(is_lockable(m));
61 }
62
63 // Lock a mutex that is already locked by another thread. This should block until it is unlocked.
64 {
65 std::atomic<bool> ready(false);
66 std::recursive_timed_mutex m;
67 m.lock();
68 std::atomic<bool> is_locked_from_main(true);
69
70 std::thread t = support::make_test_thread([&] {
71 ready = true;
72 m.lock();
73 assert(!is_locked_from_main);
74 m.unlock();
75 });
76
77 while (!ready)
78 /* spin */;
79
80 // We would rather signal this after we unlock, but that would create a race condition.
81 // We instead signal it before we unlock, which means that it's technically possible for
82 // the thread to take the lock while main is still holding it yet for the test to still pass.
83 is_locked_from_main = false;
84 m.unlock();
85
86 t.join();
87 }
88
89 // Make sure that at most one thread can acquire the mutex concurrently.
90 {
91 std::atomic<int> counter(0);
92 std::recursive_timed_mutex mutex;
93
94 std::vector<std::thread> threads;
95 for (int i = 0; i != 10; ++i) {
96 threads.push_back(support::make_test_thread([&] {
97 mutex.lock();
98 counter++;
99 assert(counter == 1);
100 counter--;
101 mutex.unlock();
102 }));
103 }
104
105 for (auto& t : threads)
106 t.join();
107 }
108
109 return 0;
110}
111

source code of libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.timedmutex.requirements/thread.timedmutex.recursive/lock.pass.cpp