1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-08-07 06:43:00 +03:00

Set default stack size from program environment

New environment variable GLIBC_PTHREAD_DEFAULT_STACKSIZE to do this.
This commit is contained in:
Siddhesh Poyarekar
2013-03-01 14:15:39 +05:30
parent fd6cdc6da4
commit e23872c8db
8 changed files with 155 additions and 26 deletions

View File

@@ -1,3 +1,9 @@
2013-03-01 Siddhesh Poyarekar <siddhesh@redhat.com>
* csu/libc-start.c (__pthread_initialize_minimal): Change
function arguments.
* csu/libc-tls.c (__pthread_initialize_minimal): Likewise.
2013-02-28 Joseph Myers <joseph@codesourcery.com> 2013-02-28 Joseph Myers <joseph@codesourcery.com>
[BZ #13550] [BZ #13550]

4
NEWS
View File

@@ -17,6 +17,10 @@ Version 2.18
and program exit. This needs compiler support for offloading C++11 and program exit. This needs compiler support for offloading C++11
destructor calls to glibc. destructor calls to glibc.
* Add support for setting thread stack sizes from the program environment,
independently of the process stack size using the
GLIBC_PTHREAD_DEFAULT_STACKSIZE environment variable.
Version 2.17 Version 2.17

View File

@@ -30,7 +30,7 @@ extern int __libc_multiple_libcs;
#include <tls.h> #include <tls.h>
#ifndef SHARED #ifndef SHARED
# include <dl-osinfo.h> # include <dl-osinfo.h>
extern void __pthread_initialize_minimal (void); extern void __pthread_initialize_minimal (int, char **, char **);
# ifndef THREAD_SET_STACK_GUARD # ifndef THREAD_SET_STACK_GUARD
/* Only exported for architectures that don't store the stack guard canary /* Only exported for architectures that don't store the stack guard canary
in thread local area. */ in thread local area. */
@@ -167,7 +167,7 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
/* Initialize the thread library at least a bit since the libgcc /* Initialize the thread library at least a bit since the libgcc
functions are using thread functions if these are available and functions are using thread functions if these are available and
we need to setup errno. */ we need to setup errno. */
__pthread_initialize_minimal (); __pthread_initialize_minimal (argc, argv, __environ);
/* Set up the stack checker's canary. */ /* Set up the stack checker's canary. */
uintptr_t stack_chk_guard = _dl_setup_stack_chk_guard (_dl_random); uintptr_t stack_chk_guard = _dl_setup_stack_chk_guard (_dl_random);

View File

@@ -243,7 +243,7 @@ _dl_tls_setup (void)
not used. */ not used. */
void void
__attribute__ ((weak)) __attribute__ ((weak))
__pthread_initialize_minimal (void) __pthread_initialize_minimal (int argc, char **argv, char **envp)
{ {
__libc_setup_tls (TLS_INIT_TCB_SIZE, TLS_INIT_TCB_ALIGN); __libc_setup_tls (TLS_INIT_TCB_SIZE, TLS_INIT_TCB_ALIGN);
} }

View File

@@ -1,3 +1,12 @@
2013-03-01 Siddhesh Poyarekar <siddhesh@redhat.com>
* Makefile (tests): Add tst-pthread-stack-env.
(tst-pthread-stack-env-ENV): Set environment for test.
* nptl-init.c (set_default_stacksize): New function.
(__pthread_initialize_minimal_internal): Accept ARGC, ARGV and
ENVP. Initialize __ENVIRON and set __DEFAULT_STACKSIZE.
* tst-pthread-stack-env.c: New test case.
2013-02-21 David S. Miller <davem@davemloft.net> 2013-02-21 David S. Miller <davem@davemloft.net>
* sysdeps/unix/sysv/linux/sparc/lowlevellock.h * sysdeps/unix/sysv/linux/sparc/lowlevellock.h

View File

@@ -251,7 +251,8 @@ tests = tst-typesizes \
tst-exec1 tst-exec2 tst-exec3 tst-exec4 \ tst-exec1 tst-exec2 tst-exec3 tst-exec4 \
tst-exit1 tst-exit2 tst-exit3 \ tst-exit1 tst-exit2 tst-exit3 \
tst-stdio1 tst-stdio2 \ tst-stdio1 tst-stdio2 \
tst-stack1 tst-stack2 tst-stack3 tst-pthread-getattr \ tst-stack1 tst-stack2 tst-stack3 \
tst-pthread-getattr tst-pthread-stack-env \
tst-unload \ tst-unload \
tst-dlsym1 \ tst-dlsym1 \
tst-sysconf \ tst-sysconf \
@@ -441,6 +442,8 @@ tst-cancel7-ARGS = --command "exec $(host-test-program-cmd)"
tst-cancelx7-ARGS = $(tst-cancel7-ARGS) tst-cancelx7-ARGS = $(tst-cancel7-ARGS)
tst-umask1-ARGS = $(objpfx)tst-umask1.temp tst-umask1-ARGS = $(objpfx)tst-umask1.temp
tst-pthread-stack-env-ENV = GLIBC_PTHREAD_DEFAULT_STACKSIZE=1048576
$(objpfx)tst-atfork2: $(libdl) $(shared-thread-library) $(objpfx)tst-atfork2: $(libdl) $(shared-thread-library)
LDFLAGS-tst-atfork2 = -rdynamic LDFLAGS-tst-atfork2 = -rdynamic
tst-atfork2-ENV = MALLOC_TRACE=$(objpfx)tst-atfork2.mtrace tst-atfork2-ENV = MALLOC_TRACE=$(objpfx)tst-atfork2.mtrace

View File

@@ -276,8 +276,26 @@ extern void **__libc_dl_error_tsd (void) __attribute__ ((const));
/* This can be set by the debugger before initialization is complete. */ /* This can be set by the debugger before initialization is complete. */
static bool __nptl_initial_report_events __attribute_used__; static bool __nptl_initial_report_events __attribute_used__;
static void
set_default_stacksize (size_t stacksize)
{
if (stacksize < PTHREAD_STACK_MIN)
stacksize = PTHREAD_STACK_MIN;
/* Make sure it meets the minimum size that allocate_stack
(allocatestack.c) will demand, which depends on the page size. */
const uintptr_t pagesz = GLRO(dl_pagesize);
const size_t minstack = pagesz + __static_tls_size + MINIMAL_REST_STACK;
if (stacksize < minstack)
stacksize = minstack;
/* Round the resource limit up to page size. */
stacksize = (stacksize + pagesz - 1) & -pagesz;
__default_stacksize = stacksize;
}
void void
__pthread_initialize_minimal_internal (void) __pthread_initialize_minimal_internal (int argc, char **argv, char **envp)
{ {
#ifndef SHARED #ifndef SHARED
/* Unlike in the dynamically linked case the dynamic linker has not /* Unlike in the dynamically linked case the dynamic linker has not
@@ -401,29 +419,41 @@ __pthread_initialize_minimal_internal (void)
__static_tls_size = roundup (__static_tls_size, static_tls_align); __static_tls_size = roundup (__static_tls_size, static_tls_align);
/* Determine the default allowed stack size. This is the size used /* Initialize the environment. libc.so gets initialized after us due to a
in case the user does not specify one. */ circular dependency and hence __environ is not available otherwise. */
struct rlimit limit; __environ = envp;
if (getrlimit (RLIMIT_STACK, &limit) != 0
|| limit.rlim_cur == RLIM_INFINITY)
/* The system limit is not usable. Use an architecture-specific
default. */
limit.rlim_cur = ARCH_STACK_DEFAULT_SIZE;
else if (limit.rlim_cur < PTHREAD_STACK_MIN)
/* The system limit is unusably small.
Use the minimal size acceptable. */
limit.rlim_cur = PTHREAD_STACK_MIN;
/* Make sure it meets the minimum size that allocate_stack #ifndef SHARED
(allocatestack.c) will demand, which depends on the page size. */ __libc_init_secure ();
const uintptr_t pagesz = GLRO(dl_pagesize); #endif
const size_t minstack = pagesz + __static_tls_size + MINIMAL_REST_STACK;
if (limit.rlim_cur < minstack)
limit.rlim_cur = minstack;
/* Round the resource limit up to page size. */ size_t stacksize = 0;
limit.rlim_cur = (limit.rlim_cur + pagesz - 1) & -pagesz; char *envval = __libc_secure_getenv ("GLIBC_PTHREAD_DEFAULT_STACKSIZE");
__default_stacksize = limit.rlim_cur;
if (__glibc_unlikely (envval != NULL && envval[0] != '\0'))
{
char *env_conv = envval;
size_t ret = strtoul (envval, &env_conv, 0);
if (*env_conv == '\0' && env_conv != envval)
stacksize = ret;
}
if (stacksize == 0)
{
/* Determine the default allowed stack size. This is the size used
in case the user does not specify one. */
struct rlimit limit;
if (getrlimit (RLIMIT_STACK, &limit) != 0
|| limit.rlim_cur == RLIM_INFINITY)
/* The system limit is not usable. Use an architecture-specific
default. */
stacksize = ARCH_STACK_DEFAULT_SIZE;
else
stacksize = limit.rlim_cur;
}
set_default_stacksize (stacksize);
#ifdef SHARED #ifdef SHARED
/* Transfer the old value from the dynamic linker's internal location. */ /* Transfer the old value from the dynamic linker's internal location. */

View File

@@ -0,0 +1,77 @@
/* Verify that pthreads uses the default thread stack size set with the
GLIBC_PTHREAD_DEFAULT_STACKSIZE environment variable.
Copyright (C) 2013 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
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, see
<http://www.gnu.org/licenses/>. */
#include <pthread.h>
#include <stdio.h>
#include <string.h>
/* It is possible that the default stack size somehow ends up being 1MB, thus
giving a false positive. The ideal way to test this would be to get the
current stacksize fork a process with the default stack size set to
something different to the current stack size and verify in the child
process that the environment variable worked. */
#define STACKSIZE 1024 * 1024L
void *
thr (void *u)
{
size_t stacksize, guardsize;
pthread_attr_t attr;
pthread_getattr_np (pthread_self (), &attr);
pthread_attr_getstacksize (&attr, &stacksize);
pthread_attr_getguardsize (&attr, &guardsize);
/* FIXME once guardsize is excluded from stacksize. */
if (stacksize - guardsize != STACKSIZE)
{
printf ("Stack size is %zu, should be %zu\n", stacksize - guardsize,
STACKSIZE);
return (void *) 1;
}
return NULL;
}
int
do_test (int argc, char **argv)
{
pthread_t t;
void *thr_ret;
int ret;
if ((ret = pthread_create (&t, NULL, thr, NULL)) != 0)
{
printf ("thread create failed: %s\n", strerror (ret));
return 1;
}
if ((ret = pthread_join (t, &thr_ret)) != 0)
{
printf ("join failed: %s\n", strerror (ret));
return 1;
}
if (thr_ret != NULL && thr_ret != PTHREAD_CANCELED)
return 1;
return 0;
}
#include "../test-skeleton.c"