1 /* Linuxthreads - a simple clone()-based implementation of Posix        */
2 /* threads for Linux.                                                   */
3 /* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr)              */
4 /*                                                                      */
5 /* This program is free software; you can redistribute it and/or        */
6 /* modify it under the terms of the GNU Library General Public License  */
7 /* as published by the Free Software Foundation; either version 2       */
8 /* of the License, or (at your option) any later version.               */
9 /*                                                                      */
10 /* This program 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        */
13 /* GNU Library General Public License for more details.                 */
14 
15 /* Handling of thread attributes */
16 
17 #include <errno.h>
18 #include <inttypes.h>
19 #include <stdio.h>
20 #include <stdio_ext.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <sys/param.h>
25 #include <sys/resource.h>
26 #include "pthread.h"
27 #include "internals.h"
28 
29 
30 #define __sched_get_priority_max(x) (L4_SCHED_MAX_PRIO)
31 #define __sched_get_priority_min(x) (1)
32 
33 int
34 attribute_hidden
__pthread_attr_init(pthread_attr_t * attr)35 __pthread_attr_init(pthread_attr_t *attr)
36 {
37   size_t ps = L4_PAGESIZE;
38 
39   attr->__detachstate = PTHREAD_CREATE_JOINABLE;
40   attr->__schedpolicy = SCHED_OTHER;
41   attr->__schedparam.sched_priority = 0;
42   attr->__inheritsched = PTHREAD_INHERIT_SCHED;
43   attr->__scope = PTHREAD_SCOPE_SYSTEM;
44 #ifdef NEED_SEPARATE_REGISTER_STACK
45   attr->__guardsize = ps + ps;
46 #else
47   attr->__guardsize = ps;
48 #endif
49   attr->__stackaddr = NULL;
50   attr->__stackaddr_set = 0;
51   attr->__stacksize = STACK_SIZE - ps;
52 
53   // L4 specifics
54   attr->affinity = l4_sched_cpu_set(0, ~0, 1);
55   attr->create_flags = 0;
56   return 0;
57 }
strong_alias(__pthread_attr_init,pthread_attr_init)58 strong_alias (__pthread_attr_init, pthread_attr_init)
59 
60 int
61 attribute_hidden
62 __pthread_attr_destroy(pthread_attr_t *attr)
63 {
64   return 0;
65 }
strong_alias(__pthread_attr_destroy,pthread_attr_destroy)66 strong_alias (__pthread_attr_destroy, pthread_attr_destroy)
67 
68 int
69 attribute_hidden
70 __pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
71 {
72   if (detachstate < PTHREAD_CREATE_JOINABLE ||
73       detachstate > PTHREAD_CREATE_DETACHED)
74     return EINVAL;
75   attr->__detachstate = detachstate;
76   return 0;
77 }
strong_alias(__pthread_attr_setdetachstate,pthread_attr_setdetachstate)78 strong_alias (__pthread_attr_setdetachstate, pthread_attr_setdetachstate)
79 
80 int
81 attribute_hidden
82 __pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
83 {
84   *detachstate = attr->__detachstate;
85   return 0;
86 }
strong_alias(__pthread_attr_getdetachstate,pthread_attr_getdetachstate)87 strong_alias (__pthread_attr_getdetachstate, pthread_attr_getdetachstate)
88 
89 int
90 attribute_hidden
91 __pthread_attr_setschedparam(pthread_attr_t *attr,
92                                  const struct sched_param *param)
93 {
94   int max_prio = __sched_get_priority_max(attr->__schedpolicy);
95   int min_prio = __sched_get_priority_min(attr->__schedpolicy);
96 
97   if (param->sched_priority < min_prio || param->sched_priority > max_prio)
98     return EINVAL;
99   memcpy (&attr->__schedparam, param, sizeof (struct sched_param));
100   return 0;
101 }
strong_alias(__pthread_attr_setschedparam,pthread_attr_setschedparam)102 strong_alias (__pthread_attr_setschedparam, pthread_attr_setschedparam)
103 
104 int
105 attribute_hidden
106 __pthread_attr_getschedparam(const pthread_attr_t *attr,
107                                  struct sched_param *param)
108 {
109   memcpy (param, &attr->__schedparam, sizeof (struct sched_param));
110   return 0;
111 }
strong_alias(__pthread_attr_getschedparam,pthread_attr_getschedparam)112 strong_alias (__pthread_attr_getschedparam, pthread_attr_getschedparam)
113 
114 int
115 attribute_hidden
116 __pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
117 {
118   if (policy != SCHED_OTHER && policy != SCHED_FIFO && policy != SCHED_RR
119       && policy != SCHED_L4)
120     return EINVAL;
121   attr->__schedpolicy = policy;
122   return 0;
123 }
strong_alias(__pthread_attr_setschedpolicy,pthread_attr_setschedpolicy)124 strong_alias (__pthread_attr_setschedpolicy, pthread_attr_setschedpolicy)
125 
126 int
127 attribute_hidden
128 __pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
129 {
130   *policy = attr->__schedpolicy;
131   return 0;
132 }
strong_alias(__pthread_attr_getschedpolicy,pthread_attr_getschedpolicy)133 strong_alias (__pthread_attr_getschedpolicy, pthread_attr_getschedpolicy)
134 
135 int
136 attribute_hidden
137 __pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit)
138 {
139   if (inherit != PTHREAD_INHERIT_SCHED && inherit != PTHREAD_EXPLICIT_SCHED)
140     return EINVAL;
141   attr->__inheritsched = inherit;
142   return 0;
143 }
strong_alias(__pthread_attr_setinheritsched,pthread_attr_setinheritsched)144 strong_alias (__pthread_attr_setinheritsched, pthread_attr_setinheritsched)
145 
146 int
147 attribute_hidden
148 __pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inherit)
149 {
150   *inherit = attr->__inheritsched;
151   return 0;
152 }
strong_alias(__pthread_attr_getinheritsched,pthread_attr_getinheritsched)153 strong_alias (__pthread_attr_getinheritsched, pthread_attr_getinheritsched)
154 
155 int
156 attribute_hidden
157 __pthread_attr_setscope(pthread_attr_t *attr, int scope)
158 {
159   switch (scope) {
160   case PTHREAD_SCOPE_SYSTEM:
161     attr->__scope = scope;
162     return 0;
163   case PTHREAD_SCOPE_PROCESS:
164     return ENOTSUP;
165   default:
166     return EINVAL;
167   }
168 }
strong_alias(__pthread_attr_setscope,pthread_attr_setscope)169 strong_alias (__pthread_attr_setscope, pthread_attr_setscope)
170 
171 int
172 attribute_hidden
173 __pthread_attr_getscope(const pthread_attr_t *attr, int *scope)
174 {
175   *scope = attr->__scope;
176   return 0;
177 }
strong_alias(__pthread_attr_getscope,pthread_attr_getscope)178 strong_alias (__pthread_attr_getscope, pthread_attr_getscope)
179 
180 int
181 attribute_hidden
182 __pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize)
183 {
184   /* The guard size must not be larger than the stack itself */
185   if (guardsize >= attr->__stacksize) return EINVAL;
186 
187   attr->__guardsize = guardsize;
188 
189   return 0;
190 }
weak_alias(__pthread_attr_setguardsize,pthread_attr_setguardsize)191 weak_alias (__pthread_attr_setguardsize, pthread_attr_setguardsize)
192 
193 int
194 attribute_hidden
195 __pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize)
196 {
197   *guardsize = attr->__guardsize;
198   return 0;
199 }
weak_alias(__pthread_attr_getguardsize,pthread_attr_getguardsize)200 weak_alias (__pthread_attr_getguardsize, pthread_attr_getguardsize)
201 
202 #if 0 /* uClibc: deprecated stuff disabled */
203 int __pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr)
204 {
205   attr->__stackaddr = stackaddr;
206   attr->__stackaddr_set = 1;
207   return 0;
208 }
209 weak_alias (__pthread_attr_setstackaddr, pthread_attr_setstackaddr)
210 
211 link_warning (pthread_attr_setstackaddr,
212 	      "the use of `pthread_attr_setstackaddr' is deprecated, use `pthread_attr_setstack'")
213 
214 int __pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr)
215 {
216   /* XXX This function has a stupid definition.  The standard specifies
217      no error value but what is if no stack address was set?  We simply
218      return the value we have in the member.  */
219   *stackaddr = attr->__stackaddr;
220   return 0;
221 }
222 weak_alias (__pthread_attr_getstackaddr, pthread_attr_getstackaddr)
223 
224 link_warning (pthread_attr_getstackaddr,
225 	      "the use of `pthread_attr_getstackaddr' is deprecated, use `pthread_attr_getstack'")
226 #endif
227 
228 
229 int
230 attribute_hidden
231 __pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
232 {
233   /* We have to check against the maximum allowed stack size.  This is no
234      problem if the manager is already started and we determined it.  If
235      this hasn't happened, we have to find the limit outself.  */
236   if (__pthread_max_stacksize == 0)
237     __pthread_init_max_stacksize ();
238 
239   if (stacksize > __pthread_max_stacksize)
240     return EINVAL;
241 
242   /* We don't accept value smaller than PTHREAD_STACK_MIN.  */
243   if (stacksize < PTHREAD_STACK_MIN)
244     return EINVAL;
245 
246   attr->__stacksize = stacksize;
247   return 0;
248 }
249 
250 #if PTHREAD_STACK_MIN == 16384 || defined __UCLIBC__
weak_alias(__pthread_attr_setstacksize,pthread_attr_setstacksize)251 weak_alias (__pthread_attr_setstacksize, pthread_attr_setstacksize)
252 #else
253 versioned_symbol (libpthread, __pthread_attr_setstacksize,
254                   pthread_attr_setstacksize, GLIBC_2_3_3);
255 
256 # if SHLIB_COMPAT(libpthread, GLIBC_2_1, GLIBC_2_3_3)
257 
258 int
259 attribute_hidden
260 __old_pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
261 {
262   /* We have to check against the maximum allowed stack size.  This is no
263      problem if the manager is already started and we determined it.  If
264      this hasn't happened, we have to find the limit outself.  */
265   if (__pthread_max_stacksize == 0)
266     __pthread_init_max_stacksize ();
267 
268   if (stacksize > __pthread_max_stacksize)
269     return EINVAL;
270 
271   /* We don't accept value smaller than old PTHREAD_STACK_MIN.  */
272   if (stacksize < 16384)
273     return EINVAL;
274 
275   attr->__stacksize = stacksize;
276   return 0;
277 }
278 compat_symbol (libpthread, __old_pthread_attr_setstacksize,
279 	       pthread_attr_setstacksize, GLIBC_2_1);
280 # endif
281 #endif
282 
283 
284 int
285 attribute_hidden
286 __pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize)
287 {
288   *stacksize = attr->__stacksize;
289   return 0;
290 }
weak_alias(__pthread_attr_getstacksize,pthread_attr_getstacksize)291 weak_alias (__pthread_attr_getstacksize, pthread_attr_getstacksize)
292 
293 int
294 attribute_hidden
295 __pthread_attr_setstack (pthread_attr_t *attr, void *stackaddr,
296 			     size_t stacksize)
297 {
298   int err;
299 
300   if ((((uintptr_t) stackaddr)
301        & (__alignof__ (struct pthread) - 1)) != 0)
302     err = EINVAL;
303   else
304     err = __pthread_attr_setstacksize (attr, stacksize);
305   if (err == 0)
306     {
307 #ifndef _STACK_GROWS_UP
308       attr->__stackaddr = (char *) stackaddr + stacksize;
309 #else
310       attr->__stackaddr = stackaddr;
311 #endif
312       attr->__stackaddr_set = 1;
313     }
314 
315   return err;
316 }
317 
318 #if PTHREAD_STACK_MIN == 16384 || defined __UCLIBC__
weak_alias(__pthread_attr_setstack,pthread_attr_setstack)319 weak_alias (__pthread_attr_setstack, pthread_attr_setstack)
320 #else
321 versioned_symbol (libpthread, __pthread_attr_setstack, pthread_attr_setstack,
322                   GLIBC_2_3_3);
323 # if SHLIB_COMPAT(libpthread, GLIBC_2_2, GLIBC_2_3_3)
324 int
325 attribute_hidden
326 __old_pthread_attr_setstack (pthread_attr_t *attr, void *stackaddr,
327 				 size_t stacksize)
328 {
329   int err;
330 
331   if ((((uintptr_t) stackaddr)
332        & (__alignof__ (struct pthread) - 1)) != 0)
333     err = EINVAL;
334   else
335     err = __old_pthread_attr_setstacksize (attr, stacksize);
336   if (err == 0)
337     {
338 #  ifndef _STACK_GROWS_UP
339       attr->__stackaddr = (char *) stackaddr + stacksize;
340 #  else
341       attr->__stackaddr = stackaddr;
342 #  endif
343       attr->__stackaddr_set = 1;
344     }
345 
346   return err;
347 }
348 
349 compat_symbol (libpthread, __old_pthread_attr_setstack, pthread_attr_setstack,
350                GLIBC_2_2);
351 
352 # endif
353 #endif
354 
355 int
356 attribute_hidden
357 __pthread_attr_getstack (const pthread_attr_t *attr, void **stackaddr,
358 			     size_t *stacksize)
359 {
360   /* XXX This function has a stupid definition.  The standard specifies
361      no error value but what is if no stack address was set?  We simply
362      return the value we have in the member.  */
363 #ifndef _STACK_GROWS_UP
364   *stackaddr = (char *) attr->__stackaddr - attr->__stacksize;
365 #else
366   *stackaddr = attr->__stackaddr;
367 #endif
368   *stacksize = attr->__stacksize;
369   return 0;
370 }
weak_alias(__pthread_attr_getstack,pthread_attr_getstack)371 weak_alias (__pthread_attr_getstack, pthread_attr_getstack)
372 
373 int pthread_getattr_np (pthread_t thread, pthread_attr_t *attr)
374 {
375   pthread_handle handle = thread_handle (thread);
376   pthread_descr descr;
377 #ifdef NOT_FOR_L4
378   int ret = 0;
379 #endif
380 
381   if (handle == NULL)
382     return ENOENT;
383 
384   descr = handle_to_descr(handle);
385 
386   attr->__detachstate = (descr->p_detached
387 			 ? PTHREAD_CREATE_DETACHED
388 			 : PTHREAD_CREATE_JOINABLE);
389 
390   attr->__schedpolicy = descr->p_sched_policy;
391   if (attr->__schedpolicy == -1)
392     return EINVAL;
393   attr->__schedparam.sched_priority = descr->p_priority;
394 
395   if (attr->__schedparam.sched_priority < 0)
396     return EINVAL;
397 
398   attr->__inheritsched = descr->p_inheritsched;
399   attr->__scope = PTHREAD_SCOPE_SYSTEM;
400 
401 #ifdef _STACK_GROWS_DOWN
402 # ifdef USE_TLS
403   attr->__stacksize = descr->p_stackaddr - (char *)descr->p_guardaddr
404 		      - descr->p_guardsize;
405 # else
406   attr->__stacksize = (char *)(descr + 1) - (char *)descr->p_guardaddr
407 		      - descr->p_guardsize;
408 # endif
409 #else
410 # ifdef USE_TLS
411   attr->__stacksize = (char *)descr->p_guardaddr - descr->p_stackaddr;
412 # else
413   attr->__stacksize = (char *)descr->p_guardaddr - (char *)descr;
414 # endif
415 #endif
416   attr->__guardsize = descr->p_guardsize;
417   attr->__stackaddr_set = descr->p_userstack;
418 #ifdef NEED_SEPARATE_REGISTER_STACK
419   if (descr->p_userstack == 0)
420     attr->__stacksize *= 2;
421   /* XXX This is awkward.  The guard pages are in the middle of the
422      two stacks.  We must count the guard size in the stack size since
423      otherwise the range of the stack area cannot be computed.  */
424   attr->__stacksize += attr->__guardsize;
425 #endif
426 #ifdef USE_TLS
427   attr->__stackaddr = descr->p_stackaddr;
428 #else
429 # ifndef _STACK_GROWS_UP
430   attr->__stackaddr = (char *)(descr + 1);
431 # else
432   attr->__stackaddr = (char *)descr;
433 # endif
434 #endif
435 
436 
437 #ifdef NOT_FOR_L4 // XXX: fix for initial thread
438 #ifdef USE_TLS
439   if (attr->__stackaddr == NULL)
440 #else
441   if (descr == &__pthread_initial_thread)
442 #endif
443     {
444       /* Stack size limit.  */
445       struct rlimit rl;
446 
447       /* The safest way to get the top of the stack is to read
448 	 /proc/self/maps and locate the line into which
449 	 __libc_stack_end falls.  */
450       FILE *fp = fopen ("/proc/self/maps", "rc");
451       if (fp == NULL)
452 	ret = errno;
453       /* We need the limit of the stack in any case.  */
454       else if (getrlimit (RLIMIT_STACK, &rl) != 0)
455 	ret = errno;
456       else
457 	{
458 	  /* We need no locking.  */
459 	  __fsetlocking (fp, FSETLOCKING_BYCALLER);
460 
461 	  /* Until we found an entry (which should always be the case)
462 	     mark the result as a failure.  */
463 	  ret = ENOENT;
464 
465 	  char *line = NULL;
466 	  size_t linelen = 0;
467 	  uintptr_t last_to = 0;
468 
469 	  while (! feof_unlocked (fp))
470 	    {
471 	      if (getdelim (&line, &linelen, '\n', fp) <= 0)
472 		break;
473 
474 	      uintptr_t from;
475 	      uintptr_t to;
476 	      if (sscanf (line, "%" SCNxPTR "-%" SCNxPTR, &from, &to) != 2)
477 		continue;
478 	      if (from <= (uintptr_t) __libc_stack_end
479 		  && (uintptr_t) __libc_stack_end < to)
480 		{
481 		  /* Found the entry.  Now we have the info we need.  */
482 		  attr->__stacksize = rl.rlim_cur;
483 #ifdef _STACK_GROWS_UP
484 		  /* Don't check to enforce a limit on the __stacksize */
485 		  attr->__stackaddr = (void *) from;
486 #else
487 		  attr->__stackaddr = (void *) to;
488 
489 		  /* The limit might be too high.  */
490 		  if ((size_t) attr->__stacksize
491 		      > (size_t) attr->__stackaddr - last_to)
492 		    attr->__stacksize = (size_t) attr->__stackaddr - last_to;
493 #endif
494 
495 		  /* We succeed and no need to look further.  */
496 		  ret = 0;
497 		  break;
498 		}
499 	      last_to = to;
500 	    }
501 
502 	  fclose (fp);
503 	  free (line);
504 	}
505     }
506 #endif
507   return 0;
508 
509 }
510