chiark / gitweb /
eglibc (2.11.3-4+deb6u3) squeeze-lts; urgency=medium
[eglibc.git] / nptl / tst-cancel17.c
1 /* Copyright (C) 2003, 2005 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
4
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.
9
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.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19
20 #include <aio.h>
21 #include <errno.h>
22 #include <pthread.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27
28
29 static pthread_barrier_t b;
30
31
32 /* Cleanup handling test.  */
33 static int cl_called;
34
35 static void
36 cl (void *arg)
37 {
38   ++cl_called;
39 }
40
41
42 static void *
43 tf (void *arg)
44 {
45   int r = pthread_barrier_wait (&b);
46   if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
47     {
48       puts ("tf: barrier_wait failed");
49       exit (1);
50     }
51
52   pthread_cleanup_push (cl, NULL);
53
54   const struct aiocb *l[1] = { arg };
55
56   TEMP_FAILURE_RETRY (aio_suspend (l, 1, NULL));
57
58   pthread_cleanup_pop (0);
59
60   puts ("tf: aio_suspend returned");
61
62   exit (1);
63 }
64
65
66 static void *
67 tf2 (void *arg)
68 {
69   int r = pthread_barrier_wait (&b);
70   if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
71     {
72       puts ("tf2: barrier_wait failed");
73       exit (1);
74     }
75
76   pthread_cleanup_push (cl, NULL);
77
78   const struct aiocb *l[1] = { arg };
79   struct timespec ts = { .tv_sec = 1000, .tv_nsec = 0 };
80
81   TEMP_FAILURE_RETRY (aio_suspend (l, 1, &ts));
82
83   pthread_cleanup_pop (0);
84
85   puts ("tf2: aio_suspend returned");
86
87   exit (1);
88 }
89
90
91 static int
92 do_test (void)
93 {
94   int fds[2];
95   if (pipe (fds) != 0)
96     {
97       puts ("pipe failed");
98       return 1;
99     }
100
101   struct aiocb a, a2, *ap;
102   char mem[1];
103   memset (&a, '\0', sizeof (a));
104   a.aio_fildes = fds[0];
105   a.aio_buf = mem;
106   a.aio_nbytes = sizeof (mem);
107   if (aio_read (&a) != 0)
108     {
109       puts ("aio_read failed");
110       return 1;
111     }
112
113   if (pthread_barrier_init (&b, NULL, 2) != 0)
114     {
115       puts ("barrier_init failed");
116       return 1;
117     }
118
119   pthread_t th;
120   if (pthread_create (&th, NULL, tf, &a) != 0)
121     {
122       puts ("1st create failed");
123       return 1;
124     }
125
126   int r = pthread_barrier_wait (&b);
127   if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
128     {
129       puts ("barrier_wait failed");
130       exit (1);
131     }
132
133   struct timespec  ts = { .tv_sec = 0, .tv_nsec = 100000000 };
134   while (nanosleep (&ts, &ts) != 0)
135     continue;
136
137   puts ("going to cancel tf in-time");
138   if (pthread_cancel (th) != 0)
139     {
140       puts ("1st cancel failed");
141       return 1;
142     }
143
144   void *status;
145   if (pthread_join (th, &status) != 0)
146     {
147       puts ("1st join failed");
148       return 1;
149     }
150   if (status != PTHREAD_CANCELED)
151     {
152       puts ("1st thread not canceled");
153       return 1;
154     }
155
156   if (cl_called == 0)
157     {
158       puts ("tf cleanup handler not called");
159       return 1;
160     }
161   if (cl_called > 1)
162     {
163       puts ("tf cleanup handler called more than once");
164       return 1;
165     }
166
167   cl_called = 0;
168
169   if (pthread_create (&th, NULL, tf2, &a) != 0)
170     {
171       puts ("2nd create failed");
172       return 1;
173     }
174
175   r = pthread_barrier_wait (&b);
176   if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
177     {
178       puts ("2nd barrier_wait failed");
179       exit (1);
180     }
181
182   ts.tv_sec = 0;
183   ts.tv_nsec = 100000000;
184   while (nanosleep (&ts, &ts) != 0)
185     continue;
186
187   puts ("going to cancel tf2 in-time");
188   if (pthread_cancel (th) != 0)
189     {
190       puts ("2nd cancel failed");
191       return 1;
192     }
193
194   if (pthread_join (th, &status) != 0)
195     {
196       puts ("2nd join failed");
197       return 1;
198     }
199   if (status != PTHREAD_CANCELED)
200     {
201       puts ("2nd thread not canceled");
202       return 1;
203     }
204
205   if (cl_called == 0)
206     {
207       puts ("tf2 cleanup handler not called");
208       return 1;
209     }
210   if (cl_called > 1)
211     {
212       puts ("tf2 cleanup handler called more than once");
213       return 1;
214     }
215
216   puts ("in-time cancellation succeeded");
217
218   ap = &a;
219   if (aio_cancel (fds[0], &a) != AIO_CANCELED)
220     {
221       puts ("aio_cancel failed");
222       /* If aio_cancel failed, we cannot reuse aiocb a.  */
223       ap = &a2;
224     }
225
226
227   cl_called = 0;
228
229   size_t len2 = fpathconf (fds[1], _PC_PIPE_BUF);
230   size_t page_size = sysconf (_SC_PAGESIZE);
231   len2 = 20 * (len2 < page_size ? page_size : len2) + sizeof (mem) + 1;
232   char *mem2 = malloc (len2);
233   if (mem2 == NULL)
234     {
235       puts ("could not allocate memory for pipe write");
236       return 1;
237     }
238
239   memset (ap, '\0', sizeof (*ap));
240   ap->aio_fildes = fds[1];
241   ap->aio_buf = mem2;
242   ap->aio_nbytes = len2;
243   if (aio_write (ap) != 0)
244     {
245       puts ("aio_write failed");
246       return 1;
247     }
248
249   if (pthread_create (&th, NULL, tf, ap) != 0)
250     {
251       puts ("3rd create failed");
252       return 1;
253     }
254
255   puts ("going to cancel tf early");
256   if (pthread_cancel (th) != 0)
257     {
258       puts ("3rd cancel failed");
259       return 1;
260     }
261
262   r = pthread_barrier_wait (&b);
263   if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
264     {
265       puts ("3rd barrier_wait failed");
266       exit (1);
267     }
268
269   if (pthread_join (th, &status) != 0)
270     {
271       puts ("3rd join failed");
272       return 1;
273     }
274   if (status != PTHREAD_CANCELED)
275     {
276       puts ("3rd thread not canceled");
277       return 1;
278     }
279
280   if (cl_called == 0)
281     {
282       puts ("tf cleanup handler not called");
283       return 1;
284     }
285   if (cl_called > 1)
286     {
287       puts ("tf cleanup handler called more than once");
288       return 1;
289     }
290
291   cl_called = 0;
292
293   if (pthread_create (&th, NULL, tf2, ap) != 0)
294     {
295       puts ("4th create failed");
296       return 1;
297     }
298
299   puts ("going to cancel tf2 early");
300   if (pthread_cancel (th) != 0)
301     {
302       puts ("4th cancel failed");
303       return 1;
304     }
305
306   r = pthread_barrier_wait (&b);
307   if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
308     {
309       puts ("4th barrier_wait failed");
310       exit (1);
311     }
312
313   if (pthread_join (th, &status) != 0)
314     {
315       puts ("4th join failed");
316       return 1;
317     }
318   if (status != PTHREAD_CANCELED)
319     {
320       puts ("4th thread not canceled");
321       return 1;
322     }
323
324   if (cl_called == 0)
325     {
326       puts ("tf2 cleanup handler not called");
327       return 1;
328     }
329   if (cl_called > 1)
330     {
331       puts ("tf2 cleanup handler called more than once");
332       return 1;
333     }
334
335   puts ("early cancellation succeeded");
336
337   return 0;
338 }
339
340 #define TEST_FUNCTION do_test ()
341 #include "../test-skeleton.c"