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 *
tf(void * arg)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)
42 	{
43 	  error (0, err, "pthread_attr_init failed");
44 	  return tf;
45 	}
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     }
94   else
95     printf ("thread stack %p-%p (0x%zx)\n", stackaddr, stackaddr + stacksize,
96 	    stacksize);
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 	}
119       else
120 	printf ("thread guardsize %zd\n", guardsize1);
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;
170   err = pthread_getaffinity_np (pthread_self (), sizeof (c1), &c1);
171   if (err == 0)
172     {
173       err = pthread_attr_getaffinity_np (&a, sizeof (c2), &c2);
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
do_test(void)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 
221   err = pthread_attr_getaffinity_np (&a, sizeof (c1), &c1);
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     }
269   else
270     printf ("initial thread stack %p-%p (0x%zx)\n", stackaddr,
271 	    stackaddr + stacksize, stacksize);
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 
315   err = pthread_getaffinity_np (pthread_self (), sizeof (c1), &c1);
316   if (err == 0)
317     {
318       err = pthread_attr_getaffinity_np (&a, sizeof (c2), &c2);
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)
355 	result = 1;
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 
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 (&th, &a, tf, &a);
374   DIAG_POP_NEEDS_COMMENT;
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)
390 	result = 1;
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 
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 (&th, &a, tf, &a);
409   DIAG_POP_NEEDS_COMMENT;
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)
425 	result = 1;
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"
440