Refer to C23 in place of C2X in glibc
[glibc.git] / nptl / tst-cancel17.c
blobb456450d63fc44cbacc2ddf89aa83f75d8728d57
1 /* Copyright (C) 2003-2024 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
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.
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.
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/>. */
18 #include <aio.h>
19 #include <errno.h>
20 #include <pthread.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
27 static pthread_barrier_t b;
30 /* Cleanup handling test. */
31 static int cl_called;
33 static void
34 cl (void *arg)
36 ++cl_called;
40 static void *
41 tf (void *arg)
43 int r = pthread_barrier_wait (&b);
44 if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
46 puts ("tf: barrier_wait failed");
47 exit (1);
50 pthread_cleanup_push (cl, NULL);
52 const struct aiocb *l[1] = { arg };
54 TEMP_FAILURE_RETRY (aio_suspend (l, 1, NULL));
56 pthread_cleanup_pop (0);
58 puts ("tf: aio_suspend returned");
60 exit (1);
64 static void *
65 tf2 (void *arg)
67 int r = pthread_barrier_wait (&b);
68 if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
70 puts ("tf2: barrier_wait failed");
71 exit (1);
74 pthread_cleanup_push (cl, NULL);
76 const struct aiocb *l[1] = { arg };
77 struct timespec ts = { .tv_sec = 1000, .tv_nsec = 0 };
79 TEMP_FAILURE_RETRY (aio_suspend (l, 1, &ts));
81 pthread_cleanup_pop (0);
83 puts ("tf2: aio_suspend returned");
85 exit (1);
89 static int
90 do_test (void)
92 int fds[2];
93 if (pipe (fds) != 0)
95 puts ("pipe failed");
96 return 1;
99 struct aiocb a, a2, *ap;
100 char mem[1];
101 memset (&a, '\0', sizeof (a));
102 a.aio_fildes = fds[0];
103 a.aio_buf = mem;
104 a.aio_nbytes = sizeof (mem);
105 if (aio_read (&a) != 0)
107 puts ("aio_read failed");
108 return 1;
111 if (pthread_barrier_init (&b, NULL, 2) != 0)
113 puts ("barrier_init failed");
114 return 1;
117 pthread_t th;
118 if (pthread_create (&th, NULL, tf, &a) != 0)
120 puts ("1st create failed");
121 return 1;
124 int r = pthread_barrier_wait (&b);
125 if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
127 puts ("barrier_wait failed");
128 exit (1);
131 struct timespec ts = { .tv_sec = 0, .tv_nsec = 100000000 };
132 while (nanosleep (&ts, &ts) != 0)
133 continue;
135 puts ("going to cancel tf in-time");
136 if (pthread_cancel (th) != 0)
138 puts ("1st cancel failed");
139 return 1;
142 void *status;
143 if (pthread_join (th, &status) != 0)
145 puts ("1st join failed");
146 return 1;
148 if (status != PTHREAD_CANCELED)
150 puts ("1st thread not canceled");
151 return 1;
154 if (cl_called == 0)
156 puts ("tf cleanup handler not called");
157 return 1;
159 if (cl_called > 1)
161 puts ("tf cleanup handler called more than once");
162 return 1;
165 cl_called = 0;
167 if (pthread_create (&th, NULL, tf2, &a) != 0)
169 puts ("2nd create failed");
170 return 1;
173 r = pthread_barrier_wait (&b);
174 if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
176 puts ("2nd barrier_wait failed");
177 exit (1);
180 ts.tv_sec = 0;
181 ts.tv_nsec = 100000000;
182 while (nanosleep (&ts, &ts) != 0)
183 continue;
185 puts ("going to cancel tf2 in-time");
186 if (pthread_cancel (th) != 0)
188 puts ("2nd cancel failed");
189 return 1;
192 if (pthread_join (th, &status) != 0)
194 puts ("2nd join failed");
195 return 1;
197 if (status != PTHREAD_CANCELED)
199 puts ("2nd thread not canceled");
200 return 1;
203 if (cl_called == 0)
205 puts ("tf2 cleanup handler not called");
206 return 1;
208 if (cl_called > 1)
210 puts ("tf2 cleanup handler called more than once");
211 return 1;
214 puts ("in-time cancellation succeeded");
216 ap = &a;
217 if (aio_cancel (fds[0], &a) != AIO_CANCELED)
219 puts ("aio_cancel failed");
220 /* If aio_cancel failed, we cannot reuse aiocb a. */
221 ap = &a2;
225 cl_called = 0;
227 size_t len2 = fpathconf (fds[1], _PC_PIPE_BUF);
228 size_t page_size = sysconf (_SC_PAGESIZE);
229 len2 = 20 * (len2 < page_size ? page_size : len2) + sizeof (mem) + 1;
230 char *mem2 = malloc (len2);
231 if (mem2 == NULL)
233 puts ("could not allocate memory for pipe write");
234 return 1;
237 memset (ap, '\0', sizeof (*ap));
238 ap->aio_fildes = fds[1];
239 ap->aio_buf = mem2;
240 ap->aio_nbytes = len2;
241 if (aio_write (ap) != 0)
243 puts ("aio_write failed");
244 return 1;
247 if (pthread_create (&th, NULL, tf, ap) != 0)
249 puts ("3rd create failed");
250 return 1;
253 puts ("going to cancel tf early");
254 if (pthread_cancel (th) != 0)
256 puts ("3rd cancel failed");
257 return 1;
260 r = pthread_barrier_wait (&b);
261 if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
263 puts ("3rd barrier_wait failed");
264 exit (1);
267 if (pthread_join (th, &status) != 0)
269 puts ("3rd join failed");
270 return 1;
272 if (status != PTHREAD_CANCELED)
274 puts ("3rd thread not canceled");
275 return 1;
278 if (cl_called == 0)
280 puts ("tf cleanup handler not called");
281 return 1;
283 if (cl_called > 1)
285 puts ("tf cleanup handler called more than once");
286 return 1;
289 cl_called = 0;
291 if (pthread_create (&th, NULL, tf2, ap) != 0)
293 puts ("4th create failed");
294 return 1;
297 puts ("going to cancel tf2 early");
298 if (pthread_cancel (th) != 0)
300 puts ("4th cancel failed");
301 return 1;
304 r = pthread_barrier_wait (&b);
305 if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
307 puts ("4th barrier_wait failed");
308 exit (1);
311 if (pthread_join (th, &status) != 0)
313 puts ("4th join failed");
314 return 1;
316 if (status != PTHREAD_CANCELED)
318 puts ("4th thread not canceled");
319 return 1;
322 if (cl_called == 0)
324 puts ("tf2 cleanup handler not called");
325 return 1;
327 if (cl_called > 1)
329 puts ("tf2 cleanup handler called more than once");
330 return 1;
333 puts ("early cancellation succeeded");
335 if (ap == &a2)
337 /* The aio_read(&a) was not canceled because the read request was
338 already in progress. In the meanwhile aio_write(ap) wrote something
339 to the pipe and the read request either has already been finished or
340 is able to read the requested byte.
341 Wait for the read request before returning from this function because
342 the return value and error code from the read syscall will be written
343 to the struct aiocb a, which lies on the stack of this function.
344 Otherwise the stack from subsequent function calls - e.g. _dl_fini -
345 will be corrupted, which can lead to undefined behaviour like a
346 segmentation fault. */
347 const struct aiocb *l[1] = { &a };
348 TEMP_FAILURE_RETRY (aio_suspend(l, 1, NULL));
351 return 0;
354 #define TEST_FUNCTION do_test ()
355 #include "../test-skeleton.c"