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 #include <errno.h>
19 #include <pthread.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <time.h>
23 #include <sys/time.h>
24 
25 
26 static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
27 static pthread_mutex_t mut = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
28 
29 static pthread_barrier_t bar;
30 
31 
32 static void
ch(void * arg)33 ch (void *arg)
34 {
35   int e = pthread_mutex_lock (&mut);
36   if (e == 0)
37     {
38       puts ("mutex not locked at all by cond_wait");
39       exit (1);
40     }
41 
42   if (e != EDEADLK)
43     {
44       puts ("no deadlock error signaled");
45       exit (1);
46     }
47 
48   if (pthread_mutex_unlock (&mut) != 0)
49     {
50       puts ("ch: cannot unlock mutex");
51       exit (1);
52     }
53 
54   puts ("ch done");
55 }
56 
57 
58 static void *
tf1(void * p)59 tf1 (void *p)
60 {
61   int err;
62 
63   if (pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL) != 0
64       || pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, NULL) != 0)
65     {
66       puts ("cannot set cancellation options");
67       exit (1);
68     }
69 
70   err = pthread_mutex_lock (&mut);
71   if (err != 0)
72     {
73       puts ("child: cannot get mutex");
74       exit (1);
75     }
76 
77   err = pthread_barrier_wait (&bar);
78   if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD)
79     {
80       printf ("barrier_wait returned %d\n", err);
81       exit (1);
82     }
83 
84   puts ("child: got mutex; waiting");
85 
86   pthread_cleanup_push (ch, NULL);
87 
88   pthread_cond_wait (&cond, &mut);
89 
90   pthread_cleanup_pop (0);
91 
92   puts ("child: cond_wait should not have returned");
93 
94   return NULL;
95 }
96 
97 
98 static void *
tf2(void * p)99 tf2 (void *p)
100 {
101   int err;
102 
103   if (pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL) != 0
104       || pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, NULL) != 0)
105     {
106       puts ("cannot set cancellation options");
107       exit (1);
108     }
109 
110   err = pthread_mutex_lock (&mut);
111   if (err != 0)
112     {
113       puts ("child: cannot get mutex");
114       exit (1);
115     }
116 
117   err = pthread_barrier_wait (&bar);
118   if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD)
119     {
120       printf ("barrier_wait returned %d\n", err);
121       exit (1);
122     }
123 
124   puts ("child: got mutex; waiting");
125 
126   pthread_cleanup_push (ch, NULL);
127 
128   /* Current time.  */
129   struct timeval tv;
130   (void) gettimeofday (&tv, NULL);
131   /* +1000 seconds in correct format.  */
132   struct timespec ts;
133   TIMEVAL_TO_TIMESPEC (&tv, &ts);
134   ts.tv_sec += 1000;
135 
136   pthread_cond_timedwait (&cond, &mut, &ts);
137 
138   pthread_cleanup_pop (0);
139 
140   puts ("child: cond_wait should not have returned");
141 
142   return NULL;
143 }
144 
145 
146 static int
do_test(void)147 do_test (void)
148 {
149   pthread_t th;
150   int err;
151 
152   printf ("&cond = %p\n&mut = %p\n", &cond, &mut);
153 
154   puts ("parent: get mutex");
155 
156   err = pthread_barrier_init (&bar, NULL, 2);
157   if (err != 0)
158     {
159       puts ("parent: cannot init barrier");
160       exit (1);
161     }
162 
163   puts ("parent: create child");
164 
165   err = pthread_create (&th, NULL, tf1, NULL);
166   if (err != 0)
167     {
168       puts ("parent: cannot create thread");
169       exit (1);
170     }
171 
172   puts ("parent: wait for child to lock mutex");
173 
174   err = pthread_barrier_wait (&bar);
175   if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD)
176     {
177       puts ("parent: cannot wait for barrier");
178       exit (1);
179     }
180 
181   err = pthread_mutex_lock (&mut);
182   if (err != 0)
183     {
184       puts ("parent: mutex_lock failed");
185       exit (1);
186     }
187 
188   err = pthread_mutex_unlock (&mut);
189   if (err != 0)
190     {
191       puts ("parent: mutex_unlock failed");
192       exit (1);
193     }
194 
195   if (pthread_cancel (th) != 0)
196     {
197       puts ("cannot cancel thread");
198       exit (1);
199     }
200 
201   void *r;
202   err = pthread_join (th, &r);
203   if (err != 0)
204     {
205       puts ("parent: failed to join");
206       exit (1);
207     }
208 
209   if (r != PTHREAD_CANCELED)
210     {
211       puts ("child hasn't been canceled");
212       exit (1);
213     }
214 
215 
216 
217   puts ("parent: create 2nd child");
218 
219   err = pthread_create (&th, NULL, tf2, NULL);
220   if (err != 0)
221     {
222       puts ("parent: cannot create thread");
223       exit (1);
224     }
225 
226   puts ("parent: wait for child to lock mutex");
227 
228   err = pthread_barrier_wait (&bar);
229   if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD)
230     {
231       puts ("parent: cannot wait for barrier");
232       exit (1);
233     }
234 
235   err = pthread_mutex_lock (&mut);
236   if (err != 0)
237     {
238       puts ("parent: mutex_lock failed");
239       exit (1);
240     }
241 
242   err = pthread_mutex_unlock (&mut);
243   if (err != 0)
244     {
245       puts ("parent: mutex_unlock failed");
246       exit (1);
247     }
248 
249   if (pthread_cancel (th) != 0)
250     {
251       puts ("cannot cancel thread");
252       exit (1);
253     }
254 
255   err = pthread_join (th, &r);
256   if (err != 0)
257     {
258       puts ("parent: failed to join");
259       exit (1);
260     }
261 
262   if (r != PTHREAD_CANCELED)
263     {
264       puts ("child hasn't been canceled");
265       exit (1);
266     }
267 
268   puts ("done");
269 
270   return 0;
271 }
272 
273 
274 #define TEST_FUNCTION do_test ()
275 #include "../test-skeleton.c"
276