1/* Copyright (C) 2003-2024 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
30static void *
31tf (void *arg)
32{
33 return NULL;
34}
35
36static void
37handler (int sig)
38{
39}
40
41static void __attribute__ ((noinline))
42clobber_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
56static int
57do_test (void)
58{
59 pthread_t th;
60 int old, rc;
61 int ret = 0;
62 int fd[2];
63
64 rc = pipe (pipedes: fd);
65 if (rc < 0)
66 error (EXIT_FAILURE, errno, format: "couldn't create pipe");
67
68 rc = pthread_create (newthread: &th, NULL, start_routine: tf, NULL);
69 if (rc)
70 error (EXIT_FAILURE, errnum: rc, format: "couldn't create thread");
71
72 rc = pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, oldtype: &old);
73 if (rc)
74 {
75 error (status: 0, errnum: rc, format: "1st pthread_setcanceltype failed");
76 ret = 1;
77 }
78 if (old != PTHREAD_CANCEL_DEFERRED && old != PTHREAD_CANCEL_ASYNCHRONOUS)
79 {
80 error (status: 0, errnum: 0, format: "1st pthread_setcanceltype returned invalid value %d",
81 old);
82 ret = 1;
83 }
84
85 clobber_lots_of_regs ();
86 close (fd: fd[0]);
87
88 rc = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, oldtype: &old);
89 if (rc)
90 {
91 error (status: 0, errnum: rc, format: "pthread_setcanceltype after close failed");
92 ret = 1;
93 }
94 if (old != PTHREAD_CANCEL_DEFERRED)
95 {
96 error (status: 0, errnum: 0, format: "pthread_setcanceltype after close returned invalid value %d",
97 old);
98 ret = 1;
99 }
100
101 clobber_lots_of_regs ();
102 close (fd: fd[1]);
103
104 rc = pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, oldtype: &old);
105 if (rc)
106 {
107 error (status: 0, errnum: rc, format: "pthread_setcanceltype after 2nd close failed");
108 ret = 1;
109 }
110 if (old != PTHREAD_CANCEL_ASYNCHRONOUS)
111 {
112 error (status: 0, errnum: 0, format: "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, act: &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, new: &it, NULL);
126
127 clobber_lots_of_regs ();
128 pause ();
129
130 memset (&it, 0, sizeof (it));
131 setitimer (ITIMER_REAL, new: &it, NULL);
132
133 rc = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, oldtype: &old);
134 if (rc)
135 {
136 error (status: 0, errnum: rc, format: "pthread_setcanceltype after pause failed");
137 ret = 1;
138 }
139 if (old != PTHREAD_CANCEL_DEFERRED)
140 {
141 error (status: 0, errnum: 0, format: "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, new: &it, NULL);
150
151 clobber_lots_of_regs ();
152 pause ();
153
154 memset (&it, 0, sizeof (it));
155 setitimer (ITIMER_REAL, new: &it, NULL);
156
157 rc = pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, oldtype: &old);
158 if (rc)
159 {
160 error (status: 0, errnum: rc, format: "pthread_setcanceltype after 2nd pause failed");
161 ret = 1;
162 }
163 if (old != PTHREAD_CANCEL_ASYNCHRONOUS)
164 {
165 error (status: 0, errnum: 0, format: "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 (template: fname) == NULL)
173 {
174 error (status: 0, errno, format: "mkdtemp failed");
175 ret = 1;
176 }
177 *enddir = '/';
178
179 clobber_lots_of_regs ();
180 creat (file: fname, mode: 0400);
181
182 rc = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, oldtype: &old);
183 if (rc)
184 {
185 error (status: 0, errnum: rc, format: "pthread_setcanceltype after creat failed");
186 ret = 1;
187 }
188 if (old != PTHREAD_CANCEL_DEFERRED)
189 {
190 error (status: 0, errnum: 0, format: "pthread_setcanceltype after creat returned invalid value %d",
191 old);
192 ret = 1;
193 }
194
195 clobber_lots_of_regs ();
196 creat (file: fname, mode: 0400);
197
198 rc = pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, oldtype: &old);
199 if (rc)
200 {
201 error (status: 0, errnum: rc, format: "pthread_setcanceltype after 2nd creat failed");
202 ret = 1;
203 }
204 if (old != PTHREAD_CANCEL_ASYNCHRONOUS)
205 {
206 error (status: 0, errnum: 0, format: "pthread_setcanceltype after 2nd creat returned invalid value %d",
207 old);
208 ret = 1;
209 }
210
211 clobber_lots_of_regs ();
212 open (file: fname, O_CREAT, 0400);
213
214 rc = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, oldtype: &old);
215 if (rc)
216 {
217 error (status: 0, errnum: rc, format: "pthread_setcanceltype after open failed");
218 ret = 1;
219 }
220 if (old != PTHREAD_CANCEL_DEFERRED)
221 {
222 error (status: 0, errnum: 0, format: "pthread_setcanceltype after open returned invalid value %d",
223 old);
224 ret = 1;
225 }
226
227 clobber_lots_of_regs ();
228 open (file: fname, O_CREAT, 0400);
229
230 rc = pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, oldtype: &old);
231 if (rc)
232 {
233 error (status: 0, errnum: rc, format: "pthread_setcanceltype after 2nd open failed");
234 ret = 1;
235 }
236 if (old != PTHREAD_CANCEL_ASYNCHRONOUS)
237 {
238 error (status: 0, errnum: 0, format: "pthread_setcanceltype after 2nd open returned invalid value %d",
239 old);
240 ret = 1;
241 }
242
243 *enddir = '\0';
244 rmdir (path: fname);
245
246 clobber_lots_of_regs ();
247 select (nfds: -1, NULL, NULL, NULL, NULL);
248
249 rc = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, oldtype: &old);
250 if (rc)
251 {
252 error (status: 0, errnum: rc, format: "pthread_setcanceltype after select failed");
253 ret = 1;
254 }
255 if (old != PTHREAD_CANCEL_DEFERRED)
256 {
257 error (status: 0, errnum: 0, format: "pthread_setcanceltype after select returned invalid value %d",
258 old);
259 ret = 1;
260 }
261
262 clobber_lots_of_regs ();
263 select (nfds: -1, NULL, NULL, NULL, NULL);
264
265 rc = pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, oldtype: &old);
266 if (rc)
267 {
268 error (status: 0, errnum: rc, format: "pthread_setcanceltype after 2nd select failed");
269 ret = 1;
270 }
271 if (old != PTHREAD_CANCEL_ASYNCHRONOUS)
272 {
273 error (status: 0, errnum: 0, format: "pthread_setcanceltype after 2nd select returned invalid value %d",
274 old);
275 ret = 1;
276 }
277
278 pthread_join (th: th, NULL);
279
280 return ret;
281}
282
283#define TEST_FUNCTION do_test ()
284#include "../test-skeleton.c"
285

source code of glibc/sysdeps/pthread/tst-cancel19.c