diff options
author | Siddhesh Poyarekar <siddhesh@redhat.com> | 2013-03-01 14:15:39 +0530 |
---|---|---|
committer | Siddhesh Poyarekar <siddhesh@redhat.com> | 2013-03-01 14:15:39 +0530 |
commit | e23872c8db1fb26713b9c15b12686ac7a0077576 (patch) | |
tree | a7fa040afb53ba1f5bd98bb33f214aa32e3729b8 /nptl | |
parent | fd6cdc6da490616f4d381f4d44f03d61f64da2ba (diff) | |
download | glibc-e23872c8db1fb26713b9c15b12686ac7a0077576.tar.gz |
Set default stack size from program environment
New environment variable GLIBC_PTHREAD_DEFAULT_STACKSIZE to do this.
Diffstat (limited to 'nptl')
-rw-r--r-- | nptl/ChangeLog | 9 | ||||
-rw-r--r-- | nptl/Makefile | 5 | ||||
-rw-r--r-- | nptl/nptl-init.c | 74 | ||||
-rw-r--r-- | nptl/tst-pthread-stack-env.c | 77 |
4 files changed, 142 insertions, 23 deletions
diff --git a/nptl/ChangeLog b/nptl/ChangeLog index 2a676085ad..39b91a8177 100644 --- a/nptl/ChangeLog +++ b/nptl/ChangeLog @@ -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> * sysdeps/unix/sysv/linux/sparc/lowlevellock.h diff --git a/nptl/Makefile b/nptl/Makefile index 6af4b37af4..e7cfe8bcd4 100644 --- a/nptl/Makefile +++ b/nptl/Makefile @@ -251,7 +251,8 @@ tests = tst-typesizes \ tst-exec1 tst-exec2 tst-exec3 tst-exec4 \ tst-exit1 tst-exit2 tst-exit3 \ 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-dlsym1 \ tst-sysconf \ @@ -441,6 +442,8 @@ tst-cancel7-ARGS = --command "exec $(host-test-program-cmd)" tst-cancelx7-ARGS = $(tst-cancel7-ARGS) tst-umask1-ARGS = $(objpfx)tst-umask1.temp +tst-pthread-stack-env-ENV = GLIBC_PTHREAD_DEFAULT_STACKSIZE=1048576 + $(objpfx)tst-atfork2: $(libdl) $(shared-thread-library) LDFLAGS-tst-atfork2 = -rdynamic tst-atfork2-ENV = MALLOC_TRACE=$(objpfx)tst-atfork2.mtrace diff --git a/nptl/nptl-init.c b/nptl/nptl-init.c index 19e6616420..50148224e8 100644 --- a/nptl/nptl-init.c +++ b/nptl/nptl-init.c @@ -276,8 +276,26 @@ extern void **__libc_dl_error_tsd (void) __attribute__ ((const)); /* This can be set by the debugger before initialization is complete. */ 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 -__pthread_initialize_minimal_internal (void) +__pthread_initialize_minimal_internal (int argc, char **argv, char **envp) { #ifndef SHARED /* 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); - /* 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. */ - 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; + /* Initialize the environment. libc.so gets initialized after us due to a + circular dependency and hence __environ is not available otherwise. */ + __environ = envp; - /* 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 (limit.rlim_cur < minstack) - limit.rlim_cur = minstack; +#ifndef SHARED + __libc_init_secure (); +#endif - /* Round the resource limit up to page size. */ - limit.rlim_cur = (limit.rlim_cur + pagesz - 1) & -pagesz; - __default_stacksize = limit.rlim_cur; + size_t stacksize = 0; + char *envval = __libc_secure_getenv ("GLIBC_PTHREAD_DEFAULT_STACKSIZE"); + + 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 /* Transfer the old value from the dynamic linker's internal location. */ diff --git a/nptl/tst-pthread-stack-env.c b/nptl/tst-pthread-stack-env.c new file mode 100644 index 0000000000..09f03044c0 --- /dev/null +++ b/nptl/tst-pthread-stack-env.c @@ -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" |