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