]>
Commit | Line | Data |
---|---|---|
06f6ca90 | 1 | /* pthread_getattr_np test. |
dff8da6b | 2 | Copyright (C) 2003-2024 Free Software Foundation, Inc. |
06f6ca90 | 3 | This file is part of the GNU C Library. |
06f6ca90 UD |
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 | |
59ba27a6 | 16 | License along with the GNU C Library; if not, see |
5a82c748 | 17 | <https://www.gnu.org/licenses/>. */ |
06f6ca90 UD |
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> | |
40c4162d | 28 | #include <libc-diag.h> |
06f6ca90 UD |
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 (ap); | |
41 | if (err) | |
bcad1181 UD |
42 | { |
43 | error (0, err, "pthread_attr_init failed"); | |
44 | return tf; | |
45 | } | |
06f6ca90 UD |
46 | } |
47 | else | |
48 | ap = (pthread_attr_t *) arg; | |
49 | ||
50 | err = pthread_getattr_np (pthread_self (), &a); | |
51 | if (err) | |
52 | { | |
53 | error (0, err, "pthread_getattr_np failed"); | |
54 | result = tf; | |
55 | } | |
56 | ||
57 | int detachstate1, detachstate2; | |
58 | err = pthread_attr_getdetachstate (&a, &detachstate1); | |
59 | if (err) | |
60 | { | |
61 | error (0, err, "pthread_attr_getdetachstate failed"); | |
62 | result = tf; | |
63 | } | |
64 | else | |
65 | { | |
66 | err = pthread_attr_getdetachstate (ap, &detachstate2); | |
67 | if (err) | |
68 | { | |
69 | error (0, err, "pthread_attr_getdetachstate failed"); | |
70 | result = tf; | |
71 | } | |
72 | else if (detachstate1 != detachstate2) | |
73 | { | |
74 | error (0, 0, "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 (&a, &stackaddr, &stacksize); | |
83 | if (err) | |
84 | { | |
85 | error (0, err, "pthread_attr_getstack failed"); | |
86 | result = tf; | |
87 | } | |
88 | else if ((void *) &a < stackaddr | |
89 | || (void *) &a >= stackaddr + stacksize) | |
90 | { | |
91 | error (0, 0, "pthread_attr_getstack returned range does not cover thread's stack"); | |
92 | result = tf; | |
93 | } | |
8b8074da UD |
94 | else |
95 | printf ("thread stack %p-%p (0x%zx)\n", stackaddr, stackaddr + stacksize, | |
96 | stacksize); | |
06f6ca90 UD |
97 | |
98 | size_t guardsize1, guardsize2; | |
99 | err = pthread_attr_getguardsize (&a, &guardsize1); | |
100 | if (err) | |
101 | { | |
102 | error (0, err, "pthread_attr_getguardsize failed"); | |
103 | result = tf; | |
104 | } | |
105 | else | |
106 | { | |
107 | err = pthread_attr_getguardsize (ap, &guardsize2); | |
108 | if (err) | |
109 | { | |
110 | error (0, err, "pthread_attr_getguardsize failed"); | |
111 | result = tf; | |
112 | } | |
113 | else if (guardsize1 != guardsize2) | |
114 | { | |
115 | error (0, 0, "guardsize differs %zd != %zd", | |
116 | guardsize1, guardsize2); | |
117 | result = tf; | |
118 | } | |
8b8074da UD |
119 | else |
120 | printf ("thread guardsize %zd\n", guardsize1); | |
06f6ca90 UD |
121 | } |
122 | ||
123 | int scope1, scope2; | |
124 | err = pthread_attr_getscope (&a, &scope1); | |
125 | if (err) | |
126 | { | |
127 | error (0, err, "pthread_attr_getscope failed"); | |
128 | result = tf; | |
129 | } | |
130 | else | |
131 | { | |
132 | err = pthread_attr_getscope (ap, &scope2); | |
133 | if (err) | |
134 | { | |
135 | error (0, err, "pthread_attr_getscope failed"); | |
136 | result = tf; | |
137 | } | |
138 | else if (scope1 != scope2) | |
139 | { | |
140 | error (0, 0, "scope differs %d != %d", | |
141 | scope1, scope2); | |
142 | result = tf; | |
143 | } | |
144 | } | |
145 | ||
146 | int inheritsched1, inheritsched2; | |
147 | err = pthread_attr_getinheritsched (&a, &inheritsched1); | |
148 | if (err) | |
149 | { | |
150 | error (0, err, "pthread_attr_getinheritsched failed"); | |
151 | result = tf; | |
152 | } | |
153 | else | |
154 | { | |
155 | err = pthread_attr_getinheritsched (ap, &inheritsched2); | |
156 | if (err) | |
157 | { | |
158 | error (0, err, "pthread_attr_getinheritsched failed"); | |
159 | result = tf; | |
160 | } | |
161 | else if (inheritsched1 != inheritsched2) | |
162 | { | |
163 | error (0, 0, "inheritsched differs %d != %d", | |
164 | inheritsched1, inheritsched2); | |
165 | result = tf; | |
166 | } | |
167 | } | |
168 | ||
169 | cpu_set_t c1, c2; | |
439ff07b | 170 | err = pthread_getaffinity_np (pthread_self (), sizeof (c1), &c1); |
06f6ca90 UD |
171 | if (err == 0) |
172 | { | |
439ff07b | 173 | err = pthread_attr_getaffinity_np (&a, sizeof (c2), &c2); |
06f6ca90 UD |
174 | if (err) |
175 | { | |
176 | error (0, err, "pthread_attr_getaffinity_np failed"); | |
177 | result = tf; | |
178 | } | |
179 | else if (memcmp (&c1, &c2, sizeof (c1))) | |
180 | { | |
181 | error (0, 0, "pthread_attr_getaffinity_np returned different CPU mask than pthread_getattr_np"); | |
182 | result = tf; | |
183 | } | |
184 | } | |
185 | ||
186 | err = pthread_attr_destroy (&a); | |
187 | if (err) | |
188 | { | |
189 | error (0, err, "pthread_attr_destroy failed"); | |
190 | result = tf; | |
191 | } | |
192 | ||
193 | if (ap == &a2) | |
194 | { | |
195 | err = pthread_attr_destroy (ap); | |
196 | if (err) | |
197 | { | |
198 | error (0, err, "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 (&a); | |
215 | if (err) | |
216 | { | |
217 | error (0, err, "pthread_attr_init failed"); | |
218 | result = 1; | |
219 | } | |
220 | ||
439ff07b | 221 | err = pthread_attr_getaffinity_np (&a, sizeof (c1), &c1); |
06f6ca90 UD |
222 | if (err && err != ENOSYS) |
223 | { | |
224 | error (0, err, "pthread_attr_getaffinity_np failed"); | |
225 | result = 1; | |
226 | } | |
227 | ||
228 | err = pthread_attr_destroy (&a); | |
229 | if (err) | |
230 | { | |
231 | error (0, err, "pthread_attr_destroy failed"); | |
232 | result = 1; | |
233 | } | |
234 | ||
235 | err = pthread_getattr_np (pthread_self (), &a); | |
236 | if (err) | |
237 | { | |
238 | error (0, err, "pthread_getattr_np failed"); | |
239 | result = 1; | |
240 | } | |
241 | ||
242 | int detachstate; | |
243 | err = pthread_attr_getdetachstate (&a, &detachstate); | |
244 | if (err) | |
245 | { | |
246 | error (0, err, "pthread_attr_getdetachstate failed"); | |
247 | result = 1; | |
248 | } | |
249 | else if (detachstate != PTHREAD_CREATE_JOINABLE) | |
250 | { | |
251 | error (0, 0, "initial thread not joinable"); | |
252 | result = 1; | |
253 | } | |
254 | ||
255 | void *stackaddr; | |
256 | size_t stacksize; | |
257 | err = pthread_attr_getstack (&a, &stackaddr, &stacksize); | |
258 | if (err) | |
259 | { | |
260 | error (0, err, "pthread_attr_getstack failed"); | |
261 | result = 1; | |
262 | } | |
263 | else if ((void *) &a < stackaddr | |
264 | || (void *) &a >= stackaddr + stacksize) | |
265 | { | |
266 | error (0, 0, "pthread_attr_getstack returned range does not cover main's stack"); | |
267 | result = 1; | |
268 | } | |
8b8074da UD |
269 | else |
270 | printf ("initial thread stack %p-%p (0x%zx)\n", stackaddr, | |
271 | stackaddr + stacksize, stacksize); | |
06f6ca90 UD |
272 | |
273 | size_t guardsize; | |
274 | err = pthread_attr_getguardsize (&a, &guardsize); | |
275 | if (err) | |
276 | { | |
277 | error (0, err, "pthread_attr_getguardsize failed"); | |
278 | result = 1; | |
279 | } | |
280 | else if (guardsize != 0) | |
281 | { | |
282 | error (0, 0, "pthread_attr_getguardsize returned %zd != 0", | |
283 | guardsize); | |
284 | result = 1; | |
285 | } | |
286 | ||
287 | int scope; | |
288 | err = pthread_attr_getscope (&a, &scope); | |
289 | if (err) | |
290 | { | |
291 | error (0, err, "pthread_attr_getscope failed"); | |
292 | result = 1; | |
293 | } | |
294 | else if (scope != PTHREAD_SCOPE_SYSTEM) | |
295 | { | |
296 | error (0, 0, "pthread_attr_getscope returned %d != PTHREAD_SCOPE_SYSTEM", | |
297 | scope); | |
298 | result = 1; | |
299 | } | |
300 | ||
301 | int inheritsched; | |
302 | err = pthread_attr_getinheritsched (&a, &inheritsched); | |
303 | if (err) | |
304 | { | |
305 | error (0, err, "pthread_attr_getinheritsched failed"); | |
306 | result = 1; | |
307 | } | |
308 | else if (inheritsched != PTHREAD_INHERIT_SCHED) | |
309 | { | |
310 | error (0, 0, "pthread_attr_getinheritsched returned %d != PTHREAD_INHERIT_SCHED", | |
311 | inheritsched); | |
312 | result = 1; | |
313 | } | |
314 | ||
439ff07b | 315 | err = pthread_getaffinity_np (pthread_self (), sizeof (c1), &c1); |
06f6ca90 UD |
316 | if (err == 0) |
317 | { | |
439ff07b | 318 | err = pthread_attr_getaffinity_np (&a, sizeof (c2), &c2); |
06f6ca90 UD |
319 | if (err) |
320 | { | |
321 | error (0, err, "pthread_attr_getaffinity_np failed"); | |
322 | result = 1; | |
323 | } | |
324 | else if (memcmp (&c1, &c2, sizeof (c1))) | |
325 | { | |
326 | error (0, 0, "pthread_attr_getaffinity_np returned different CPU mask than pthread_getattr_np"); | |
327 | result = 1; | |
328 | } | |
329 | } | |
330 | ||
331 | err = pthread_attr_destroy (&a); | |
332 | if (err) | |
333 | { | |
334 | error (0, err, "pthread_attr_destroy failed"); | |
335 | result = 1; | |
336 | } | |
337 | ||
338 | pthread_t th; | |
339 | err = pthread_create (&th, NULL, tf, NULL); | |
340 | if (err) | |
341 | { | |
342 | error (0, err, "pthread_create #1 failed"); | |
343 | result = 1; | |
344 | } | |
345 | else | |
346 | { | |
347 | void *ret; | |
348 | err = pthread_join (th, &ret); | |
349 | if (err) | |
350 | { | |
351 | error (0, err, "pthread_join #1 failed"); | |
352 | result = 1; | |
353 | } | |
354 | else if (ret != NULL) | |
bcad1181 | 355 | result = 1; |
06f6ca90 UD |
356 | } |
357 | ||
358 | err = pthread_attr_init (&a); | |
359 | if (err) | |
360 | { | |
361 | error (0, err, "pthread_attr_init failed"); | |
362 | result = 1; | |
363 | } | |
364 | ||
40c4162d JM |
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 | |
06f6ca90 | 373 | err = pthread_create (&th, &a, tf, &a); |
40c4162d | 374 | DIAG_POP_NEEDS_COMMENT; |
06f6ca90 UD |
375 | if (err) |
376 | { | |
377 | error (0, err, "pthread_create #2 failed"); | |
378 | result = 1; | |
379 | } | |
380 | else | |
381 | { | |
382 | void *ret; | |
383 | err = pthread_join (th, &ret); | |
384 | if (err) | |
385 | { | |
386 | error (0, err, "pthread_join #2 failed"); | |
387 | result = 1; | |
388 | } | |
389 | else if (ret != NULL) | |
bcad1181 | 390 | result = 1; |
06f6ca90 UD |
391 | } |
392 | ||
393 | err = pthread_attr_setguardsize (&a, 16 * sysconf (_SC_PAGESIZE)); | |
394 | if (err) | |
395 | { | |
396 | error (0, err, "pthread_attr_setguardsize failed"); | |
397 | result = 1; | |
398 | } | |
399 | ||
40c4162d JM |
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 | |
06f6ca90 | 408 | err = pthread_create (&th, &a, tf, &a); |
40c4162d | 409 | DIAG_POP_NEEDS_COMMENT; |
06f6ca90 UD |
410 | if (err) |
411 | { | |
412 | error (0, err, "pthread_create #3 failed"); | |
413 | result = 1; | |
414 | } | |
415 | else | |
416 | { | |
417 | void *ret; | |
418 | err = pthread_join (th, &ret); | |
419 | if (err) | |
420 | { | |
421 | error (0, err, "pthread_join #3 failed"); | |
422 | result = 1; | |
423 | } | |
424 | else if (ret != NULL) | |
bcad1181 | 425 | result = 1; |
06f6ca90 UD |
426 | } |
427 | ||
428 | err = pthread_attr_destroy (&a); | |
429 | if (err) | |
430 | { | |
431 | error (0, err, "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" |