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/>. */
27 static pthread_barrier_t b
;
30 /* Cleanup handling test. */
43 int r
= pthread_barrier_wait (&b
);
44 if (r
!= 0 && r
!= PTHREAD_BARRIER_SERIAL_THREAD
)
46 puts ("tf: barrier_wait failed");
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");
67 int r
= pthread_barrier_wait (&b
);
68 if (r
!= 0 && r
!= PTHREAD_BARRIER_SERIAL_THREAD
)
70 puts ("tf2: barrier_wait failed");
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");
99 struct aiocb a
, a2
, *ap
;
101 memset (&a
, '\0', sizeof (a
));
102 a
.aio_fildes
= fds
[0];
104 a
.aio_nbytes
= sizeof (mem
);
105 if (aio_read (&a
) != 0)
107 puts ("aio_read failed");
111 if (pthread_barrier_init (&b
, NULL
, 2) != 0)
113 puts ("barrier_init failed");
118 if (pthread_create (&th
, NULL
, tf
, &a
) != 0)
120 puts ("1st create failed");
124 int r
= pthread_barrier_wait (&b
);
125 if (r
!= 0 && r
!= PTHREAD_BARRIER_SERIAL_THREAD
)
127 puts ("barrier_wait failed");
131 struct timespec ts
= { .tv_sec
= 0, .tv_nsec
= 100000000 };
132 while (nanosleep (&ts
, &ts
) != 0)
135 puts ("going to cancel tf in-time");
136 if (pthread_cancel (th
) != 0)
138 puts ("1st cancel failed");
143 if (pthread_join (th
, &status
) != 0)
145 puts ("1st join failed");
148 if (status
!= PTHREAD_CANCELED
)
150 puts ("1st thread not canceled");
156 puts ("tf cleanup handler not called");
161 puts ("tf cleanup handler called more than once");
167 if (pthread_create (&th
, NULL
, tf2
, &a
) != 0)
169 puts ("2nd create failed");
173 r
= pthread_barrier_wait (&b
);
174 if (r
!= 0 && r
!= PTHREAD_BARRIER_SERIAL_THREAD
)
176 puts ("2nd barrier_wait failed");
181 ts
.tv_nsec
= 100000000;
182 while (nanosleep (&ts
, &ts
) != 0)
185 puts ("going to cancel tf2 in-time");
186 if (pthread_cancel (th
) != 0)
188 puts ("2nd cancel failed");
192 if (pthread_join (th
, &status
) != 0)
194 puts ("2nd join failed");
197 if (status
!= PTHREAD_CANCELED
)
199 puts ("2nd thread not canceled");
205 puts ("tf2 cleanup handler not called");
210 puts ("tf2 cleanup handler called more than once");
214 puts ("in-time cancellation succeeded");
217 if (aio_cancel (fds
[0], &a
) != AIO_CANCELED
)
219 puts ("aio_cancel failed");
220 /* If aio_cancel failed, we cannot reuse aiocb a. */
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
);
233 puts ("could not allocate memory for pipe write");
237 memset (ap
, '\0', sizeof (*ap
));
238 ap
->aio_fildes
= fds
[1];
240 ap
->aio_nbytes
= len2
;
241 if (aio_write (ap
) != 0)
243 puts ("aio_write failed");
247 if (pthread_create (&th
, NULL
, tf
, ap
) != 0)
249 puts ("3rd create failed");
253 puts ("going to cancel tf early");
254 if (pthread_cancel (th
) != 0)
256 puts ("3rd cancel failed");
260 r
= pthread_barrier_wait (&b
);
261 if (r
!= 0 && r
!= PTHREAD_BARRIER_SERIAL_THREAD
)
263 puts ("3rd barrier_wait failed");
267 if (pthread_join (th
, &status
) != 0)
269 puts ("3rd join failed");
272 if (status
!= PTHREAD_CANCELED
)
274 puts ("3rd thread not canceled");
280 puts ("tf cleanup handler not called");
285 puts ("tf cleanup handler called more than once");
291 if (pthread_create (&th
, NULL
, tf2
, ap
) != 0)
293 puts ("4th create failed");
297 puts ("going to cancel tf2 early");
298 if (pthread_cancel (th
) != 0)
300 puts ("4th cancel failed");
304 r
= pthread_barrier_wait (&b
);
305 if (r
!= 0 && r
!= PTHREAD_BARRIER_SERIAL_THREAD
)
307 puts ("4th barrier_wait failed");
311 if (pthread_join (th
, &status
) != 0)
313 puts ("4th join failed");
316 if (status
!= PTHREAD_CANCELED
)
318 puts ("4th thread not canceled");
324 puts ("tf2 cleanup handler not called");
329 puts ("tf2 cleanup handler called more than once");
333 puts ("early cancellation succeeded");
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
));
354 #define TEST_FUNCTION do_test ()
355 #include "../test-skeleton.c"