xref: /llvm-project/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.scoped/mutex.pass.cpp (revision 164c204a19f7859d570003d4c5e82faf48cb65a9)
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, c++14
11 
12 // <mutex>
13 
14 // template <class ...Mutex> class scoped_lock;
15 
16 // explicit scoped_lock(mutex_type& m);
17 
18 #include <mutex>
19 #include <cassert>
20 #include "test_macros.h"
21 
22 struct TestMutex {
23     bool locked = false;
24     TestMutex() = default;
~TestMutexTestMutex25     ~TestMutex() { assert(!locked); }
26 
lockTestMutex27     void lock() { assert(!locked); locked = true; }
try_lockTestMutex28     bool try_lock() { if (locked) return false; locked = true; return true; }
unlockTestMutex29     void unlock() { assert(locked); locked = false; }
30 
31     TestMutex(TestMutex const&) = delete;
32     TestMutex& operator=(TestMutex const&) = delete;
33 };
34 
35 #if !defined(TEST_HAS_NO_EXCEPTIONS)
36 struct TestMutexThrows {
37     bool locked = false;
38     bool throws_on_lock = false;
39 
40     TestMutexThrows() = default;
~TestMutexThrowsTestMutexThrows41     ~TestMutexThrows() { assert(!locked); }
42 
lockTestMutexThrows43     void lock() {
44         assert(!locked);
45         if (throws_on_lock) {
46             throw 42;
47         }
48         locked = true;
49     }
50 
try_lockTestMutexThrows51     bool try_lock() {
52         if (locked) return false;
53         lock();
54         return true;
55     }
56 
unlockTestMutexThrows57     void unlock() { assert(locked); locked = false; }
58 
59     TestMutexThrows(TestMutexThrows const&) = delete;
60     TestMutexThrows& operator=(TestMutexThrows const&) = delete;
61 };
62 #endif // !defined(TEST_HAS_NO_EXCEPTIONS)
63 
main(int,char **)64 int main(int, char**)
65 {
66     {
67         using LG = std::scoped_lock<>;
68         LG lg;
69         (void)lg;
70     }
71     {
72         using LG = std::scoped_lock<TestMutex>;
73         TestMutex m1;
74         {
75             LG lg(m1);
76             assert(m1.locked);
77         }
78         assert(!m1.locked);
79     }
80     {
81         using LG = std::scoped_lock<TestMutex, TestMutex>;
82         TestMutex m1, m2;
83         {
84             LG lg(m1, m2);
85             assert(m1.locked && m2.locked);
86         }
87         assert(!m1.locked && !m2.locked);
88     }
89     {
90         using LG = std::scoped_lock<TestMutex, TestMutex, TestMutex>;
91         TestMutex m1, m2, m3;
92         {
93             LG lg(m1, m2, m3);
94             assert(m1.locked && m2.locked && m3.locked);
95         }
96         assert(!m1.locked && !m2.locked && !m3.locked);
97     }
98 #if !defined(TEST_HAS_NO_EXCEPTIONS)
99     {
100         using MT = TestMutexThrows;
101         using LG = std::scoped_lock<MT>;
102         MT m1;
103         m1.throws_on_lock = true;
104         try {
105             LG lg(m1);
106             assert(false);
107         } catch (int) {}
108         assert(!m1.locked);
109     }
110     {
111         using MT = TestMutexThrows;
112         using LG = std::scoped_lock<MT, MT>;
113         MT m1, m2;
114         m1.throws_on_lock = true;
115         try {
116             LG lg(m1, m2);
117             assert(false);
118         } catch (int) {}
119         assert(!m1.locked && !m2.locked);
120     }
121     {
122         using MT = TestMutexThrows;
123         using LG = std::scoped_lock<MT, MT, MT>;
124         MT m1, m2, m3;
125         m2.throws_on_lock = true;
126         try {
127             LG lg(m1, m2, m3);
128             assert(false);
129         } catch (int) {}
130         assert(!m1.locked && !m2.locked && !m3.locked);
131     }
132 #endif
133 
134 #if TEST_STD_VER >= 17
135     {
136     TestMutex m1, m2, m3;
137         {
138         std::scoped_lock sl{};
139         static_assert((std::is_same<decltype(sl), std::scoped_lock<>>::value), "" );
140         }
141         {
142         std::scoped_lock sl{m1};
143         static_assert((std::is_same<decltype(sl), std::scoped_lock<decltype(m1)>>::value), "" );
144         }
145         {
146         std::scoped_lock sl{m1, m2};
147         static_assert((std::is_same<decltype(sl), std::scoped_lock<decltype(m1), decltype(m2)>>::value), "" );
148         }
149         {
150         std::scoped_lock sl{m1, m2, m3};
151         static_assert((std::is_same<decltype(sl), std::scoped_lock<decltype(m1), decltype(m2), decltype(m3)>>::value), "" );
152         }
153     }
154 #endif
155 
156   return 0;
157 }
158