1 | /* pthread_getattr_np test. |
2 | Copyright (C) 2003-2022 Free Software Foundation, Inc. |
3 | This file is part of the GNU C Library. |
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, see |
17 | <https://www.gnu.org/licenses/>. */ |
18 | |
19 | #include <errno.h> |
20 | #include <error.h> |
21 | #include <pthread.h> |
22 | #include <stdio.h> |
23 | #include <stdlib.h> |
24 | #include <string.h> |
25 | #include <unistd.h> |
26 | |
27 | #include <stackinfo.h> |
28 | #include <libc-diag.h> |
29 | |
30 | static void * |
31 | tf (void *arg) |
32 | { |
33 | pthread_attr_t a, *ap, a2; |
34 | int err; |
35 | void *result = NULL; |
36 | |
37 | if (arg == NULL) |
38 | { |
39 | ap = &a2; |
40 | err = pthread_attr_init (attr: ap); |
41 | if (err) |
42 | { |
43 | error (status: 0, errnum: err, format: "pthread_attr_init failed" ); |
44 | return tf; |
45 | } |
46 | } |
47 | else |
48 | ap = (pthread_attr_t *) arg; |
49 | |
50 | err = pthread_getattr_np (th: pthread_self (), attr: &a); |
51 | if (err) |
52 | { |
53 | error (status: 0, errnum: err, format: "pthread_getattr_np failed" ); |
54 | result = tf; |
55 | } |
56 | |
57 | int detachstate1, detachstate2; |
58 | err = pthread_attr_getdetachstate (attr: &a, detachstate: &detachstate1); |
59 | if (err) |
60 | { |
61 | error (status: 0, errnum: err, format: "pthread_attr_getdetachstate failed" ); |
62 | result = tf; |
63 | } |
64 | else |
65 | { |
66 | err = pthread_attr_getdetachstate (attr: ap, detachstate: &detachstate2); |
67 | if (err) |
68 | { |
69 | error (status: 0, errnum: err, format: "pthread_attr_getdetachstate failed" ); |
70 | result = tf; |
71 | } |
72 | else if (detachstate1 != detachstate2) |
73 | { |
74 | error (status: 0, errnum: 0, format: "detachstate differs %d != %d" , |
75 | detachstate1, detachstate2); |
76 | result = tf; |
77 | } |
78 | } |
79 | |
80 | void *stackaddr; |
81 | size_t stacksize; |
82 | err = pthread_attr_getstack (attr: &a, stackaddr: &stackaddr, stacksize: &stacksize); |
83 | if (err) |
84 | { |
85 | error (status: 0, errnum: err, format: "pthread_attr_getstack failed" ); |
86 | result = tf; |
87 | } |
88 | else if ((void *) &a < stackaddr |
89 | || (void *) &a >= stackaddr + stacksize) |
90 | { |
91 | error (status: 0, errnum: 0, format: "pthread_attr_getstack returned range does not cover thread's stack" ); |
92 | result = tf; |
93 | } |
94 | else |
95 | printf (format: "thread stack %p-%p (0x%zx)\n" , stackaddr, stackaddr + stacksize, |
96 | stacksize); |
97 | |
98 | size_t guardsize1, guardsize2; |
99 | err = pthread_attr_getguardsize (attr: &a, guardsize: &guardsize1); |
100 | if (err) |
101 | { |
102 | error (status: 0, errnum: err, format: "pthread_attr_getguardsize failed" ); |
103 | result = tf; |
104 | } |
105 | else |
106 | { |
107 | err = pthread_attr_getguardsize (attr: ap, guardsize: &guardsize2); |
108 | if (err) |
109 | { |
110 | error (status: 0, errnum: err, format: "pthread_attr_getguardsize failed" ); |
111 | result = tf; |
112 | } |
113 | else if (guardsize1 != guardsize2) |
114 | { |
115 | error (status: 0, errnum: 0, format: "guardsize differs %zd != %zd" , |
116 | guardsize1, guardsize2); |
117 | result = tf; |
118 | } |
119 | else |
120 | printf (format: "thread guardsize %zd\n" , guardsize1); |
121 | } |
122 | |
123 | int scope1, scope2; |
124 | err = pthread_attr_getscope (attr: &a, scope: &scope1); |
125 | if (err) |
126 | { |
127 | error (status: 0, errnum: err, format: "pthread_attr_getscope failed" ); |
128 | result = tf; |
129 | } |
130 | else |
131 | { |
132 | err = pthread_attr_getscope (attr: ap, scope: &scope2); |
133 | if (err) |
134 | { |
135 | error (status: 0, errnum: err, format: "pthread_attr_getscope failed" ); |
136 | result = tf; |
137 | } |
138 | else if (scope1 != scope2) |
139 | { |
140 | error (status: 0, errnum: 0, format: "scope differs %d != %d" , |
141 | scope1, scope2); |
142 | result = tf; |
143 | } |
144 | } |
145 | |
146 | int inheritsched1, inheritsched2; |
147 | err = pthread_attr_getinheritsched (attr: &a, inherit: &inheritsched1); |
148 | if (err) |
149 | { |
150 | error (status: 0, errnum: err, format: "pthread_attr_getinheritsched failed" ); |
151 | result = tf; |
152 | } |
153 | else |
154 | { |
155 | err = pthread_attr_getinheritsched (attr: ap, inherit: &inheritsched2); |
156 | if (err) |
157 | { |
158 | error (status: 0, errnum: err, format: "pthread_attr_getinheritsched failed" ); |
159 | result = tf; |
160 | } |
161 | else if (inheritsched1 != inheritsched2) |
162 | { |
163 | error (status: 0, errnum: 0, format: "inheritsched differs %d != %d" , |
164 | inheritsched1, inheritsched2); |
165 | result = tf; |
166 | } |
167 | } |
168 | |
169 | cpu_set_t c1, c2; |
170 | err = pthread_getaffinity_np (th: pthread_self (), cpusetsize: sizeof (c1), cpuset: &c1); |
171 | if (err == 0) |
172 | { |
173 | err = pthread_attr_getaffinity_np (attr: &a, cpusetsize: sizeof (c2), cpuset: &c2); |
174 | if (err) |
175 | { |
176 | error (status: 0, errnum: err, format: "pthread_attr_getaffinity_np failed" ); |
177 | result = tf; |
178 | } |
179 | else if (memcmp (&c1, &c2, sizeof (c1))) |
180 | { |
181 | error (status: 0, errnum: 0, format: "pthread_attr_getaffinity_np returned different CPU mask than pthread_getattr_np" ); |
182 | result = tf; |
183 | } |
184 | } |
185 | |
186 | err = pthread_attr_destroy (attr: &a); |
187 | if (err) |
188 | { |
189 | error (status: 0, errnum: err, format: "pthread_attr_destroy failed" ); |
190 | result = tf; |
191 | } |
192 | |
193 | if (ap == &a2) |
194 | { |
195 | err = pthread_attr_destroy (attr: ap); |
196 | if (err) |
197 | { |
198 | error (status: 0, errnum: err, format: "pthread_attr_destroy failed" ); |
199 | result = tf; |
200 | } |
201 | } |
202 | |
203 | return result; |
204 | } |
205 | |
206 | |
207 | static int |
208 | do_test (void) |
209 | { |
210 | int result = 0; |
211 | pthread_attr_t a; |
212 | cpu_set_t c1, c2; |
213 | |
214 | int err = pthread_attr_init (attr: &a); |
215 | if (err) |
216 | { |
217 | error (status: 0, errnum: err, format: "pthread_attr_init failed" ); |
218 | result = 1; |
219 | } |
220 | |
221 | err = pthread_attr_getaffinity_np (attr: &a, cpusetsize: sizeof (c1), cpuset: &c1); |
222 | if (err && err != ENOSYS) |
223 | { |
224 | error (status: 0, errnum: err, format: "pthread_attr_getaffinity_np failed" ); |
225 | result = 1; |
226 | } |
227 | |
228 | err = pthread_attr_destroy (attr: &a); |
229 | if (err) |
230 | { |
231 | error (status: 0, errnum: err, format: "pthread_attr_destroy failed" ); |
232 | result = 1; |
233 | } |
234 | |
235 | err = pthread_getattr_np (th: pthread_self (), attr: &a); |
236 | if (err) |
237 | { |
238 | error (status: 0, errnum: err, format: "pthread_getattr_np failed" ); |
239 | result = 1; |
240 | } |
241 | |
242 | int detachstate; |
243 | err = pthread_attr_getdetachstate (attr: &a, detachstate: &detachstate); |
244 | if (err) |
245 | { |
246 | error (status: 0, errnum: err, format: "pthread_attr_getdetachstate failed" ); |
247 | result = 1; |
248 | } |
249 | else if (detachstate != PTHREAD_CREATE_JOINABLE) |
250 | { |
251 | error (status: 0, errnum: 0, format: "initial thread not joinable" ); |
252 | result = 1; |
253 | } |
254 | |
255 | void *stackaddr; |
256 | size_t stacksize; |
257 | err = pthread_attr_getstack (attr: &a, stackaddr: &stackaddr, stacksize: &stacksize); |
258 | if (err) |
259 | { |
260 | error (status: 0, errnum: err, format: "pthread_attr_getstack failed" ); |
261 | result = 1; |
262 | } |
263 | else if ((void *) &a < stackaddr |
264 | || (void *) &a >= stackaddr + stacksize) |
265 | { |
266 | error (status: 0, errnum: 0, format: "pthread_attr_getstack returned range does not cover main's stack" ); |
267 | result = 1; |
268 | } |
269 | else |
270 | printf (format: "initial thread stack %p-%p (0x%zx)\n" , stackaddr, |
271 | stackaddr + stacksize, stacksize); |
272 | |
273 | size_t guardsize; |
274 | err = pthread_attr_getguardsize (attr: &a, guardsize: &guardsize); |
275 | if (err) |
276 | { |
277 | error (status: 0, errnum: err, format: "pthread_attr_getguardsize failed" ); |
278 | result = 1; |
279 | } |
280 | else if (guardsize != 0) |
281 | { |
282 | error (status: 0, errnum: 0, format: "pthread_attr_getguardsize returned %zd != 0" , |
283 | guardsize); |
284 | result = 1; |
285 | } |
286 | |
287 | int scope; |
288 | err = pthread_attr_getscope (attr: &a, scope: &scope); |
289 | if (err) |
290 | { |
291 | error (status: 0, errnum: err, format: "pthread_attr_getscope failed" ); |
292 | result = 1; |
293 | } |
294 | else if (scope != PTHREAD_SCOPE_SYSTEM) |
295 | { |
296 | error (status: 0, errnum: 0, format: "pthread_attr_getscope returned %d != PTHREAD_SCOPE_SYSTEM" , |
297 | scope); |
298 | result = 1; |
299 | } |
300 | |
301 | int inheritsched; |
302 | err = pthread_attr_getinheritsched (attr: &a, inherit: &inheritsched); |
303 | if (err) |
304 | { |
305 | error (status: 0, errnum: err, format: "pthread_attr_getinheritsched failed" ); |
306 | result = 1; |
307 | } |
308 | else if (inheritsched != PTHREAD_INHERIT_SCHED) |
309 | { |
310 | error (status: 0, errnum: 0, format: "pthread_attr_getinheritsched returned %d != PTHREAD_INHERIT_SCHED" , |
311 | inheritsched); |
312 | result = 1; |
313 | } |
314 | |
315 | err = pthread_getaffinity_np (th: pthread_self (), cpusetsize: sizeof (c1), cpuset: &c1); |
316 | if (err == 0) |
317 | { |
318 | err = pthread_attr_getaffinity_np (attr: &a, cpusetsize: sizeof (c2), cpuset: &c2); |
319 | if (err) |
320 | { |
321 | error (status: 0, errnum: err, format: "pthread_attr_getaffinity_np failed" ); |
322 | result = 1; |
323 | } |
324 | else if (memcmp (&c1, &c2, sizeof (c1))) |
325 | { |
326 | error (status: 0, errnum: 0, format: "pthread_attr_getaffinity_np returned different CPU mask than pthread_getattr_np" ); |
327 | result = 1; |
328 | } |
329 | } |
330 | |
331 | err = pthread_attr_destroy (attr: &a); |
332 | if (err) |
333 | { |
334 | error (status: 0, errnum: err, format: "pthread_attr_destroy failed" ); |
335 | result = 1; |
336 | } |
337 | |
338 | pthread_t th; |
339 | err = pthread_create (newthread: &th, NULL, start_routine: tf, NULL); |
340 | if (err) |
341 | { |
342 | error (status: 0, errnum: err, format: "pthread_create #1 failed" ); |
343 | result = 1; |
344 | } |
345 | else |
346 | { |
347 | void *ret; |
348 | err = pthread_join (th: th, thread_return: &ret); |
349 | if (err) |
350 | { |
351 | error (status: 0, errnum: err, format: "pthread_join #1 failed" ); |
352 | result = 1; |
353 | } |
354 | else if (ret != NULL) |
355 | result = 1; |
356 | } |
357 | |
358 | err = pthread_attr_init (attr: &a); |
359 | if (err) |
360 | { |
361 | error (status: 0, errnum: err, format: "pthread_attr_init failed" ); |
362 | result = 1; |
363 | } |
364 | |
365 | DIAG_PUSH_NEEDS_COMMENT; |
366 | #if __GNUC_PREREQ (7, 0) |
367 | /* GCC 8 warns about aliasing of the restrict-qualified arguments |
368 | passed &a. Since pthread_create does not dereference its fourth |
369 | argument, this aliasing, which is deliberate in this test, cannot |
370 | in fact cause problems. */ |
371 | DIAG_IGNORE_NEEDS_COMMENT (8, "-Wrestrict" ); |
372 | #endif |
373 | err = pthread_create (newthread: &th, attr: &a, start_routine: tf, arg: &a); |
374 | DIAG_POP_NEEDS_COMMENT; |
375 | if (err) |
376 | { |
377 | error (status: 0, errnum: err, format: "pthread_create #2 failed" ); |
378 | result = 1; |
379 | } |
380 | else |
381 | { |
382 | void *ret; |
383 | err = pthread_join (th: th, thread_return: &ret); |
384 | if (err) |
385 | { |
386 | error (status: 0, errnum: err, format: "pthread_join #2 failed" ); |
387 | result = 1; |
388 | } |
389 | else if (ret != NULL) |
390 | result = 1; |
391 | } |
392 | |
393 | err = pthread_attr_setguardsize (attr: &a, guardsize: 16 * sysconf (_SC_PAGESIZE)); |
394 | if (err) |
395 | { |
396 | error (status: 0, errnum: err, format: "pthread_attr_setguardsize failed" ); |
397 | result = 1; |
398 | } |
399 | |
400 | DIAG_PUSH_NEEDS_COMMENT; |
401 | #if __GNUC_PREREQ (7, 0) |
402 | /* GCC 8 warns about aliasing of the restrict-qualified arguments |
403 | passed &a. Since pthread_create does not dereference its fourth |
404 | argument, this aliasing, which is deliberate in this test, cannot |
405 | in fact cause problems. */ |
406 | DIAG_IGNORE_NEEDS_COMMENT (8, "-Wrestrict" ); |
407 | #endif |
408 | err = pthread_create (newthread: &th, attr: &a, start_routine: tf, arg: &a); |
409 | DIAG_POP_NEEDS_COMMENT; |
410 | if (err) |
411 | { |
412 | error (status: 0, errnum: err, format: "pthread_create #3 failed" ); |
413 | result = 1; |
414 | } |
415 | else |
416 | { |
417 | void *ret; |
418 | err = pthread_join (th: th, thread_return: &ret); |
419 | if (err) |
420 | { |
421 | error (status: 0, errnum: err, format: "pthread_join #3 failed" ); |
422 | result = 1; |
423 | } |
424 | else if (ret != NULL) |
425 | result = 1; |
426 | } |
427 | |
428 | err = pthread_attr_destroy (attr: &a); |
429 | if (err) |
430 | { |
431 | error (status: 0, errnum: err, format: "pthread_attr_destroy failed" ); |
432 | result = 1; |
433 | } |
434 | |
435 | return result; |
436 | } |
437 | |
438 | #define TEST_FUNCTION do_test () |
439 | #include "../test-skeleton.c" |
440 | |