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 <error.h>
20 #include <fcntl.h>
21 #include <pthread.h>
22 #include <signal.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/select.h>
27 #include <sys/time.h>
28 #include <unistd.h>
29 
30 static void *
tf(void * arg)31 tf (void *arg)
32 {
33   return NULL;
34 }
35 
36 static void
handler(int sig)37 handler (int sig)
38 {
39 }
40 
41 static void __attribute__ ((noinline))
clobber_lots_of_regs(void)42 clobber_lots_of_regs (void)
43 {
44 #define X1(n) long r##n = 10##n; __asm __volatile ("" : "+r" (r##n));
45 #define X2(n) X1(n##0) X1(n##1) X1(n##2) X1(n##3) X1(n##4)
46 #define X3(n) X2(n##0) X2(n##1) X2(n##2) X2(n##3) X2(n##4)
47   X3(0) X3(1) X3(2) X3(3) X3(4)
48 #undef X1
49 #define X1(n) __asm __volatile ("" : : "r" (r##n));
50   X3(0) X3(1) X3(2) X3(3) X3(4)
51 #undef X1
52 #undef X2
53 #undef X3
54 }
55 
56 static int
do_test(void)57 do_test (void)
58 {
59   pthread_t th;
60   int old, rc;
61   int ret = 0;
62   int fd[2];
63 
64   rc = pipe (fd);
65   if (rc < 0)
66     error (EXIT_FAILURE, errno, "couldn't create pipe");
67 
68   rc = pthread_create (&th, NULL, tf, NULL);
69   if (rc)
70     error (EXIT_FAILURE, rc, "couldn't create thread");
71 
72   rc = pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &old);
73   if (rc)
74     {
75       error (0, rc, "1st pthread_setcanceltype failed");
76       ret = 1;
77     }
78   if (old != PTHREAD_CANCEL_DEFERRED && old != PTHREAD_CANCEL_ASYNCHRONOUS)
79     {
80       error (0, 0, "1st pthread_setcanceltype returned invalid value %d",
81 	     old);
82       ret = 1;
83     }
84 
85   clobber_lots_of_regs ();
86   close (fd[0]);
87 
88   rc = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &old);
89   if (rc)
90     {
91       error (0, rc, "pthread_setcanceltype after close failed");
92       ret = 1;
93     }
94   if (old != PTHREAD_CANCEL_DEFERRED)
95     {
96       error (0, 0, "pthread_setcanceltype after close returned invalid value %d",
97 	     old);
98       ret = 1;
99     }
100 
101   clobber_lots_of_regs ();
102   close (fd[1]);
103 
104   rc = pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &old);
105   if (rc)
106     {
107       error (0, rc, "pthread_setcanceltype after 2nd close failed");
108       ret = 1;
109     }
110   if (old != PTHREAD_CANCEL_ASYNCHRONOUS)
111     {
112       error (0, 0, "pthread_setcanceltype after 2nd close returned invalid value %d",
113 	     old);
114       ret = 1;
115     }
116 
117   struct sigaction sa = { .sa_handler = handler, .sa_flags = 0 };
118   sigemptyset (&sa.sa_mask);
119   sigaction (SIGALRM, &sa, NULL);
120 
121   struct itimerval it;
122   it.it_value.tv_sec = 1;
123   it.it_value.tv_usec = 0;
124   it.it_interval = it.it_value;
125   setitimer (ITIMER_REAL, &it, NULL);
126 
127   clobber_lots_of_regs ();
128   pause ();
129 
130   memset (&it, 0, sizeof (it));
131   setitimer (ITIMER_REAL, &it, NULL);
132 
133   rc = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &old);
134   if (rc)
135     {
136       error (0, rc, "pthread_setcanceltype after pause failed");
137       ret = 1;
138     }
139   if (old != PTHREAD_CANCEL_DEFERRED)
140     {
141       error (0, 0, "pthread_setcanceltype after pause returned invalid value %d",
142 	     old);
143       ret = 1;
144     }
145 
146   it.it_value.tv_sec = 1;
147   it.it_value.tv_usec = 0;
148   it.it_interval = it.it_value;
149   setitimer (ITIMER_REAL, &it, NULL);
150 
151   clobber_lots_of_regs ();
152   pause ();
153 
154   memset (&it, 0, sizeof (it));
155   setitimer (ITIMER_REAL, &it, NULL);
156 
157   rc = pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &old);
158   if (rc)
159     {
160       error (0, rc, "pthread_setcanceltype after 2nd pause failed");
161       ret = 1;
162     }
163   if (old != PTHREAD_CANCEL_ASYNCHRONOUS)
164     {
165       error (0, 0, "pthread_setcanceltype after 2nd pause returned invalid value %d",
166 	     old);
167       ret = 1;
168     }
169 
170   char fname[] = "/tmp/tst-cancel19-dir-XXXXXX\0foo/bar";
171   char *enddir = strchr (fname, '\0');
172   if (mkdtemp (fname) == NULL)
173     {
174       error (0, errno, "mkdtemp failed");
175       ret = 1;
176     }
177   *enddir = '/';
178 
179   clobber_lots_of_regs ();
180   creat (fname, 0400);
181 
182   rc = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &old);
183   if (rc)
184     {
185       error (0, rc, "pthread_setcanceltype after creat failed");
186       ret = 1;
187     }
188   if (old != PTHREAD_CANCEL_DEFERRED)
189     {
190       error (0, 0, "pthread_setcanceltype after creat returned invalid value %d",
191 	     old);
192       ret = 1;
193     }
194 
195   clobber_lots_of_regs ();
196   creat (fname, 0400);
197 
198   rc = pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &old);
199   if (rc)
200     {
201       error (0, rc, "pthread_setcanceltype after 2nd creat failed");
202       ret = 1;
203     }
204   if (old != PTHREAD_CANCEL_ASYNCHRONOUS)
205     {
206       error (0, 0, "pthread_setcanceltype after 2nd creat returned invalid value %d",
207 	     old);
208       ret = 1;
209     }
210 
211   clobber_lots_of_regs ();
212   open (fname, O_CREAT, 0400);
213 
214   rc = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &old);
215   if (rc)
216     {
217       error (0, rc, "pthread_setcanceltype after open failed");
218       ret = 1;
219     }
220   if (old != PTHREAD_CANCEL_DEFERRED)
221     {
222       error (0, 0, "pthread_setcanceltype after open returned invalid value %d",
223 	     old);
224       ret = 1;
225     }
226 
227   clobber_lots_of_regs ();
228   open (fname, O_CREAT, 0400);
229 
230   rc = pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &old);
231   if (rc)
232     {
233       error (0, rc, "pthread_setcanceltype after 2nd open failed");
234       ret = 1;
235     }
236   if (old != PTHREAD_CANCEL_ASYNCHRONOUS)
237     {
238       error (0, 0, "pthread_setcanceltype after 2nd open returned invalid value %d",
239 	     old);
240       ret = 1;
241     }
242 
243   *enddir = '\0';
244   rmdir (fname);
245 
246   clobber_lots_of_regs ();
247   select (-1, NULL, NULL, NULL, NULL);
248 
249   rc = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &old);
250   if (rc)
251     {
252       error (0, rc, "pthread_setcanceltype after select failed");
253       ret = 1;
254     }
255   if (old != PTHREAD_CANCEL_DEFERRED)
256     {
257       error (0, 0, "pthread_setcanceltype after select returned invalid value %d",
258 	     old);
259       ret = 1;
260     }
261 
262   clobber_lots_of_regs ();
263   select (-1, NULL, NULL, NULL, NULL);
264 
265   rc = pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &old);
266   if (rc)
267     {
268       error (0, rc, "pthread_setcanceltype after 2nd select failed");
269       ret = 1;
270     }
271   if (old != PTHREAD_CANCEL_ASYNCHRONOUS)
272     {
273       error (0, 0, "pthread_setcanceltype after 2nd select returned invalid value %d",
274 	     old);
275       ret = 1;
276     }
277 
278   pthread_join (th, NULL);
279 
280   return ret;
281 }
282 
283 #define TEST_FUNCTION do_test ()
284 #include "../test-skeleton.c"
285