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