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