chiark / gitweb /
eglibc (2.11.3-4+deb6u3) squeeze-lts; urgency=medium
[eglibc.git] / nptl / tst-cancel21.c
1 /* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Jakub Jelinek <jakub@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 <errno.h>
21 #include <pthread.h>
22 #include <signal.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <sys/wait.h>
26 #include <unistd.h>
27
28
29 static int fd[4];
30 static pthread_barrier_t b;
31 volatile int in_sh_body;
32 unsigned long cleanups;
33
34 static void
35 cl (void *arg)
36 {
37   cleanups = (cleanups << 4) | (long) arg;
38 }
39
40
41 static void __attribute__((noinline))
42 sh_body (void)
43 {
44   char c;
45
46   pthread_cleanup_push (cl, (void *) 1L);
47
48   in_sh_body = 1;
49   if (read (fd[2], &c, 1) == 1)
50     {
51       puts ("read succeeded");
52       exit (1);
53     }
54
55   pthread_cleanup_pop (0);
56 }
57
58
59 static void
60 sh (int sig)
61 {
62   pthread_cleanup_push (cl, (void *) 2L);
63   sh_body ();
64   in_sh_body = 0;
65
66   pthread_cleanup_pop (0);
67 }
68
69
70 static void __attribute__((noinline))
71 tf_body (void)
72 {
73   char c;
74
75   pthread_cleanup_push (cl, (void *) 3L);
76
77   int r = pthread_barrier_wait (&b);
78   if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
79     {
80       puts ("child thread: barrier_wait failed");
81       exit (1);
82     }
83
84   if (read (fd[0], &c, 1) == 1)
85     {
86       puts ("read succeeded");
87       exit (1);
88     }
89
90   read (fd[0], &c, 1);
91
92   pthread_cleanup_pop (0);
93 }
94
95
96 static void *
97 tf (void *arg)
98 {
99   pthread_t th = (pthread_t) arg;
100
101   int r = pthread_barrier_wait (&b);
102   if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
103     {
104       puts ("parent thread: barrier_wait failed");
105       exit (1);
106     }
107
108   sleep (1);
109
110   r = pthread_kill (th, SIGHUP);
111   if (r)
112     {
113       errno = r;
114       printf ("pthread_kill failed %m\n");
115       exit (1);
116     }
117
118   while (in_sh_body == 0)
119     sleep (1);
120
121   if (pthread_cancel (th) != 0)
122     {
123       puts ("cancel failed");
124       exit (1);
125     }
126
127   /* This will cause the read in the initial thread to return.  */
128   close (fd[0]);
129   close (fd[1]);
130   close (fd[2]);
131   close (fd[3]);
132
133   void *ret;
134   if (pthread_join (th, &ret) != 0)
135     {
136       puts ("join failed");
137       exit (1);
138     }
139
140   if (ret != PTHREAD_CANCELED)
141     {
142       puts ("result is wrong");
143       exit (1);
144     }
145
146   if (cleanups != 0x1234L)
147     {
148       printf ("called cleanups %lx\n", cleanups);
149       exit (1);
150     }
151
152   if (pthread_barrier_destroy (&b))
153     {
154       puts ("barrier destroy failed");
155       exit (1);
156     }
157
158   exit (0);
159 }
160
161
162 static int
163 do_one_test (void)
164 {
165   in_sh_body = 0;
166
167   pid_t pid = fork ();
168
169   if (pid == -1)
170     {
171       printf ("fork failed: %m\n");
172       return 1;
173     }
174
175   if (pid)
176     {
177       int status;
178       if (waitpid (pid, &status, 0) < 0)
179         {
180           printf ("waitpid failed %m\n");
181           return 1;
182         }
183
184       return !WIFEXITED (status) || WEXITSTATUS (status);
185     }
186
187   if (pthread_barrier_init (&b, NULL, 2) != 0)
188     {
189       puts ("barrier_init failed");
190       exit (1);
191     }
192
193   cleanups = 0;
194   if (pipe (fd) != 0 || pipe (fd + 2) != 0)
195     {
196       puts ("pipe failed");
197       exit (1);
198     }
199
200   pthread_t th;
201   if (pthread_create (&th, NULL, tf, (void *) pthread_self ()) != 0)
202     {
203       puts ("create failed");
204       exit (1);
205     }
206
207   pthread_cleanup_push (cl, (void *) 4L);
208   tf_body ();
209   pthread_cleanup_pop (0);
210   exit (1);
211 }
212
213
214 static int
215 do_test (void)
216 {
217   stack_t ss;
218   ss.ss_sp = malloc (2 * SIGSTKSZ);
219   if (ss.ss_sp == NULL)
220     {
221       puts ("failed to allocate alternate stack");
222       return 1;
223     }
224   ss.ss_flags = 0;
225   ss.ss_size = 2 * SIGSTKSZ;
226   if (sigaltstack (&ss, NULL) < 0)
227     {
228       printf ("sigaltstack failed %m\n");
229       return 1;
230     }
231
232   struct sigaction sa;
233   sa.sa_handler = sh;
234   sigemptyset (&sa.sa_mask);
235   sa.sa_flags = 0;
236
237   if (sigaction (SIGHUP, &sa, NULL) != 0)
238     {
239       puts ("sigaction failed");
240       return 1;
241     }
242
243   puts ("sa_flags = 0 test");
244   if (do_one_test ())
245     return 1;
246
247   sa.sa_handler = sh;
248   sigemptyset (&sa.sa_mask);
249   sa.sa_flags = SA_ONSTACK;
250
251   if (sigaction (SIGHUP, &sa, NULL) != 0)
252     {
253       puts ("sigaction failed");
254       return 1;
255     }
256
257   puts ("sa_flags = SA_ONSTACK test");
258   if (do_one_test ())
259     return 1;
260
261   sa.sa_sigaction = (void (*)(int, siginfo_t *, void *)) sh;
262   sigemptyset (&sa.sa_mask);
263   sa.sa_flags = SA_SIGINFO;
264
265   if (sigaction (SIGHUP, &sa, NULL) != 0)
266     {
267       puts ("sigaction failed");
268       return 1;
269     }
270
271   puts ("sa_flags = SA_SIGINFO test");
272   if (do_one_test ())
273     return 1;
274
275   sa.sa_sigaction = (void (*)(int, siginfo_t *, void *)) sh;
276   sigemptyset (&sa.sa_mask);
277   sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
278
279   if (sigaction (SIGHUP, &sa, NULL) != 0)
280     {
281       puts ("sigaction failed");
282       return 1;
283     }
284
285   puts ("sa_flags = SA_SIGINFO|SA_ONSTACK test");
286   if (do_one_test ())
287     return 1;
288
289   return 0;
290 }
291
292 #define TIMEOUT 40
293 #define TEST_FUNCTION do_test ()
294 #include "../test-skeleton.c"