1 /* Copyright (C) 2003-2022 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
27 static pthread_mutex_t *m;
28 static pthread_barrier_t b;
29 static pthread_cond_t c;
30 static bool done;
31
32
33 static void
cl(void * arg)34 cl (void *arg)
35 {
36 if (pthread_mutex_unlock (m) != 0)
37 {
38 puts ("cl: mutex_unlocked failed");
39 exit (1);
40 }
41 }
42
43
44 static void *
tf(void * arg)45 tf (void *arg)
46 {
47 if (pthread_mutex_lock (m) != 0)
48 {
49 puts ("tf: mutex_lock failed");
50 return (void *) 1l;
51 }
52
53 int e = pthread_barrier_wait (&b);
54 if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
55 {
56 puts ("barrier_wait failed");
57 return (void *) 1l;
58 }
59
60 if (arg == NULL)
61 do
62 if (pthread_cond_wait (&c, m) != 0)
63 {
64 puts ("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 (&c, m) != 0)
74 {
75 puts ("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 (m) != 0)
84 {
85 puts ("tf: mutex_unlock failed");
86 return (void *) 1l;
87 }
88
89 return NULL;
90 }
91
92
93 static int
check_type(const char * mas,pthread_mutexattr_t * ma)94 check_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 #if HAVE_TUNABLES
102 int ma_type = PTHREAD_MUTEX_TIMED_NP;
103 if (ma != NULL)
104 {
105 e = pthread_mutexattr_gettype (ma, &ma_type);
106 if (e != 0)
107 {
108 printf ("pthread_mutexattr_gettype failed with %d (%m)\n", e);
109 return 1;
110 }
111 }
112 if (ma_type == PTHREAD_MUTEX_TIMED_NP)
113 {
114 /* This type of mutex can be elided if elision is enabled via the tunables
115 framework. Some tests below are failing if the mutex is elided.
116 Thus we only run those if we assume that the mutex won't be elided. */
117 if (TUNABLE_GET_FULL (glibc, elision, enable, int32_t, NULL) == 1)
118 assume_elided_mutex = true;
119 }
120 #endif
121
122 e = pthread_mutex_init (m, ma);
123 if (e != 0)
124 {
125 #ifdef ENABLE_PI
126 if (e == ENOTSUP)
127 {
128 puts ("PI mutexes unsupported");
129 return 0;
130 }
131 #endif
132 printf ("1st mutex_init failed for %s\n", mas);
133 return 1;
134 }
135
136 if (pthread_mutex_destroy (m) != 0)
137 {
138 printf ("immediate mutex_destroy failed for %s\n", mas);
139 return 1;
140 }
141
142 if (pthread_mutex_init (m, ma) != 0)
143 {
144 printf ("2nd mutex_init failed for %s\n", mas);
145 return 1;
146 }
147
148 if (pthread_mutex_lock (m) != 0)
149 {
150 printf ("1st mutex_lock failed for %s\n", mas);
151 return 1;
152 }
153
154 /* Elided mutexes don't fail destroy, thus only test this if we don't assume
155 elision. */
156 if (assume_elided_mutex == false)
157 {
158 e = pthread_mutex_destroy (m);
159 if (e == 0)
160 {
161 printf ("mutex_destroy of self-locked mutex succeeded for %s\n", mas);
162 return 1;
163 }
164 if (e != EBUSY)
165 {
166 printf ("\
167 mutex_destroy of self-locked mutex did not return EBUSY %s\n",
168 mas);
169 return 1;
170 }
171 }
172
173 if (pthread_mutex_unlock (m) != 0)
174 {
175 printf ("1st mutex_unlock failed for %s\n", mas);
176 return 1;
177 }
178
179 if (pthread_mutex_trylock (m) != 0)
180 {
181 printf ("mutex_trylock failed for %s\n", mas);
182 return 1;
183 }
184
185 /* Elided mutexes don't fail destroy. */
186 if (assume_elided_mutex == false)
187 {
188 e = pthread_mutex_destroy (m);
189 if (e == 0)
190 {
191 printf ("mutex_destroy of self-trylocked mutex succeeded for %s\n",
192 mas);
193 return 1;
194 }
195 if (e != EBUSY)
196 {
197 printf ("\
198 mutex_destroy of self-trylocked mutex did not return EBUSY %s\n",
199 mas);
200 return 1;
201 }
202 }
203
204 if (pthread_mutex_unlock (m) != 0)
205 {
206 printf ("2nd mutex_unlock failed for %s\n", mas);
207 return 1;
208 }
209
210 pthread_t th;
211 if (pthread_create (&th, NULL, tf, NULL) != 0)
212 {
213 puts ("1st create failed");
214 return 1;
215 }
216 done = false;
217
218 e = pthread_barrier_wait (&b);
219 if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
220 {
221 puts ("1st barrier_wait failed");
222 return 1;
223 }
224
225 if (pthread_mutex_lock (m) != 0)
226 {
227 printf ("2nd mutex_lock failed for %s\n", mas);
228 return 1;
229 }
230
231 if (pthread_mutex_unlock (m) != 0)
232 {
233 printf ("3rd mutex_unlock failed for %s\n", mas);
234 return 1;
235 }
236
237 /* Elided mutexes don't fail destroy. */
238 if (assume_elided_mutex == false)
239 {
240 e = pthread_mutex_destroy (m);
241 if (e == 0)
242 {
243 printf ("mutex_destroy of condvar-used mutex succeeded for %s\n",
244 mas);
245 return 1;
246 }
247 if (e != EBUSY)
248 {
249 printf ("\
250 mutex_destroy of condvar-used mutex did not return EBUSY for %s\n", mas);
251 return 1;
252 }
253 }
254
255 done = true;
256 if (pthread_cond_signal (&c) != 0)
257 {
258 puts ("cond_signal failed");
259 return 1;
260 }
261
262 void *r;
263 if (pthread_join (th, &r) != 0)
264 {
265 puts ("join failed");
266 return 1;
267 }
268 if (r != NULL)
269 {
270 puts ("thread didn't return NULL");
271 return 1;
272 }
273
274 if (pthread_mutex_destroy (m) != 0)
275 {
276 printf ("mutex_destroy after condvar-use failed for %s\n", mas);
277 return 1;
278 }
279
280 if (pthread_mutex_init (m, ma) != 0)
281 {
282 printf ("3rd mutex_init failed for %s\n", mas);
283 return 1;
284 }
285
286 if (pthread_create (&th, NULL, tf, (void *) 1) != 0)
287 {
288 puts ("2nd create failed");
289 return 1;
290 }
291 done = false;
292
293 e = pthread_barrier_wait (&b);
294 if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
295 {
296 puts ("2nd barrier_wait failed");
297 return 1;
298 }
299
300 if (pthread_mutex_lock (m) != 0)
301 {
302 printf ("3rd mutex_lock failed for %s\n", mas);
303 return 1;
304 }
305
306 if (pthread_mutex_unlock (m) != 0)
307 {
308 printf ("4th mutex_unlock failed for %s\n", mas);
309 return 1;
310 }
311
312 /* Elided mutexes don't fail destroy. */
313 if (assume_elided_mutex == false)
314 {
315 e = pthread_mutex_destroy (m);
316 if (e == 0)
317 {
318 printf ("2nd mutex_destroy of condvar-used mutex succeeded for %s\n",
319 mas);
320 return 1;
321 }
322 if (e != EBUSY)
323 {
324 printf ("\
325 2nd mutex_destroy of condvar-used mutex did not return EBUSY for %s\n",
326 mas);
327 return 1;
328 }
329 }
330
331 if (pthread_cancel (th) != 0)
332 {
333 puts ("cond_cancel failed");
334 return 1;
335 }
336
337 if (pthread_join (th, &r) != 0)
338 {
339 puts ("join failed");
340 return 1;
341 }
342 if (r != PTHREAD_CANCELED)
343 {
344 puts ("thread not canceled");
345 return 1;
346 }
347
348 if (pthread_mutex_destroy (m) != 0)
349 {
350 printf ("mutex_destroy after condvar-canceled failed for %s\n", mas);
351 return 1;
352 }
353
354 return 0;
355 }
356
357
358 static int
do_test(void)359 do_test (void)
360 {
361 pthread_mutex_t mm;
362 m = &mm;
363
364 if (pthread_barrier_init (&b, NULL, 2) != 0)
365 {
366 puts ("barrier_init failed");
367 return 1;
368 }
369
370 if (pthread_cond_init (&c, NULL) != 0)
371 {
372 puts ("cond_init failed");
373 return 1;
374 }
375
376 puts ("check normal mutex");
377 int res = check_type ("normal", NULL);
378
379 pthread_mutexattr_t ma;
380 if (pthread_mutexattr_init (&ma) != 0)
381 {
382 puts ("1st mutexattr_init failed");
383 return 1;
384 }
385 if (pthread_mutexattr_settype (&ma, PTHREAD_MUTEX_RECURSIVE) != 0)
386 {
387 puts ("1st mutexattr_settype failed");
388 return 1;
389 }
390 #ifdef ENABLE_PI
391 if (pthread_mutexattr_setprotocol (&ma, PTHREAD_PRIO_INHERIT))
392 {
393 puts ("1st pthread_mutexattr_setprotocol failed");
394 return 1;
395 }
396 #endif
397 puts ("check recursive mutex");
398 res |= check_type ("recursive", &ma);
399 if (pthread_mutexattr_destroy (&ma) != 0)
400 {
401 puts ("1st mutexattr_destroy failed");
402 return 1;
403 }
404
405 if (pthread_mutexattr_init (&ma) != 0)
406 {
407 puts ("2nd mutexattr_init failed");
408 return 1;
409 }
410 if (pthread_mutexattr_settype (&ma, PTHREAD_MUTEX_ERRORCHECK) != 0)
411 {
412 puts ("2nd mutexattr_settype failed");
413 return 1;
414 }
415 #ifdef ENABLE_PI
416 if (pthread_mutexattr_setprotocol (&ma, PTHREAD_PRIO_INHERIT))
417 {
418 puts ("2nd pthread_mutexattr_setprotocol failed");
419 return 1;
420 }
421 #endif
422 puts ("check error-checking mutex");
423 res |= check_type ("error-checking", &ma);
424 if (pthread_mutexattr_destroy (&ma) != 0)
425 {
426 puts ("2nd mutexattr_destroy failed");
427 return 1;
428 }
429
430 return res;
431 }
432
433 #define TEST_FUNCTION do_test ()
434 #include "../test-skeleton.c"
435