1 /* Copyright (C) 2003-2020 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
28 static pthread_barrier_t b
;
31 /* Cleanup handling test. */
44 int r
= pthread_barrier_wait (&b
);
45 if (r
!= 0 && r
!= PTHREAD_BARRIER_SERIAL_THREAD
)
47 puts ("tf: barrier_wait failed");
51 pthread_cleanup_push (cl
, NULL
);
53 const struct aiocb
*l
[1] = { arg
};
55 TEMP_FAILURE_RETRY (aio_suspend (l
, 1, NULL
));
57 pthread_cleanup_pop (0);
59 puts ("tf: aio_suspend returned");
68 int r
= pthread_barrier_wait (&b
);
69 if (r
!= 0 && r
!= PTHREAD_BARRIER_SERIAL_THREAD
)
71 puts ("tf2: barrier_wait failed");
75 pthread_cleanup_push (cl
, NULL
);
77 const struct aiocb
*l
[1] = { arg
};
78 struct timespec ts
= { .tv_sec
= 1000, .tv_nsec
= 0 };
80 TEMP_FAILURE_RETRY (aio_suspend (l
, 1, &ts
));
82 pthread_cleanup_pop (0);
84 puts ("tf2: aio_suspend returned");
100 struct aiocb a
, a2
, *ap
;
102 memset (&a
, '\0', sizeof (a
));
103 a
.aio_fildes
= fds
[0];
105 a
.aio_nbytes
= sizeof (mem
);
106 if (aio_read (&a
) != 0)
108 puts ("aio_read failed");
112 if (pthread_barrier_init (&b
, NULL
, 2) != 0)
114 puts ("barrier_init failed");
119 if (pthread_create (&th
, NULL
, tf
, &a
) != 0)
121 puts ("1st create failed");
125 int r
= pthread_barrier_wait (&b
);
126 if (r
!= 0 && r
!= PTHREAD_BARRIER_SERIAL_THREAD
)
128 puts ("barrier_wait failed");
132 struct timespec ts
= { .tv_sec
= 0, .tv_nsec
= 100000000 };
133 while (nanosleep (&ts
, &ts
) != 0)
136 puts ("going to cancel tf in-time");
137 if (pthread_cancel (th
) != 0)
139 puts ("1st cancel failed");
144 if (pthread_join (th
, &status
) != 0)
146 puts ("1st join failed");
149 if (status
!= PTHREAD_CANCELED
)
151 puts ("1st thread not canceled");
157 puts ("tf cleanup handler not called");
162 puts ("tf cleanup handler called more than once");
168 if (pthread_create (&th
, NULL
, tf2
, &a
) != 0)
170 puts ("2nd create failed");
174 r
= pthread_barrier_wait (&b
);
175 if (r
!= 0 && r
!= PTHREAD_BARRIER_SERIAL_THREAD
)
177 puts ("2nd barrier_wait failed");
182 ts
.tv_nsec
= 100000000;
183 while (nanosleep (&ts
, &ts
) != 0)
186 puts ("going to cancel tf2 in-time");
187 if (pthread_cancel (th
) != 0)
189 puts ("2nd cancel failed");
193 if (pthread_join (th
, &status
) != 0)
195 puts ("2nd join failed");
198 if (status
!= PTHREAD_CANCELED
)
200 puts ("2nd thread not canceled");
206 puts ("tf2 cleanup handler not called");
211 puts ("tf2 cleanup handler called more than once");
215 puts ("in-time cancellation succeeded");
218 if (aio_cancel (fds
[0], &a
) != AIO_CANCELED
)
220 puts ("aio_cancel failed");
221 /* If aio_cancel failed, we cannot reuse aiocb a. */
228 size_t len2
= fpathconf (fds
[1], _PC_PIPE_BUF
);
229 size_t page_size
= sysconf (_SC_PAGESIZE
);
230 len2
= 20 * (len2
< page_size
? page_size
: len2
) + sizeof (mem
) + 1;
231 char *mem2
= malloc (len2
);
234 puts ("could not allocate memory for pipe write");
238 memset (ap
, '\0', sizeof (*ap
));
239 ap
->aio_fildes
= fds
[1];
241 ap
->aio_nbytes
= len2
;
242 if (aio_write (ap
) != 0)
244 puts ("aio_write failed");
248 if (pthread_create (&th
, NULL
, tf
, ap
) != 0)
250 puts ("3rd create failed");
254 puts ("going to cancel tf early");
255 if (pthread_cancel (th
) != 0)
257 puts ("3rd cancel failed");
261 r
= pthread_barrier_wait (&b
);
262 if (r
!= 0 && r
!= PTHREAD_BARRIER_SERIAL_THREAD
)
264 puts ("3rd barrier_wait failed");
268 if (pthread_join (th
, &status
) != 0)
270 puts ("3rd join failed");
273 if (status
!= PTHREAD_CANCELED
)
275 puts ("3rd thread not canceled");
281 puts ("tf cleanup handler not called");
286 puts ("tf cleanup handler called more than once");
292 if (pthread_create (&th
, NULL
, tf2
, ap
) != 0)
294 puts ("4th create failed");
298 puts ("going to cancel tf2 early");
299 if (pthread_cancel (th
) != 0)
301 puts ("4th cancel failed");
305 r
= pthread_barrier_wait (&b
);
306 if (r
!= 0 && r
!= PTHREAD_BARRIER_SERIAL_THREAD
)
308 puts ("4th barrier_wait failed");
312 if (pthread_join (th
, &status
) != 0)
314 puts ("4th join failed");
317 if (status
!= PTHREAD_CANCELED
)
319 puts ("4th thread not canceled");
325 puts ("tf2 cleanup handler not called");
330 puts ("tf2 cleanup handler called more than once");
334 puts ("early cancellation succeeded");
338 /* The aio_read(&a) was not canceled because the read request was
339 already in progress. In the meanwhile aio_write(ap) wrote something
340 to the pipe and the read request either has already been finished or
341 is able to read the requested byte.
342 Wait for the read request before returning from this function because
343 the return value and error code from the read syscall will be written
344 to the struct aiocb a, which lies on the stack of this function.
345 Otherwise the stack from subsequent function calls - e.g. _dl_fini -
346 will be corrupted, which can lead to undefined behaviour like a
347 segmentation fault. */
348 const struct aiocb
*l
[1] = { &a
};
349 TEMP_FAILURE_RETRY (aio_suspend(l
, 1, NULL
));
355 #define TEST_FUNCTION do_test ()
356 #include "../test-skeleton.c"