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