1 /* Copyright (C) 2002-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 m;
25 static pthread_barrier_t b;
26 
27 
28 static void *
tf(void * arg)29 tf (void *arg)
30 {
31   int e = pthread_mutex_unlock (&m);
32   if (e == 0)
33     {
34       puts ("child: 1st mutex_unlock succeeded");
35       exit (1);
36     }
37   else if (e != EPERM)
38     {
39       puts ("child: 1st mutex_unlock error != EPERM");
40       exit (1);
41     }
42 
43   e = pthread_mutex_trylock (&m);
44   if (e == 0)
45     {
46       puts ("child: 1st trylock suceeded");
47       exit (1);
48     }
49   if (e != EBUSY)
50     {
51       puts ("child: 1st trylock didn't return EBUSY");
52       exit (1);
53     }
54 
55   e = pthread_barrier_wait (&b);
56   if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
57     {
58       puts ("child: 1st barrier_wait failed");
59       exit (1);
60     }
61 
62   e = pthread_barrier_wait (&b);
63   if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
64     {
65       puts ("child: 2nd barrier_wait failed");
66       exit (1);
67     }
68 
69   e = pthread_mutex_unlock (&m);
70   if (e == 0)
71     {
72       puts ("child: 2nd mutex_unlock succeeded");
73       exit (1);
74     }
75   else if (e != EPERM)
76     {
77       puts ("child: 2nd mutex_unlock error != EPERM");
78       exit (1);
79     }
80 
81   if (pthread_mutex_trylock (&m) != 0)
82     {
83       puts ("child: 2nd trylock failed");
84       exit (1);
85     }
86 
87   if (pthread_mutex_unlock (&m) != 0)
88     {
89       puts ("child: 3rd mutex_unlock failed");
90       exit (1);
91     }
92 
93   return NULL;
94 }
95 
96 
97 static int
do_test(void)98 do_test (void)
99 {
100   pthread_mutexattr_t a;
101   int e;
102 
103   if (pthread_mutexattr_init (&a) != 0)
104     {
105       puts ("mutexattr_init failed");
106       return 1;
107     }
108 
109   if (pthread_mutexattr_settype (&a, PTHREAD_MUTEX_ERRORCHECK) != 0)
110     {
111       puts ("mutexattr_settype failed");
112       return 1;
113     }
114 
115 #ifdef ENABLE_PI
116   if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT) != 0)
117     {
118       puts ("pthread_mutexattr_setprotocol failed");
119       return 1;
120     }
121 #endif
122 
123   e = pthread_mutex_init (&m, &a);
124   if (e != 0)
125     {
126 #ifdef ENABLE_PI
127       if (e == ENOTSUP)
128 	{
129 	  puts ("PI mutexes unsupported");
130 	  return 0;
131 	}
132 #endif
133       puts ("mutex_init failed");
134       return 1;
135     }
136 
137   if (pthread_barrier_init (&b, NULL, 2) != 0)
138     {
139       puts ("barrier_init failed");
140       return 1;
141     }
142 
143   e = pthread_mutex_unlock (&m);
144   if (e == 0)
145     {
146       puts ("1st mutex_unlock succeeded");
147       return 1;
148     }
149   else if (e != EPERM)
150     {
151       puts ("1st mutex_unlock error != EPERM");
152       return 1;
153     }
154 
155   if (pthread_mutex_lock (&m) != 0)
156     {
157       puts ("mutex_lock failed");
158       return 1;
159     }
160 
161   e = pthread_mutex_lock (&m);
162   if (e == 0)
163     {
164       puts ("2nd mutex_lock succeeded");
165       return 1;
166     }
167   else if (e != EDEADLK)
168     {
169       puts ("2nd mutex_lock error != EDEADLK");
170       return 1;
171     }
172 
173   pthread_t th;
174   if (pthread_create (&th, NULL, tf, NULL) != 0)
175     {
176       puts ("create failed");
177       return 1;
178     }
179 
180   e = pthread_barrier_wait (&b);
181   if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
182     {
183       puts ("1st barrier_wait failed");
184       return 1;
185     }
186 
187   if (pthread_mutex_unlock (&m) != 0)
188     {
189       puts ("2nd mutex_unlock failed");
190       return 1;
191     }
192 
193   e = pthread_mutex_unlock (&m);
194   if (e == 0)
195     {
196       puts ("3rd mutex_unlock succeeded");
197       return 1;
198     }
199   else if (e != EPERM)
200     {
201       puts ("3rd mutex_unlock error != EPERM");
202       return 1;
203     }
204 
205   e = pthread_barrier_wait (&b);
206   if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
207     {
208       puts ("2nd barrier_wait failed");
209       return 1;
210     }
211 
212   if (pthread_join (th, NULL) != 0)
213     {
214       puts ("join failed");
215       return 1;
216     }
217 
218   if (pthread_mutex_destroy (&m) != 0)
219     {
220       puts ("mutex_destroy failed");
221       return 1;
222     }
223 
224   if (pthread_barrier_destroy (&b) != 0)
225     {
226       puts ("barrier_destroy failed");
227       return 1;
228     }
229 
230   if (pthread_mutexattr_destroy (&a) != 0)
231     {
232       puts ("mutexattr_destroy failed");
233       return 1;
234     }
235 
236   return 0;
237 }
238 
239 #define TEST_FUNCTION do_test ()
240 #include "../test-skeleton.c"
241