1/* Copyright (C) 2003-2024 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, see
16 <https://www.gnu.org/licenses/>. */
17
18/* This test checks behavior not required by POSIX. */
19#include <errno.h>
20#include <pthread.h>
21#include <stdbool.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <unistd.h>
25#include <elf/dl-tunables.h>
26
27static pthread_mutex_t *m;
28static pthread_barrier_t b;
29static pthread_cond_t c;
30static bool done;
31
32
33static void
34cl (void *arg)
35{
36 if (pthread_mutex_unlock (mutex: m) != 0)
37 {
38 puts (s: "cl: mutex_unlocked failed");
39 exit (1);
40 }
41}
42
43
44static void *
45tf (void *arg)
46{
47 if (pthread_mutex_lock (mutex: m) != 0)
48 {
49 puts (s: "tf: mutex_lock failed");
50 return (void *) 1l;
51 }
52
53 int e = pthread_barrier_wait (barrier: &b);
54 if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
55 {
56 puts (s: "barrier_wait failed");
57 return (void *) 1l;
58 }
59
60 if (arg == NULL)
61 do
62 if (pthread_cond_wait (cond: &c, mutex: m) != 0)
63 {
64 puts (s: "tf: cond_wait failed");
65 return (void *) 1l;
66 }
67 while (! done);
68 else
69 do
70 {
71 pthread_cleanup_push (cl, NULL);
72
73 if (pthread_cond_wait (cond: &c, mutex: m) != 0)
74 {
75 puts (s: "tf: cond_wait failed");
76 return (void *) 1l;
77 }
78
79 pthread_cleanup_pop (0);
80 }
81 while (! done);
82
83 if (pthread_mutex_unlock (mutex: m) != 0)
84 {
85 puts (s: "tf: mutex_unlock failed");
86 return (void *) 1l;
87 }
88
89 return NULL;
90}
91
92
93static int
94check_type (const char *mas, pthread_mutexattr_t *ma)
95{
96 int e;
97
98 /* Check if a mutex will be elided. Lock elision can only be activated via
99 the tunables framework. By default, lock elision is disabled. */
100 bool assume_elided_mutex = false;
101 int ma_type = PTHREAD_MUTEX_TIMED_NP;
102 if (ma != NULL)
103 {
104 e = pthread_mutexattr_gettype (attr: ma, kind: &ma_type);
105 if (e != 0)
106 {
107 printf (format: "pthread_mutexattr_gettype failed with %d (%m)\n", e);
108 return 1;
109 }
110 }
111 if (ma_type == PTHREAD_MUTEX_TIMED_NP)
112 {
113 /* This type of mutex can be elided if elision is enabled via the tunables
114 framework. Some tests below are failing if the mutex is elided.
115 Thus we only run those if we assume that the mutex won't be elided. */
116 if (TUNABLE_GET_FULL (glibc, elision, enable, int32_t, NULL) == 1)
117 assume_elided_mutex = true;
118 }
119
120 e = pthread_mutex_init (mutex: m, mutexattr: ma);
121 if (e != 0)
122 {
123#ifdef ENABLE_PI
124 if (e == ENOTSUP)
125 {
126 puts ("PI mutexes unsupported");
127 return 0;
128 }
129#endif
130 printf (format: "1st mutex_init failed for %s\n", mas);
131 return 1;
132 }
133
134 if (pthread_mutex_destroy (mutex: m) != 0)
135 {
136 printf (format: "immediate mutex_destroy failed for %s\n", mas);
137 return 1;
138 }
139
140 if (pthread_mutex_init (mutex: m, mutexattr: ma) != 0)
141 {
142 printf (format: "2nd mutex_init failed for %s\n", mas);
143 return 1;
144 }
145
146 if (pthread_mutex_lock (mutex: m) != 0)
147 {
148 printf (format: "1st mutex_lock failed for %s\n", mas);
149 return 1;
150 }
151
152 /* Elided mutexes don't fail destroy, thus only test this if we don't assume
153 elision. */
154 if (assume_elided_mutex == false)
155 {
156 e = pthread_mutex_destroy (mutex: m);
157 if (e == 0)
158 {
159 printf (format: "mutex_destroy of self-locked mutex succeeded for %s\n", mas);
160 return 1;
161 }
162 if (e != EBUSY)
163 {
164 printf (format: "\
165mutex_destroy of self-locked mutex did not return EBUSY %s\n",
166 mas);
167 return 1;
168 }
169 }
170
171 if (pthread_mutex_unlock (mutex: m) != 0)
172 {
173 printf (format: "1st mutex_unlock failed for %s\n", mas);
174 return 1;
175 }
176
177 if (pthread_mutex_trylock (mutex: m) != 0)
178 {
179 printf (format: "mutex_trylock failed for %s\n", mas);
180 return 1;
181 }
182
183 /* Elided mutexes don't fail destroy. */
184 if (assume_elided_mutex == false)
185 {
186 e = pthread_mutex_destroy (mutex: m);
187 if (e == 0)
188 {
189 printf (format: "mutex_destroy of self-trylocked mutex succeeded for %s\n",
190 mas);
191 return 1;
192 }
193 if (e != EBUSY)
194 {
195 printf (format: "\
196mutex_destroy of self-trylocked mutex did not return EBUSY %s\n",
197 mas);
198 return 1;
199 }
200 }
201
202 if (pthread_mutex_unlock (mutex: m) != 0)
203 {
204 printf (format: "2nd mutex_unlock failed for %s\n", mas);
205 return 1;
206 }
207
208 pthread_t th;
209 if (pthread_create (newthread: &th, NULL, start_routine: tf, NULL) != 0)
210 {
211 puts (s: "1st create failed");
212 return 1;
213 }
214 done = false;
215
216 e = pthread_barrier_wait (barrier: &b);
217 if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
218 {
219 puts (s: "1st barrier_wait failed");
220 return 1;
221 }
222
223 if (pthread_mutex_lock (mutex: m) != 0)
224 {
225 printf (format: "2nd mutex_lock failed for %s\n", mas);
226 return 1;
227 }
228
229 if (pthread_mutex_unlock (mutex: m) != 0)
230 {
231 printf (format: "3rd mutex_unlock failed for %s\n", mas);
232 return 1;
233 }
234
235 /* Elided mutexes don't fail destroy. */
236 if (assume_elided_mutex == false)
237 {
238 e = pthread_mutex_destroy (mutex: m);
239 if (e == 0)
240 {
241 printf (format: "mutex_destroy of condvar-used mutex succeeded for %s\n",
242 mas);
243 return 1;
244 }
245 if (e != EBUSY)
246 {
247 printf (format: "\
248mutex_destroy of condvar-used mutex did not return EBUSY for %s\n", mas);
249 return 1;
250 }
251 }
252
253 done = true;
254 if (pthread_cond_signal (cond: &c) != 0)
255 {
256 puts (s: "cond_signal failed");
257 return 1;
258 }
259
260 void *r;
261 if (pthread_join (th: th, thread_return: &r) != 0)
262 {
263 puts (s: "join failed");
264 return 1;
265 }
266 if (r != NULL)
267 {
268 puts (s: "thread didn't return NULL");
269 return 1;
270 }
271
272 if (pthread_mutex_destroy (mutex: m) != 0)
273 {
274 printf (format: "mutex_destroy after condvar-use failed for %s\n", mas);
275 return 1;
276 }
277
278 if (pthread_mutex_init (mutex: m, mutexattr: ma) != 0)
279 {
280 printf (format: "3rd mutex_init failed for %s\n", mas);
281 return 1;
282 }
283
284 if (pthread_create (newthread: &th, NULL, start_routine: tf, arg: (void *) 1) != 0)
285 {
286 puts (s: "2nd create failed");
287 return 1;
288 }
289 done = false;
290
291 e = pthread_barrier_wait (barrier: &b);
292 if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
293 {
294 puts (s: "2nd barrier_wait failed");
295 return 1;
296 }
297
298 if (pthread_mutex_lock (mutex: m) != 0)
299 {
300 printf (format: "3rd mutex_lock failed for %s\n", mas);
301 return 1;
302 }
303
304 if (pthread_mutex_unlock (mutex: m) != 0)
305 {
306 printf (format: "4th mutex_unlock failed for %s\n", mas);
307 return 1;
308 }
309
310 /* Elided mutexes don't fail destroy. */
311 if (assume_elided_mutex == false)
312 {
313 e = pthread_mutex_destroy (mutex: m);
314 if (e == 0)
315 {
316 printf (format: "2nd mutex_destroy of condvar-used mutex succeeded for %s\n",
317 mas);
318 return 1;
319 }
320 if (e != EBUSY)
321 {
322 printf (format: "\
3232nd mutex_destroy of condvar-used mutex did not return EBUSY for %s\n",
324 mas);
325 return 1;
326 }
327 }
328
329 if (pthread_cancel (th: th) != 0)
330 {
331 puts (s: "cond_cancel failed");
332 return 1;
333 }
334
335 if (pthread_join (th: th, thread_return: &r) != 0)
336 {
337 puts (s: "join failed");
338 return 1;
339 }
340 if (r != PTHREAD_CANCELED)
341 {
342 puts (s: "thread not canceled");
343 return 1;
344 }
345
346 if (pthread_mutex_destroy (mutex: m) != 0)
347 {
348 printf (format: "mutex_destroy after condvar-canceled failed for %s\n", mas);
349 return 1;
350 }
351
352 return 0;
353}
354
355
356static int
357do_test (void)
358{
359 pthread_mutex_t mm;
360 m = &mm;
361
362 if (pthread_barrier_init (barrier: &b, NULL, count: 2) != 0)
363 {
364 puts (s: "barrier_init failed");
365 return 1;
366 }
367
368 if (pthread_cond_init (cond: &c, NULL) != 0)
369 {
370 puts (s: "cond_init failed");
371 return 1;
372 }
373
374 puts (s: "check normal mutex");
375 int res = check_type (mas: "normal", NULL);
376
377 pthread_mutexattr_t ma;
378 if (pthread_mutexattr_init (attr: &ma) != 0)
379 {
380 puts (s: "1st mutexattr_init failed");
381 return 1;
382 }
383 if (pthread_mutexattr_settype (attr: &ma, kind: PTHREAD_MUTEX_RECURSIVE) != 0)
384 {
385 puts (s: "1st mutexattr_settype failed");
386 return 1;
387 }
388#ifdef ENABLE_PI
389 if (pthread_mutexattr_setprotocol (&ma, PTHREAD_PRIO_INHERIT))
390 {
391 puts ("1st pthread_mutexattr_setprotocol failed");
392 return 1;
393 }
394#endif
395 puts (s: "check recursive mutex");
396 res |= check_type (mas: "recursive", ma: &ma);
397 if (pthread_mutexattr_destroy (attr: &ma) != 0)
398 {
399 puts (s: "1st mutexattr_destroy failed");
400 return 1;
401 }
402
403 if (pthread_mutexattr_init (attr: &ma) != 0)
404 {
405 puts (s: "2nd mutexattr_init failed");
406 return 1;
407 }
408 if (pthread_mutexattr_settype (attr: &ma, kind: PTHREAD_MUTEX_ERRORCHECK) != 0)
409 {
410 puts (s: "2nd mutexattr_settype failed");
411 return 1;
412 }
413#ifdef ENABLE_PI
414 if (pthread_mutexattr_setprotocol (&ma, PTHREAD_PRIO_INHERIT))
415 {
416 puts ("2nd pthread_mutexattr_setprotocol failed");
417 return 1;
418 }
419#endif
420 puts (s: "check error-checking mutex");
421 res |= check_type (mas: "error-checking", ma: &ma);
422 if (pthread_mutexattr_destroy (attr: &ma) != 0)
423 {
424 puts (s: "2nd mutexattr_destroy failed");
425 return 1;
426 }
427
428 return res;
429}
430
431#define TEST_FUNCTION do_test ()
432#include "../test-skeleton.c"
433

source code of glibc/nptl/tst-mutex8.c