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 <stdbool.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 
24 
25 static pthread_barrier_t b;
26 static pthread_cond_t c = PTHREAD_COND_INITIALIZER;
27 static pthread_mutex_t m;
28 static bool first = true;
29 
30 
31 static void *
tf(void * arg)32 tf (void *arg)
33 {
34   long int n = (long int) arg;
35 
36   if (pthread_mutex_lock (&m) != 0)
37     {
38       printf ("thread %ld: mutex_lock failed\n", n + 1);
39       exit (1);
40     }
41 
42   int e = pthread_barrier_wait (&b);
43   if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
44     {
45       printf ("thread %ld: barrier_wait failed\n", n + 1);
46       exit (1);
47     }
48 
49   e = pthread_cond_wait (&c, &m);
50   if (first)
51     {
52       if (e != 0)
53 	{
54 	  printf ("thread %ld: cond_wait failed\n", n + 1);
55 	  exit (1);
56 	}
57       first = false;
58     }
59   else
60     {
61       if (e != EOWNERDEAD)
62 	{
63 	  printf ("thread %ld: cond_wait did not return EOWNERDEAD\n", n + 1);
64 	  exit (1);
65 	}
66     }
67 
68   if (pthread_cancel (pthread_self ()) != 0)
69     {
70       printf ("thread %ld: cancel failed\n", n + 1);
71       exit (1);
72     }
73 
74   pthread_testcancel ();
75 
76   printf ("thread %ld: testcancel returned\n", n + 1);
77   exit (1);
78 }
79 
80 
81 static int
do_test(void)82 do_test (void)
83 {
84   pthread_mutexattr_t a;
85   if (pthread_mutexattr_init (&a) != 0)
86     {
87       puts ("mutexattr_init failed");
88       return 1;
89     }
90 
91   if (pthread_mutexattr_setrobust (&a, PTHREAD_MUTEX_ROBUST_NP) != 0)
92     {
93       puts ("mutexattr_setrobust failed");
94       return 1;
95     }
96 
97 #ifdef ENABLE_PI
98   if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT) != 0)
99     {
100       puts ("pthread_mutexattr_setprotocol failed");
101       return 1;
102     }
103 #endif
104 
105   int e;
106   e = pthread_mutex_init (&m, &a);
107   if (e != 0)
108     {
109 #ifdef ENABLE_PI
110       if (e == ENOTSUP)
111 	{
112 	  puts ("PI robust mutexes not supported");
113 	  return 0;
114 	}
115 #endif
116       puts ("mutex_init failed");
117       return 1;
118     }
119 
120   if (pthread_mutexattr_destroy (&a) != 0)
121     {
122       puts ("mutexattr_destroy failed");
123       return 1;
124     }
125 
126   if (pthread_barrier_init (&b, NULL, 2) != 0)
127     {
128       puts ("barrier_init failed");
129       return 1;
130     }
131 
132 #define N 5
133   pthread_t th[N];
134   for (long int n = 0; n < N; ++n)
135     {
136       if (pthread_create (&th[n], NULL, tf, (void *) n) != 0)
137 	{
138 	  printf ("pthread_create loop %ld failed\n", n + 1);
139 	  return 1;
140 	}
141 
142       e = pthread_barrier_wait (&b);
143       if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
144 	{
145 	  printf ("parent: barrier_wait failed in round %ld\n", n + 1);
146 	  return 1;
147 	}
148     }
149 
150   if (pthread_mutex_lock (&m) != 0)
151     {
152       puts ("parent: mutex_lock failed");
153       return 1;
154     }
155 
156   if (pthread_mutex_unlock (&m) != 0)
157     {
158       puts ("parent: mutex_unlock failed");
159       return 1;
160     }
161 
162   if (pthread_cond_broadcast (&c) != 0)
163     {
164       puts ("cond_broadcast failed");
165       return 1;
166     }
167 
168   for (int n = 0; n < N; ++n)
169     {
170       void *res;
171       if (pthread_join (th[n], &res) != 0)
172 	{
173 	  printf ("join round %d failed\n", n + 1);
174 	  return 1;
175 	}
176       if (res != PTHREAD_CANCELED)
177 	{
178 	  printf ("thread %d not canceled\n", n + 1);
179 	  return 1;
180 	}
181     }
182 
183   e = pthread_mutex_lock (&m);
184   if (e == 0)
185     {
186       puts ("parent: 2nd mutex_lock succeeded");
187       return 1;
188     }
189   if (e != EOWNERDEAD)
190     {
191       puts ("parent: mutex_lock did not return EOWNERDEAD");
192       return 1;
193     }
194 
195   if (pthread_mutex_unlock (&m) != 0)
196     {
197       puts ("parent: 2nd mutex_unlock failed");
198       return 1;
199     }
200 
201   if (pthread_mutex_destroy (&m) != 0)
202     {
203       puts ("mutex_destroy failed");
204       return 1;
205     }
206 
207   return 0;
208 }
209 
210 #define TEST_FUNCTION do_test ()
211 #include "../test-skeleton.c"
212