-/* Copyright (C) 2002, 2003, 2004, 2006, 2007 Free Software Foundation, Inc.
+/* Copyright (C) 2002-2019 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, write to the Free
- Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- 02111-1307 USA. */
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
#include <assert.h>
#include <errno.h>
int
-pthread_getattr_np (thread_id, attr)
- pthread_t thread_id;
- pthread_attr_t *attr;
+pthread_getattr_np (pthread_t thread_id, pthread_attr_t *attr)
{
struct pthread *thread = (struct pthread *) thread_id;
struct pthread_attr *iattr = (struct pthread_attr *) attr;
int ret = 0;
- lll_lock (thread->lock);
+ lll_lock (thread->lock, LLL_PRIVATE);
/* The thread library is responsible for keeping the values in the
thread desriptor up-to-date in case the user changes them. */
iattr->guardsize = thread->reported_guardsize;
/* The sizes are subject to alignment. */
- if (__builtin_expect (thread->stackblock != NULL, 1))
+ if (__glibc_likely (thread->stackblock != NULL))
{
- iattr->stacksize = thread->stackblock_size;
- iattr->stackaddr = (char *) thread->stackblock + iattr->stacksize;
+ /* The stack size reported to the user should not include the
+ guard size. */
+ iattr->stacksize = thread->stackblock_size - thread->guardsize;
+#if _STACK_GROWS_DOWN
+ iattr->stackaddr = (char *) thread->stackblock
+ + thread->stackblock_size;
+#else
+ iattr->stackaddr = (char *) thread->stackblock;
+#endif
}
else
{
/* No stack information available. This must be for the initial
thread. Get the info in some magical way. */
- assert (abs (thread->pid) == thread->tid);
/* Stack size limit. */
struct rlimit rl;
/* The safest way to get the top of the stack is to read
/proc/self/maps and locate the line into which
__libc_stack_end falls. */
- FILE *fp = fopen ("/proc/self/maps", "rc");
+ FILE *fp = fopen ("/proc/self/maps", "rce");
if (fp == NULL)
ret = errno;
/* We need the limit of the stack in any case. */
ret = errno;
else
{
+ /* We consider the main process stack to have ended with
+ the page containing __libc_stack_end. There is stuff below
+ it in the stack too, like the program arguments, environment
+ variables and auxv info, but we ignore those pages when
+ returning size so that the output is consistent when the
+ stack is marked executable due to a loaded DSO requiring
+ it. */
+ void *stack_end = (void *) ((uintptr_t) __libc_stack_end
+ & -(uintptr_t) GLRO(dl_pagesize));
+#if _STACK_GROWS_DOWN
+ stack_end += GLRO(dl_pagesize);
+#endif
/* We need no locking. */
__fsetlocking (fp, FSETLOCKING_BYCALLER);
char *line = NULL;
size_t linelen = 0;
+#if _STACK_GROWS_DOWN
uintptr_t last_to = 0;
+#endif
while (! feof_unlocked (fp))
{
&& (uintptr_t) __libc_stack_end < to)
{
/* Found the entry. Now we have the info we need. */
- iattr->stacksize = rl.rlim_cur;
- iattr->stackaddr = (void *) to;
-
+ iattr->stackaddr = stack_end;
+ iattr->stacksize =
+ rl.rlim_cur - (size_t) (to - (uintptr_t) stack_end);
+
+ /* Cut it down to align it to page size since otherwise we
+ risk going beyond rlimit when the kernel rounds up the
+ stack extension request. */
+ iattr->stacksize = (iattr->stacksize
+ & -(intptr_t) GLRO(dl_pagesize));
+#if _STACK_GROWS_DOWN
/* The limit might be too high. */
if ((size_t) iattr->stacksize
> (size_t) iattr->stackaddr - last_to)
iattr->stacksize = (size_t) iattr->stackaddr - last_to;
-
+#else
+ /* The limit might be too high. */
+ if ((size_t) iattr->stacksize
+ > to - (size_t) iattr->stackaddr)
+ iattr->stacksize = to - (size_t) iattr->stackaddr;
+#endif
/* We succeed and no need to look further. */
ret = 0;
break;
}
+#if _STACK_GROWS_DOWN
last_to = to;
+#endif
}
free (line);
{
free (cpuset);
if (ret == ENOSYS)
- {
+ {
/* There is no such functionality. */
ret = 0;
iattr->cpuset = NULL;
}
}
- lll_unlock (thread->lock);
+ lll_unlock (thread->lock, LLL_PRIVATE);
return ret;
}