aboutsummaryrefslogtreecommitdiff
path: root/linuxthreads
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2000-08-05 06:15:04 +0000
committerUlrich Drepper <drepper@redhat.com>2000-08-05 06:15:04 +0000
commit234dd7a6ba1a9783f43d500f8ee745b2f5b4db5a (patch)
tree7b78bb63ef3d2c1ebfc89b59759068f2e394df5c /linuxthreads
parent0a8d92310f5c5e0c09c8ff9a79ac652a66d5b3da (diff)
downloadglibc-234dd7a6ba1a9783f43d500f8ee745b2f5b4db5a.tar
glibc-234dd7a6ba1a9783f43d500f8ee745b2f5b4db5a.tar.gz
glibc-234dd7a6ba1a9783f43d500f8ee745b2f5b4db5a.tar.bz2
glibc-234dd7a6ba1a9783f43d500f8ee745b2f5b4db5a.zip
Update.
* internals.h: Declare __pthread_max_stacksize. * pthread.c (__pthread_max_stacksize): New variable. (__pthread_initialize_manager): Determine __pthread_initialize_manager value. * manager.c (thread_segment): Return always NULL if FLOATING_STACKS. (pthread_allocate_stack): Allow kernel to choose stack address if FLOATING_STACKS. This also handles variable-sized stacks. Always allocate stack and guardoage together. Use mprotect to change guardpage access. * sysdeps/i386/useldt.h: Define FLOATING_STACKS and ARCH_STACK_MAX_SIZE. * attr.c (__pthread_attr_setstacksize): Also test value against upper limit.
Diffstat (limited to 'linuxthreads')
-rw-r--r--linuxthreads/ChangeLog15
-rw-r--r--linuxthreads/attr.c25
-rw-r--r--linuxthreads/internals.h5
-rw-r--r--linuxthreads/manager.c91
-rw-r--r--linuxthreads/pthread.c25
-rw-r--r--linuxthreads/sysdeps/i386/useldt.h6
6 files changed, 133 insertions, 34 deletions
diff --git a/linuxthreads/ChangeLog b/linuxthreads/ChangeLog
index 9ed86c5a91..58947167da 100644
--- a/linuxthreads/ChangeLog
+++ b/linuxthreads/ChangeLog
@@ -1,5 +1,20 @@
2000-08-04 Ulrich Drepper <drepper@redhat.com>
+ * internals.h: Declare __pthread_max_stacksize.
+ * pthread.c (__pthread_max_stacksize): New variable.
+ (__pthread_initialize_manager): Determine __pthread_initialize_manager
+ value.
+ * manager.c (thread_segment): Return always NULL if FLOATING_STACKS.
+ (pthread_allocate_stack): Allow kernel to choose stack address if
+ FLOATING_STACKS. This also handles variable-sized stacks.
+ Always allocate stack and guardoage together. Use mprotect to
+ change guardpage access.
+ * sysdeps/i386/useldt.h: Define FLOATING_STACKS and
+ ARCH_STACK_MAX_SIZE.
+
+ * attr.c (__pthread_attr_setstacksize): Also test value against
+ upper limit.
+
* manager.c (__pthread_nonstandard_stacks): Define only if
THREAD_SELF is not defined.
(pthread_allocate_stack): Always initialize gardaddr to a correct
diff --git a/linuxthreads/attr.c b/linuxthreads/attr.c
index 966cea1203..90ab019837 100644
--- a/linuxthreads/attr.c
+++ b/linuxthreads/attr.c
@@ -18,6 +18,7 @@
#include <string.h>
#include <unistd.h>
#include <sys/param.h>
+#include <sys/resource.h>
#include "pthread.h"
#include "internals.h"
#include <shlib-compat.h>
@@ -184,6 +185,30 @@ weak_alias (__pthread_attr_getstackaddr, pthread_attr_getstackaddr)
int __pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
{
+#ifdef FLOATING_STACKS
+ /* We have to check against the maximum allowed stack size. This is no
+ problem if the manager is already started and we determined it. If
+ this hasn't happened, we have to find the limit outself. */
+ if (__pthread_max_stacksize == 0)
+ {
+ struct rlimit limit;
+
+ getrlimit(RLIMIT_STACK, &limit);
+# ifdef NEED_SEPARATE_REGISTER_STACK
+ __pthread_max_stacksize = limit.rlim_max / 2;
+# else
+ __pthread_max_stacksize = limit.rlim_max;
+# endif
+ }
+
+ if (stacksize > __pthread_max_stacksize)
+ return EINVAL;
+#else
+ /* We have a fixed size limit. */
+ if (stacksize > STACK_SIZE)
+ return EINVAL;
+#endif
+
/* We don't accept value smaller than PTHREAD_STACK_MIN. */
if (stacksize < PTHREAD_STACK_MIN)
return EINVAL;
diff --git a/linuxthreads/internals.h b/linuxthreads/internals.h
index fa6bf6b9cd..f5915529b2 100644
--- a/linuxthreads/internals.h
+++ b/linuxthreads/internals.h
@@ -272,6 +272,11 @@ extern int __pthread_manager_reader;
extern char *__pthread_manager_thread_bos;
extern char *__pthread_manager_thread_tos;
+#ifdef FLOATING_STACKS
+/* Maximum stack size. */
+extern size_t __pthread_max_stacksize;
+#endif
+
/* Pending request for a process-wide exit */
extern int __pthread_exit_requested, __pthread_exit_code;
diff --git a/linuxthreads/manager.c b/linuxthreads/manager.c
index b76203c505..1510551374 100644
--- a/linuxthreads/manager.c
+++ b/linuxthreads/manager.c
@@ -64,25 +64,29 @@ volatile pthread_descr __pthread_last_event;
/* Stack segment numbers are also indices into the __pthread_handles array. */
/* Stack segment number 0 is reserved for the initial thread. */
+#if FLOATING_STACKS
+# define thread_segment(seq) NULL
+#else
static inline pthread_descr thread_segment(int seg)
{
return (pthread_descr)(THREAD_STACK_START_ADDRESS - (seg - 1) * STACK_SIZE)
- 1;
}
+#endif
/* Flag set in signal handler to record child termination */
-static volatile int terminated_children = 0;
+static volatile int terminated_children;
/* Flag set when the initial thread is blocked on pthread_exit waiting
for all other threads to terminate */
-static int main_thread_exiting = 0;
+static int main_thread_exiting;
/* Counter used to generate unique thread identifier.
Thread identifier is pthread_threads_counter + segment. */
-static pthread_t pthread_threads_counter = 0;
+static pthread_t pthread_threads_counter;
#ifdef NEED_SEPARATE_REGISTER_STACK
/* Signal masks for the manager. These have to be global only when clone2
@@ -338,6 +342,7 @@ static int pthread_allocate_stack(const pthread_attr_t *attr,
void *map_addr;
/* Allocate space for stack and thread descriptor at default address */
+#ifdef NEED_SEPARATE_REGISTER_STACK
if (attr != NULL)
{
guardsize = page_roundup (attr->__guardsize, granularity);
@@ -350,7 +355,7 @@ static int pthread_allocate_stack(const pthread_attr_t *attr,
guardsize = granularity;
stacksize = STACK_SIZE - granularity;
}
-#ifdef NEED_SEPARATE_REGISTER_STACK
+
new_thread = default_new_thread;
new_thread_bottom = (char *) (new_thread + 1) - stacksize - guardsize;
/* Includes guard area, unlike the normal case. Use the bottom
@@ -361,6 +366,8 @@ static int pthread_allocate_stack(const pthread_attr_t *attr,
in the same region. The cost is that we might be able to map
slightly fewer stacks. */
+ /* XXX Fix for floating stacks with variable sizes. */
+
/* First the main stack: */
if (mmap((caddr_t)((char *)(new_thread + 1) - stacksize / 2),
stacksize / 2, PROT_READ | PROT_WRITE | PROT_EXEC,
@@ -382,37 +389,63 @@ static int pthread_allocate_stack(const pthread_attr_t *attr,
guardaddr = new_thread_bottom + stacksize/2;
/* We leave the guard area in the middle unmapped. */
#else /* !NEED_SEPARATE_REGISTER_STACK */
+# if FLOATING_STACKS
+ if (attr != NULL)
+ {
+ guardsize = page_roundup (attr->__guardsize, granularity);
+ stacksize = __pthread_max_stacksize - guardsize;
+ stacksize = MIN (stacksize,
+ page_roundup (attr->__stacksize, granularity));
+ }
+ else
+ {
+ guardsize = granularity;
+ stacksize = __pthread_max_stacksize - guardsize;
+ }
+
+ map_addr = mmap(NULL, stacksize + guardsize,
+ PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (map_addr == MAP_FAILED)
+ /* No more memory available. */
+ return -1;
+
+ guardaddr = map_addr;
+ if (guardsize > 0)
+ mprotect (guardaddr, guardsize, PROT_NONE);
+
+ new_thread_bottom = (char *) map_addr + guardsize;
+ new_thread = ((pthread_descr) (new_thread_bottom + stacksize)) - 1;
+# else
+ if (attr != NULL)
+ {
+ guardsize = page_roundup (attr->__guardsize, granularity);
+ stacksize = STACK_SIZE - guardsize;
+ stacksize = MIN (stacksize,
+ page_roundup (attr->__stacksize, granularity));
+ }
+ else
+ {
+ guardsize = granularity;
+ stacksize = STACK_SIZE - granularity;
+ }
+
new_thread = default_new_thread;
new_thread_bottom = (char *) (new_thread + 1) - stacksize;
- map_addr = mmap((caddr_t)((char *)(new_thread + 1) - stacksize),
- stacksize, PROT_READ | PROT_WRITE | PROT_EXEC,
+ map_addr = mmap((caddr_t)((char *)(new_thread + 1) - stacksize - guardsize),
+ stacksize + guardsize,
+ PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
if (map_addr == MAP_FAILED)
/* Bad luck, this segment is already mapped. */
return -1;
- /* We manage to get a stack. Now see whether we need a guard
- and allocate it if necessary. Notice that the default
- attributes (stack_size = STACK_SIZE - pagesize and guardsize
- = pagesize) do not need a guard page, since the RLIMIT_STACK
- soft limit prevents stacks from running into one another. */
- if (stacksize == STACK_SIZE - pagesize)
- {
- /* We don't need a guard page. */
- guardaddr = new_thread_bottom;
- guardsize = 0;
- }
- else
- {
- /* Put a bad page at the bottom of the stack */
- guardaddr = (void *)new_thread_bottom - guardsize;
- if (mmap ((caddr_t) guardaddr, guardsize, 0, MAP_FIXED, -1, 0)
- == MAP_FAILED)
- {
- /* We don't make this an error. */
- guardaddr = new_thread_bottom;
- guardsize = 0;
- }
- }
+
+ /* We manage to get a stack. Protect the guard area pages if
+ necessary. */
+ guardaddr = map_addr;
+ if (guardsize > 0)
+ mprotect (guardaddr, guardsize, PROT_NONE);
+# endif
#endif /* !NEED_SEPARATE_REGISTER_STACK */
}
/* Clear the thread data structure. */
diff --git a/linuxthreads/pthread.c b/linuxthreads/pthread.c
index d13923a821..514ba5b71f 100644
--- a/linuxthreads/pthread.c
+++ b/linuxthreads/pthread.c
@@ -182,6 +182,9 @@ char *__pthread_manager_thread_tos;
int __pthread_exit_requested;
int __pthread_exit_code;
+/* Maximum stack size. */
+size_t __pthread_max_stacksize;
+
/* Nozero if the machine has more than one processor. */
int __pthread_smp_kernel;
@@ -455,20 +458,32 @@ int __pthread_initialize_manager(void)
struct rlimit limit;
int max_stack;
+ getrlimit(RLIMIT_STACK, &limit);
+#ifdef FLOATING_STACKS
+ if (limit.rlim_cur == RLIM_INFINITY)
+ limit.rlim_cur = ARCH_STACK_MAX_SIZE;
+# ifdef NEED_SEPARATE_REGISTER_STACK
+ max_stack = limit.rlim_cur / 2;
+# else
+ max_stack = limit.rlim_cur;
+#endif
+
+ __pthread_max_stacksize = max_stack;
+#else
/* Play with the stack size limit to make sure that no stack ever grows
beyond STACK_SIZE minus one page (to act as a guard page). */
- getrlimit(RLIMIT_STACK, &limit);
-#ifdef NEED_SEPARATE_REGISTER_STACK
+# ifdef NEED_SEPARATE_REGISTER_STACK
/* STACK_SIZE bytes hold both the main stack and register backing
store. The rlimit value applies to each individually. */
- max_stack = STACK_SIZE/2 - __getpagesize();
-#else
+ max_stack = STACK_SIZE/2 - __getpagesize ();
+# else
max_stack = STACK_SIZE - __getpagesize();
-#endif
+# endif
if (limit.rlim_cur > max_stack) {
limit.rlim_cur = max_stack;
setrlimit(RLIMIT_STACK, &limit);
}
+#endif
/* If basic initialization not done yet (e.g. we're called from a
constructor run before our constructor), do it now */
if (__pthread_initial_thread_bos == NULL) pthread_initialize();
diff --git a/linuxthreads/sysdeps/i386/useldt.h b/linuxthreads/sysdeps/i386/useldt.h
index 10cc3d41a3..ebf520cc39 100644
--- a/linuxthreads/sysdeps/i386/useldt.h
+++ b/linuxthreads/sysdeps/i386/useldt.h
@@ -169,3 +169,9 @@ extern int __modify_ldt (int, struct modify_ldt_ldt_s *, size_t);
member))); \
} \
})
+
+/* We want the OS to assign stack addresses. */
+#define FLOATING_STACKS 1
+
+/* Maximum size o fthe stack if the rlimit is unlimited. */
+#define ARCH_STACK_MAX_SIZE 8*1024*1024