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: no-threads
10 // UNSUPPORTED: c++03, c++11
11 
12 // <shared_mutex>
13 
14 // class shared_timed_mutex;
15 
16 // void lock();
17 
18 #include <shared_mutex>
19 #include <atomic>
20 #include <cassert>
21 #include <chrono>
22 #include <thread>
23 #include <vector>
24 
25 #include "make_test_thread.h"
26 
27 int main(int, char**) {
28   // Exclusive-lock a mutex that is not locked yet. This should succeed.
29   {
30     std::shared_timed_mutex m;
31     m.lock();
32     m.unlock();
33   }
34 
35   // Exclusive-lock a mutex that is already locked exclusively. This should block until it is unlocked.
36   {
37     std::atomic<bool> ready(false);
38     std::shared_timed_mutex m;
39     m.lock();
40     std::atomic<bool> is_locked_from_main(true);
41 
42     std::thread t = support::make_test_thread([&] {
43       ready = true;
44       m.lock();
45       assert(!is_locked_from_main);
46       m.unlock();
47     });
48 
49     while (!ready)
50       /* spin */;
51 
52     // We would rather signal this after we unlock, but that would create a race condition.
53     // We instead signal it before we unlock, which means that it's technically possible for the thread
54     // to take the lock while we're still holding it and for the test to still pass.
55     is_locked_from_main = false;
56     m.unlock();
57 
58     t.join();
59   }
60 
61   // Exclusive-lock a mutex that is already share-locked. This should block until it is unlocked.
62   {
63     std::atomic<bool> ready(false);
64     std::shared_timed_mutex m;
65     m.lock_shared();
66     std::atomic<bool> is_locked_from_main(true);
67 
68     std::thread t = support::make_test_thread([&] {
69       ready = true;
70       m.lock();
71       assert(!is_locked_from_main);
72       m.unlock();
73     });
74 
75     while (!ready)
76       /* spin */;
77 
78     // We would rather signal this after we unlock, but that would create a race condition.
79     // We instead signal it before we unlock, which means that it's technically possible for
80     // the thread to take the lock while we're still holding it and for the test to still pass.
81     is_locked_from_main = false;
82     m.unlock_shared();
83 
84     t.join();
85   }
86 
87   // Make sure that at most one thread can acquire the mutex concurrently.
88   {
89     std::atomic<int> counter(0);
90     std::shared_timed_mutex mutex;
91 
92     std::vector<std::thread> threads;
93     for (int i = 0; i != 10; ++i) {
94       threads.push_back(support::make_test_thread([&] {
95         mutex.lock();
96         counter++;
97         assert(counter == 1);
98         counter--;
99         mutex.unlock();
100       }));
101     }
102 
103     for (auto& t : threads)
104       t.join();
105   }
106 
107   return 0;
108 }
109