Add script to devel-static as well
[platform/upstream/glibc.git] / nptl / pthread_getattr_np.c
1 /* Copyright (C) 2002-2023 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3
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.
8
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.
13
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/>.  */
17
18 #include <assert.h>
19 #include <errno.h>
20 #include <inttypes.h>
21 #include <stdio.h>
22 #include <stdio_ext.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/resource.h>
26 #include "pthreadP.h"
27 #include <lowlevellock.h>
28 #include <ldsodefs.h>
29
30
31 int
32 __pthread_getattr_np (pthread_t thread_id, pthread_attr_t *attr)
33 {
34   struct pthread *thread = (struct pthread *) thread_id;
35
36   /* Prepare the new thread attribute.  */
37   int ret = __pthread_attr_init (attr);
38   if (ret != 0)
39     return ret;
40
41   struct pthread_attr *iattr = (struct pthread_attr *) attr;
42
43   lll_lock (thread->lock, LLL_PRIVATE);
44
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;
50
51   /* Clear the flags work.  */
52   iattr->flags = thread->flags;
53
54   /* The thread might be detached by now.  */
55   if (IS_DETACHED (thread))
56     iattr->flags |= ATTR_FLAG_DETACHSTATE;
57
58   /* This is the guardsize after adjusting it.  */
59   iattr->guardsize = thread->reported_guardsize;
60
61   /* The sizes are subject to alignment.  */
62   if (__glibc_likely (thread->stackblock != NULL))
63     {
64       /* The stack size reported to the user should not include the
65          guard size.  */
66       iattr->stacksize = thread->stackblock_size - thread->guardsize;
67 #if _STACK_GROWS_DOWN
68       iattr->stackaddr = (char *) thread->stackblock
69                          + thread->stackblock_size;
70 #else
71       iattr->stackaddr = (char *) thread->stackblock;
72 #endif
73     }
74   else
75     {
76       /* No stack information available.  This must be for the initial
77          thread.  Get the info in some magical way.  */
78
79       /* Stack size limit.  */
80       struct rlimit rl;
81
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");
86       if (fp == NULL)
87         ret = errno;
88       /* We need the limit of the stack in any case.  */
89       else
90         {
91           if (__getrlimit (RLIMIT_STACK, &rl) != 0)
92             ret = errno;
93           else
94             {
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
101                  it.  */
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);
106 #endif
107               /* We need no locking.  */
108               __fsetlocking (fp, FSETLOCKING_BYCALLER);
109
110               /* Until we found an entry (which should always be the case)
111                  mark the result as a failure.  */
112               ret = ENOENT;
113
114               char *line = NULL;
115               size_t linelen = 0;
116 #if _STACK_GROWS_DOWN
117               uintptr_t last_to = 0;
118 #endif
119
120               while (! feof_unlocked (fp))
121                 {
122                   if (__getline (&line, &linelen, fp) <= 0)
123                     break;
124
125                   uintptr_t from;
126                   uintptr_t to;
127                   if (sscanf (line, "%" SCNxPTR "-%" SCNxPTR, &from, &to) != 2)
128                     continue;
129                   if (from <= (uintptr_t) __libc_stack_end
130                       && (uintptr_t) __libc_stack_end < to)
131                     {
132                       /* Found the entry.  Now we have the info we need.  */
133                       iattr->stackaddr = stack_end;
134                       iattr->stacksize =
135                         rl.rlim_cur - (size_t) (to - (uintptr_t) stack_end);
136
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;
147 #else
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;
152 #endif
153                       /* We succeed and no need to look further.  */
154                       ret = 0;
155                       break;
156                     }
157 #if _STACK_GROWS_DOWN
158                   last_to = to;
159 #endif
160                 }
161
162               free (line);
163             }
164
165           fclose (fp);
166         }
167     }
168
169   iattr->flags |= ATTR_FLAG_STACKADDR;
170
171   if (ret == 0)
172     {
173       size_t size = 16;
174       cpu_set_t *cpuset = NULL;
175
176       do
177         {
178           size <<= 1;
179
180           void *newp = realloc (cpuset, size);
181           if (newp == NULL)
182             {
183               ret = ENOMEM;
184               break;
185             }
186           cpuset = (cpu_set_t *) newp;
187
188           ret = __pthread_getaffinity_np (thread_id, size, cpuset);
189         }
190       /* Pick some ridiculous upper limit.  Is 8 million CPUs enough?  */
191       while (ret == EINVAL && size < 1024 * 1024);
192
193       if (ret == 0)
194         ret = __pthread_attr_setaffinity_np (attr, size, cpuset);
195       else if (ret == ENOSYS)
196         /* There is no such functionality.  */
197         ret = 0;
198       free (cpuset);
199     }
200
201   lll_unlock (thread->lock, LLL_PRIVATE);
202
203   if (ret != 0)
204     __pthread_attr_destroy (attr);
205
206   return ret;
207 }
208 versioned_symbol (libc, __pthread_getattr_np, pthread_getattr_np, GLIBC_2_32);
209
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);
214 #endif