1 /* Copyright (C) 2002-2023 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, see
16 <https://www.gnu.org/licenses/>. */
22 #include <stdio_ext.h>
25 #include <sys/resource.h>
27 #include <lowlevellock.h>
32 __pthread_getattr_np (pthread_t thread_id
, pthread_attr_t
*attr
)
34 struct pthread
*thread
= (struct pthread
*) thread_id
;
36 /* Prepare the new thread attribute. */
37 int ret
= __pthread_attr_init (attr
);
41 struct pthread_attr
*iattr
= (struct pthread_attr
*) attr
;
43 lll_lock (thread
->lock
, LLL_PRIVATE
);
45 /* The thread library is responsible for keeping the values in the
46 thread desriptor up-to-date in case the user changes them. */
47 memcpy (&iattr
->schedparam
, &thread
->schedparam
,
48 sizeof (struct sched_param
));
49 iattr
->schedpolicy
= thread
->schedpolicy
;
51 /* Clear the flags work. */
52 iattr
->flags
= thread
->flags
;
54 /* The thread might be detached by now. */
55 if (IS_DETACHED (thread
))
56 iattr
->flags
|= ATTR_FLAG_DETACHSTATE
;
58 /* This is the guardsize after adjusting it. */
59 iattr
->guardsize
= thread
->reported_guardsize
;
61 /* The sizes are subject to alignment. */
62 if (__glibc_likely (thread
->stackblock
!= NULL
))
64 /* The stack size reported to the user should not include the
66 iattr
->stacksize
= thread
->stackblock_size
- thread
->guardsize
;
68 iattr
->stackaddr
= (char *) thread
->stackblock
69 + thread
->stackblock_size
;
71 iattr
->stackaddr
= (char *) thread
->stackblock
;
76 /* No stack information available. This must be for the initial
77 thread. Get the info in some magical way. */
79 /* Stack size limit. */
82 /* The safest way to get the top of the stack is to read
83 /proc/self/maps and locate the line into which
84 __libc_stack_end falls. */
85 FILE *fp
= fopen ("/proc/self/maps", "rce");
88 /* We need the limit of the stack in any case. */
91 if (__getrlimit (RLIMIT_STACK
, &rl
) != 0)
95 /* We consider the main process stack to have ended with
96 the page containing __libc_stack_end. There is stuff below
97 it in the stack too, like the program arguments, environment
98 variables and auxv info, but we ignore those pages when
99 returning size so that the output is consistent when the
100 stack is marked executable due to a loaded DSO requiring
102 void *stack_end
= (void *) ((uintptr_t) __libc_stack_end
103 & -(uintptr_t) GLRO(dl_pagesize
));
104 #if _STACK_GROWS_DOWN
105 stack_end
+= GLRO(dl_pagesize
);
107 /* We need no locking. */
108 __fsetlocking (fp
, FSETLOCKING_BYCALLER
);
110 /* Until we found an entry (which should always be the case)
111 mark the result as a failure. */
116 #if _STACK_GROWS_DOWN
117 uintptr_t last_to
= 0;
120 while (! feof_unlocked (fp
))
122 if (__getline (&line
, &linelen
, fp
) <= 0)
127 if (sscanf (line
, "%" SCNxPTR
"-%" SCNxPTR
, &from
, &to
) != 2)
129 if (from
<= (uintptr_t) __libc_stack_end
130 && (uintptr_t) __libc_stack_end
< to
)
132 /* Found the entry. Now we have the info we need. */
133 iattr
->stackaddr
= stack_end
;
135 rl
.rlim_cur
- (size_t) (to
- (uintptr_t) stack_end
);
137 /* Cut it down to align it to page size since otherwise we
138 risk going beyond rlimit when the kernel rounds up the
139 stack extension request. */
140 iattr
->stacksize
= (iattr
->stacksize
141 & -(intptr_t) GLRO(dl_pagesize
));
142 #if _STACK_GROWS_DOWN
143 /* The limit might be too high. */
144 if ((size_t) iattr
->stacksize
145 > (size_t) iattr
->stackaddr
- last_to
)
146 iattr
->stacksize
= (size_t) iattr
->stackaddr
- last_to
;
148 /* The limit might be too high. */
149 if ((size_t) iattr
->stacksize
150 > to
- (size_t) iattr
->stackaddr
)
151 iattr
->stacksize
= to
- (size_t) iattr
->stackaddr
;
153 /* We succeed and no need to look further. */
157 #if _STACK_GROWS_DOWN
169 iattr
->flags
|= ATTR_FLAG_STACKADDR
;
174 cpu_set_t
*cpuset
= NULL
;
180 void *newp
= realloc (cpuset
, size
);
186 cpuset
= (cpu_set_t
*) newp
;
188 ret
= __pthread_getaffinity_np (thread_id
, size
, cpuset
);
190 /* Pick some ridiculous upper limit. Is 8 million CPUs enough? */
191 while (ret
== EINVAL
&& size
< 1024 * 1024);
194 ret
= __pthread_attr_setaffinity_np (attr
, size
, cpuset
);
195 else if (ret
== ENOSYS
)
196 /* There is no such functionality. */
201 lll_unlock (thread
->lock
, LLL_PRIVATE
);
204 __pthread_attr_destroy (attr
);
208 versioned_symbol (libc
, __pthread_getattr_np
, pthread_getattr_np
, GLIBC_2_32
);
210 #if SHLIB_COMPAT (libc, GLIBC_2_2_3, GLIBC_2_32)
211 strong_alias (__pthread_getattr_np
, __pthread_getattr_np_alias
)
212 compat_symbol (libc
, __pthread_getattr_np_alias
,
213 pthread_getattr_np
, GLIBC_2_2_3
);