]>
Commit | Line | Data |
---|---|---|
d1236680 | 1 | // { dg-do run } |
1e42d2f4 | 2 | // { dg-additional-options "-pthread" { target pthread } } |
71c54f8e | 3 | // { dg-require-effective-target c++11 } |
9b2b801a JW |
4 | // { dg-require-gthreads "" } |
5 | ||
a945c346 | 6 | // Copyright (C) 2010-2024 Free Software Foundation, Inc. |
9b2b801a JW |
7 | // |
8 | // This file is part of the GNU ISO C++ Library. This library is free | |
9 | // software; you can redistribute it and/or modify it under the | |
10 | // terms of the GNU General Public License as published by the | |
11 | // Free Software Foundation; either version 3, or (at your option) | |
12 | // any later version. | |
13 | ||
14 | // This library is distributed in the hope that it will be useful, | |
15 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | // GNU General Public License for more details. | |
18 | ||
19 | // You should have received a copy of the GNU General Public License along | |
20 | // with this library; see the file COPYING3. If not see | |
21 | // <http://www.gnu.org/licenses/>. | |
22 | ||
23 | ||
24 | #include <mutex> | |
25 | #include <testsuite_hooks.h> | |
26 | ||
27 | struct unreliable_lock | |
28 | { | |
29 | std::mutex m; | |
30 | std::unique_lock<std::mutex> l; | |
31 | ||
32 | static int count; | |
33 | static int throw_on; | |
34 | static int lock_on; | |
35 | ||
36 | unreliable_lock() : l(m, std::defer_lock) { } | |
37 | ||
38 | ~unreliable_lock() | |
39 | { | |
9b2b801a JW |
40 | VERIFY( !l.owns_lock() ); |
41 | } | |
42 | ||
43 | void lock() | |
44 | { | |
45 | if (count == throw_on) | |
46 | throw throw_on; | |
47 | ++count; | |
48 | l.lock(); | |
49 | } | |
50 | bool try_lock() | |
51 | { | |
52 | if (count == throw_on) | |
53 | throw throw_on; | |
54 | std::unique_lock<std::mutex> l2(m, std::defer_lock); | |
55 | if (count == lock_on) | |
56 | l2.lock(); | |
57 | ++count; | |
58 | return l.try_lock(); | |
59 | } | |
60 | ||
61 | void unlock() | |
62 | { | |
9b2b801a JW |
63 | VERIFY( l.owns_lock() ); |
64 | l.unlock(); | |
65 | } | |
66 | ||
67 | }; | |
68 | ||
69 | int unreliable_lock::count = 0; | |
70 | int unreliable_lock::throw_on = -1; | |
71 | int unreliable_lock::lock_on = -1; | |
72 | ||
73 | void test01() | |
74 | { | |
9b2b801a | 75 | unreliable_lock l1, l2, l3; |
c5565961 | 76 | std::mutex m1, m2, m3; |
9b2b801a JW |
77 | |
78 | try | |
79 | { | |
80 | unreliable_lock::count = 0; | |
81 | std::lock(l1, l2, l3); | |
82 | VERIFY( unreliable_lock::count == 3 ); | |
83 | l1.unlock(); | |
84 | l2.unlock(); | |
85 | l3.unlock(); | |
86 | } | |
87 | catch (...) | |
88 | { | |
89 | VERIFY( false ); | |
90 | } | |
c5565961 JW |
91 | |
92 | // Repeat with non-heterogeneous arguments | |
93 | ||
94 | try | |
95 | { | |
96 | unreliable_lock::count = 0; | |
97 | std::lock(l1, l2, l3, m1); | |
98 | VERIFY( unreliable_lock::count == 3 ); | |
99 | l1.unlock(); | |
100 | l2.unlock(); | |
101 | l3.unlock(); | |
102 | VERIFY( !m1.try_lock() ); // already locked | |
103 | m1.unlock(); | |
104 | } | |
105 | catch (...) | |
106 | { | |
107 | VERIFY( false ); | |
108 | } | |
109 | ||
110 | try | |
111 | { | |
112 | unreliable_lock::count = 0; | |
113 | std::lock(m1, l1, l2, l3); | |
114 | VERIFY( unreliable_lock::count == 3 ); | |
115 | VERIFY( !m1.try_lock() ); // already locked | |
116 | m1.unlock(); | |
117 | l1.unlock(); | |
118 | l2.unlock(); | |
119 | l3.unlock(); | |
120 | } | |
121 | catch (...) | |
122 | { | |
123 | VERIFY( false ); | |
124 | } | |
125 | ||
126 | try | |
127 | { | |
128 | unreliable_lock::count = 0; | |
129 | std::lock(l1, m1, l2, m2, l3, m3); | |
130 | VERIFY( unreliable_lock::count == 3 ); | |
131 | l1.unlock(); | |
132 | l2.unlock(); | |
133 | l3.unlock(); | |
134 | VERIFY( !m1.try_lock() ); // already locked | |
135 | VERIFY( !m2.try_lock() ); // already locked | |
136 | VERIFY( !m3.try_lock() ); // already locked | |
137 | m1.unlock(); | |
138 | m2.unlock(); | |
139 | m3.unlock(); | |
140 | } | |
141 | catch (...) | |
142 | { | |
143 | VERIFY( false ); | |
144 | } | |
9b2b801a JW |
145 | } |
146 | ||
147 | void test02() | |
148 | { | |
9b2b801a JW |
149 | // test behaviour when a lock is already held |
150 | try | |
151 | { | |
152 | unreliable_lock::lock_on = 1; | |
153 | while (unreliable_lock::lock_on < 3) | |
154 | { | |
155 | unreliable_lock::count = 0; | |
156 | unreliable_lock l1, l2, l3; | |
157 | std::lock(l1, l2, l3); | |
158 | VERIFY( unreliable_lock::count > 3 ); | |
159 | l1.unlock(); | |
160 | l2.unlock(); | |
161 | l3.unlock(); | |
162 | ++unreliable_lock::lock_on; | |
163 | } | |
164 | } | |
165 | catch (...) | |
166 | { | |
167 | VERIFY( false ); | |
168 | } | |
c5565961 JW |
169 | |
170 | // Repeat with non-heterogeneous arguments | |
171 | ||
172 | try | |
173 | { | |
174 | unreliable_lock::lock_on = 1; | |
175 | while (unreliable_lock::lock_on < 3) | |
176 | { | |
177 | unreliable_lock::count = 0; | |
178 | unreliable_lock l1, l2, l3; | |
179 | std::mutex m1; | |
180 | std::lock(l1, l2, l3, m1); | |
181 | VERIFY( unreliable_lock::count > 3 ); | |
182 | l1.unlock(); | |
183 | l2.unlock(); | |
184 | l3.unlock(); | |
185 | VERIFY( !m1.try_lock() ); // already locked | |
186 | m1.unlock(); | |
187 | ++unreliable_lock::lock_on; | |
188 | } | |
189 | } | |
190 | catch (...) | |
191 | { | |
192 | VERIFY( false ); | |
193 | } | |
9b2b801a JW |
194 | } |
195 | ||
196 | void test03() | |
197 | { | |
198 | // test behaviour when an exception is thrown | |
199 | unreliable_lock::throw_on = 0; | |
200 | while (unreliable_lock::throw_on < 3) | |
201 | { | |
202 | unreliable_lock::count = 0; | |
203 | unreliable_lock l1, l2, l3; | |
204 | bool test = false; | |
205 | try | |
206 | { | |
207 | std::lock(l1, l2, l3); | |
208 | } | |
209 | catch (...) | |
210 | { | |
211 | test = true; | |
212 | } | |
213 | VERIFY( test ); | |
214 | ++unreliable_lock::throw_on; | |
215 | } | |
c5565961 JW |
216 | |
217 | // Repeat with non-heterogeneous arguments | |
218 | ||
219 | unreliable_lock::throw_on = 0; | |
220 | while (unreliable_lock::throw_on < 3) | |
221 | { | |
222 | unreliable_lock::count = 0; | |
223 | unreliable_lock l1, l2, l3; | |
224 | std::mutex m1; | |
225 | bool test = false; | |
226 | try | |
227 | { | |
228 | std::lock(l1, l2, l3, m1); | |
229 | } | |
230 | catch (...) | |
231 | { | |
232 | test = true; | |
233 | } | |
234 | VERIFY( test ); | |
235 | VERIFY( m1.try_lock() ); // m1 was not left locked by failed std::lock | |
236 | m1.unlock(); | |
237 | ++unreliable_lock::throw_on; | |
238 | } | |
239 | ||
240 | unreliable_lock::throw_on = 0; | |
241 | while (unreliable_lock::throw_on < 3) | |
242 | { | |
243 | unreliable_lock::count = 0; | |
244 | unreliable_lock l1, l2, l3; | |
245 | std::mutex m1; | |
246 | bool test = false; | |
247 | try | |
248 | { | |
249 | std::lock(m1, l1, l2, l3); | |
250 | } | |
251 | catch (...) | |
252 | { | |
253 | test = true; | |
254 | } | |
255 | VERIFY( test ); | |
256 | VERIFY( m1.try_lock() ); // m1 was not left locked by failed std::lock | |
257 | m1.unlock(); | |
258 | ++unreliable_lock::throw_on; | |
259 | } | |
9b2b801a JW |
260 | } |
261 | ||
262 | int main() | |
263 | { | |
264 | test01(); | |
265 | test02(); | |
266 | test03(); | |
267 | return 0; | |
268 | } |