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

source code of glibc/sysdeps/pthread/tst-cond8.c