1 /* Copyright (C) 2003-2022 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3 
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.
8 
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.
13 
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/>.  */
17 
18 #include <errno.h>
19 #include <pthread.h>
20 #include <signal.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 
25 
26 static int fd[4];
27 static pthread_barrier_t b;
28 volatile int in_sh_body;
29 unsigned long cleanups;
30 
31 static void
cl(void * arg)32 cl (void *arg)
33 {
34   cleanups = (cleanups << 4) | (long) arg;
35 }
36 
37 
38 static void __attribute__((noinline))
sh_body(void)39 sh_body (void)
40 {
41   char c;
42 
43   pthread_cleanup_push (cl, (void *) 1L);
44 
45   in_sh_body = 1;
46   if (read (fd[2], &c, 1) == 1)
47     {
48       puts ("read succeeded");
49       exit (1);
50     }
51 
52   pthread_cleanup_pop (0);
53 }
54 
55 
56 static void
sh(int sig)57 sh (int sig)
58 {
59   pthread_cleanup_push (cl, (void *) 2L);
60   sh_body ();
61   in_sh_body = 0;
62 
63   pthread_cleanup_pop (0);
64 }
65 
66 
67 static void __attribute__((noinline))
tf_body(void)68 tf_body (void)
69 {
70   char c;
71 
72   pthread_cleanup_push (cl, (void *) 3L);
73 
74   int r = pthread_barrier_wait (&b);
75   if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
76     {
77       puts ("child thread: barrier_wait failed");
78       exit (1);
79     }
80 
81   if (read (fd[0], &c, 1) == 1)
82     {
83       puts ("read succeeded");
84       exit (1);
85     }
86 
87   read (fd[0], &c, 1);
88 
89   pthread_cleanup_pop (0);
90 }
91 
92 
93 static void *
tf(void * arg)94 tf (void *arg)
95 {
96   pthread_cleanup_push (cl, (void *) 4L);
97   tf_body ();
98   pthread_cleanup_pop (0);
99   return NULL;
100 }
101 
102 
103 static int
do_one_test(void)104 do_one_test (void)
105 {
106   in_sh_body = 0;
107   cleanups = 0;
108   if (pipe (fd) != 0 || pipe (fd + 2) != 0)
109     {
110       puts ("pipe failed");
111       return 1;
112     }
113 
114   pthread_t th;
115   if (pthread_create (&th, NULL, tf, NULL) != 0)
116     {
117       puts ("create failed");
118       return 1;
119     }
120 
121   int r = pthread_barrier_wait (&b);
122   if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
123     {
124       puts ("parent thread: barrier_wait failed");
125       return 1;
126     }
127 
128   sleep (1);
129 
130   r = pthread_kill (th, SIGHUP);
131   if (r)
132     {
133       errno = r;
134       printf ("pthread_kill failed %m\n");
135       return 1;
136     }
137 
138   while (in_sh_body == 0)
139     sleep (1);
140 
141   if (pthread_cancel (th) != 0)
142     {
143       puts ("cancel failed");
144       return 1;
145     }
146 
147   void *ret;
148   if (pthread_join (th, &ret) != 0)
149     {
150       puts ("join failed");
151       return 1;
152     }
153 
154   if (ret != PTHREAD_CANCELED)
155     {
156       puts ("result is wrong");
157       return 1;
158     }
159 
160   if (cleanups != 0x1234L)
161     {
162       printf ("called cleanups %lx\n", cleanups);
163       return 1;
164     }
165 
166   /* The pipe closing must be issued after the cancellation handling to avoid
167      a race condition where the cancellation runs after both pipe ends are
168      closed.  In this case the read syscall returns EOF and the cancellation
169      must not act.  */
170   close (fd[0]);
171   close (fd[1]);
172   close (fd[2]);
173   close (fd[3]);
174 
175   return 0;
176 }
177 
178 
179 static int
do_test(void)180 do_test (void)
181 {
182   stack_t ss;
183   ss.ss_sp = malloc (2 * SIGSTKSZ);
184   if (ss.ss_sp == NULL)
185     {
186       puts ("failed to allocate alternate stack");
187       return 1;
188     }
189   ss.ss_flags = 0;
190   ss.ss_size = 2 * SIGSTKSZ;
191   if (sigaltstack (&ss, NULL) < 0)
192     {
193       printf ("sigaltstack failed %m\n");
194       return 1;
195     }
196 
197   if (pthread_barrier_init (&b, NULL, 2) != 0)
198     {
199       puts ("barrier_init failed");
200       return 1;
201     }
202 
203   struct sigaction sa;
204   sa.sa_handler = sh;
205   sigemptyset (&sa.sa_mask);
206   sa.sa_flags = 0;
207 
208   if (sigaction (SIGHUP, &sa, NULL) != 0)
209     {
210       puts ("sigaction failed");
211       return 1;
212     }
213 
214   puts ("sa_flags = 0 test");
215   if (do_one_test ())
216     return 1;
217 
218   sa.sa_handler = sh;
219   sigemptyset (&sa.sa_mask);
220   sa.sa_flags = SA_ONSTACK;
221 
222   if (sigaction (SIGHUP, &sa, NULL) != 0)
223     {
224       puts ("sigaction failed");
225       return 1;
226     }
227 
228   puts ("sa_flags = SA_ONSTACK test");
229   if (do_one_test ())
230     return 1;
231 
232 #ifdef SA_SIGINFO
233   sa.sa_sigaction = (void (*)(int, siginfo_t *, void *)) sh;
234   sigemptyset (&sa.sa_mask);
235   sa.sa_flags = SA_SIGINFO;
236 
237   if (sigaction (SIGHUP, &sa, NULL) != 0)
238     {
239       puts ("sigaction failed");
240       return 1;
241     }
242 
243   puts ("sa_flags = SA_SIGINFO test");
244   if (do_one_test ())
245     return 1;
246 
247   sa.sa_sigaction = (void (*)(int, siginfo_t *, void *)) sh;
248   sigemptyset (&sa.sa_mask);
249   sa.sa_flags = SA_SIGINFO | 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_SIGINFO|SA_ONSTACK test");
258   if (do_one_test ())
259     return 1;
260 #endif
261 
262   return 0;
263 }
264 
265 #define TIMEOUT 40
266 #define TEST_FUNCTION do_test ()
267 #include "../test-skeleton.c"
268