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 | |
30 | static void * |
31 | tf (void *arg) |
32 | { |
33 | return NULL; |
34 | } |
35 | |
36 | static void |
37 | handler (int sig) |
38 | { |
39 | } |
40 | |
41 | static void __attribute__ ((noinline)) |
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 |
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 (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 | |