1 /* Copyright (C) 2005-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 #include <errno.h>
19 #include <pthread.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 
23 
24 static pthread_mutex_t m1;
25 static pthread_mutex_t m2;
26 static pthread_barrier_t b;
27 
28 
29 #ifndef LOCK
30 # define LOCK(m) pthread_mutex_lock (m)
31 #endif
32 
33 
34 static void *
tf(void * arg)35 tf (void *arg)
36 {
37   long int round = (long int) arg;
38 
39   if (pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL) != 0)
40     {
41       printf ("%ld: setcancelstate failed\n", round);
42       exit (1);
43     }
44 
45   int e = LOCK (&m1);
46   if (e != 0)
47     {
48       printf ("%ld: child: mutex_lock m1 failed with error %d\n", round, e);
49       exit (1);
50     }
51 
52   e = LOCK (&m2);
53   if (e != 0)
54     {
55       printf ("%ld: child: mutex_lock m2 failed with error %d\n", round, e);
56       exit (1);
57     }
58 
59   e = pthread_barrier_wait (&b);
60   if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
61     {
62       printf ("%ld: child: 1st barrier_wait failed\n", round);
63       exit (1);
64     }
65 
66   e = pthread_barrier_wait (&b);
67   if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
68     {
69       printf ("%ld: child: 2nd barrier_wait failed\n", round);
70       exit (1);
71     }
72 
73   pthread_testcancel ();
74 
75   printf ("%ld: testcancel returned\n", round);
76   exit (1);
77 }
78 
79 
80 static int
do_test(void)81 do_test (void)
82 {
83 #ifdef PREPARE_TMO
84   PREPARE_TMO;
85 #endif
86 
87   pthread_mutexattr_t a;
88   if (pthread_mutexattr_init (&a) != 0)
89     {
90       puts ("mutexattr_init failed");
91       return 1;
92     }
93   if (pthread_mutexattr_setrobust (&a, PTHREAD_MUTEX_ROBUST_NP) != 0)
94     {
95       puts ("mutexattr_setrobust failed");
96       return 1;
97     }
98 
99 #ifdef ENABLE_PI
100   if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT) != 0)
101     {
102       puts ("pthread_mutexattr_setprotocol failed");
103       return 1;
104     }
105   else
106     {
107       int e = pthread_mutex_init (&m1, &a);
108       if (e == ENOTSUP)
109 	{
110 	  puts ("PI robust mutexes not supported");
111 	  return 0;
112 	}
113       else if (e != 0)
114 	{
115 	  puts ("mutex_init m1 failed");
116 	  return 1;
117 	}
118       pthread_mutex_destroy (&m1);
119     }
120 #endif
121 
122 #ifndef NOT_CONSISTENT
123   if (pthread_mutex_init (&m1, &a) != 0)
124     {
125       puts ("mutex_init m1 failed");
126       return 1;
127     }
128 
129   if (pthread_mutex_init (&m2, &a) != 0)
130     {
131       puts ("mutex_init m2 failed");
132       return 1;
133     }
134 #endif
135 
136   if (pthread_barrier_init (&b, NULL, 2) != 0)
137     {
138       puts ("barrier_init failed");
139       return 1;
140     }
141 
142   for (long int round = 1; round < 5; ++round)
143     {
144 #ifdef NOT_CONSISTENT
145       if (pthread_mutex_init (&m1 , &a) != 0)
146 	{
147 	  puts ("mutex_init m1 failed");
148 	  return 1;
149 	}
150       if (pthread_mutex_init (&m2 , &a) != 0)
151 	{
152 	  puts ("mutex_init m2 failed");
153 	  return 1;
154 	}
155 #endif
156 
157       pthread_t th;
158       if (pthread_create (&th, NULL, tf, (void *) round) != 0)
159 	{
160 	  printf ("%ld: create failed\n", round);
161 	  return 1;
162 	}
163 
164       int e = pthread_barrier_wait (&b);
165       if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
166 	{
167 	  printf ("%ld: parent: 1st barrier_wait failed\n", round);
168 	  return 1;
169 	}
170 
171       if (pthread_cancel (th) != 0)
172 	{
173 	  printf ("%ld: cancel failed\n", round);
174 	  return 1;
175 	}
176 
177       e = pthread_barrier_wait (&b);
178       if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
179 	{
180 	  printf ("%ld: parent: 2nd barrier_wait failed\n", round);
181 	  return 1;
182 	}
183 
184 #ifndef AFTER_JOIN
185       if (round & 1)
186 #endif
187 	{
188 	  void *res;
189 	  if (pthread_join (th, &res) != 0)
190 	    {
191 	      printf ("%ld: join failed\n", round);
192 	      return 1;
193 	    }
194 	  if (res != PTHREAD_CANCELED)
195 	    {
196 	      printf ("%ld: thread not canceled\n", round);
197 	      return 1;
198 	    }
199 	}
200 
201       e = LOCK (&m1);
202       if (e == 0)
203 	{
204 	  printf ("%ld: parent: mutex_lock m1 succeeded\n", round);
205 	  return 1;
206 	}
207       if (e != EOWNERDEAD)
208 	{
209 	  printf ("%ld: parent: mutex_lock m1 returned wrong code\n", round);
210 	  return 1;
211 	}
212 
213       e = LOCK (&m2);
214       if (e == 0)
215 	{
216 	  printf ("%ld: parent: mutex_lock m2 succeeded\n", round);
217 	  return 1;
218 	}
219       if (e != EOWNERDEAD)
220 	{
221 	  printf ("%ld: parent: mutex_lock m2 returned wrong code\n", round);
222 	  return 1;
223 	}
224 
225 #ifndef AFTER_JOIN
226       if ((round & 1) == 0)
227 	{
228 	  void *res;
229 	  if (pthread_join (th, &res) != 0)
230 	    {
231 	      printf ("%ld: join failed\n", round);
232 	      return 1;
233 	    }
234 	  if (res != PTHREAD_CANCELED)
235 	    {
236 	      printf ("%ld: thread not canceled\n", round);
237 	      return 1;
238 	    }
239 	}
240 #endif
241 
242 #ifndef NOT_CONSISTENT
243       e = pthread_mutex_consistent (&m1);
244       if (e != 0)
245 	{
246 	  printf ("%ld: mutex_consistent m1 failed with error %d\n", round, e);
247 	  return 1;
248 	}
249 
250       e = pthread_mutex_consistent (&m2);
251       if (e != 0)
252 	{
253 	  printf ("%ld: mutex_consistent m2 failed with error %d\n", round, e);
254 	  return 1;
255 	}
256 #endif
257 
258       e = pthread_mutex_unlock (&m1);
259       if (e != 0)
260 	{
261 	  printf ("%ld: mutex_unlock m1 failed with %d\n", round, e);
262 	  return 1;
263 	}
264 
265       e = pthread_mutex_unlock (&m2);
266       if (e != 0)
267 	{
268 	  printf ("%ld: mutex_unlock m2 failed with %d\n", round, e);
269 	  return 1;
270 	}
271 
272 #ifdef NOT_CONSISTENT
273       e = LOCK (&m1);
274       if (e == 0)
275 	{
276 	  printf ("%ld: locking inconsistent mutex m1 succeeded\n", round);
277 	  return 1;
278 	}
279       if (e != ENOTRECOVERABLE)
280 	{
281 	  printf ("%ld: locking inconsistent mutex m1 failed with error %d\n",
282 		  round, e);
283 	  return 1;
284 	}
285 
286       if (pthread_mutex_destroy (&m1) != 0)
287 	{
288 	  puts ("mutex_destroy m1 failed");
289 	  return 1;
290 	}
291 
292       e = LOCK (&m2);
293       if (e == 0)
294 	{
295 	  printf ("%ld: locking inconsistent mutex m2 succeeded\n", round);
296 	  return 1;
297 	}
298       if (e != ENOTRECOVERABLE)
299 	{
300 	  printf ("%ld: locking inconsistent mutex m2 failed with error %d\n",
301 		  round, e);
302 	  return 1;
303 	}
304 
305       if (pthread_mutex_destroy (&m2) != 0)
306 	{
307 	  puts ("mutex_destroy m2 failed");
308 	  return 1;
309 	}
310 #endif
311     }
312 
313 #ifndef NOT_CONSISTENT
314   if (pthread_mutex_destroy (&m1) != 0)
315     {
316       puts ("mutex_destroy m1 failed");
317       return 1;
318     }
319 
320   if (pthread_mutex_destroy (&m2) != 0)
321     {
322       puts ("mutex_destroy m2 failed");
323       return 1;
324     }
325 #endif
326 
327   if (pthread_mutexattr_destroy (&a) != 0)
328     {
329       puts ("mutexattr_destroy failed");
330       return 1;
331     }
332 
333   return 0;
334 }
335 
336 #define TEST_FUNCTION do_test ()
337 #include "../test-skeleton.c"
338