diff options
author | David Leonard <d@cvs.openbsd.org> | 1999-11-25 07:01:48 +0000 |
---|---|---|
committer | David Leonard <d@cvs.openbsd.org> | 1999-11-25 07:01:48 +0000 |
commit | 0fe78c3128864d128b2b10153b8d533ff8c00375 (patch) | |
tree | 5229c3d97eed15f4d71927a5f454180aef2632f6 /lib/libc_r/uthread/uthread_stack.c | |
parent | ed00fa742a6455d22e3b56cf846dc5acd7a51fd7 (diff) |
sync with FreeBSD
Diffstat (limited to 'lib/libc_r/uthread/uthread_stack.c')
-rw-r--r-- | lib/libc_r/uthread/uthread_stack.c | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/lib/libc_r/uthread/uthread_stack.c b/lib/libc_r/uthread/uthread_stack.c new file mode 100644 index 00000000000..940f295efd3 --- /dev/null +++ b/lib/libc_r/uthread/uthread_stack.c @@ -0,0 +1,97 @@ +/* $OpenBSD: uthread_stack.c,v 1.1 1999/11/25 07:01:46 d Exp $ */ + +/* + * Thread stack allocation. + * + * Stack pointers are assumed to work their way down (backwards) to the + * beginning of the stack storage. The first page of this storage is + * protected using mprotect() so as to generate a SIGSEGV if a thread + * overflows its stack. + */ + +#include <stddef.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/param.h> +#include <sys/user.h> +#include <sys/mman.h> +#include <pthread.h> +#include <pthread_np.h> +#include "pthread_private.h" + +struct stack * +_thread_stack_alloc(base, size) + void *base; + size_t size; +{ + struct stack *stack; + + /* Maintain a queue of default-sized stacks that we can re-use. */ + if (size == PTHREAD_STACK_DEFAULT) { + if (pthread_mutex_lock(&_gc_mutex) != 0) + PANIC("Cannot lock gc mutex"); + + if ((stack = SLIST_FIRST(&_stackq)) != NULL) { + SLIST_REMOVE_HEAD(&_stackq, qe); + if (pthread_mutex_unlock(&_gc_mutex) != 0) + PANIC("Cannot unlock gc mutex"); + return stack; + } + if (pthread_mutex_unlock(&_gc_mutex) != 0) + PANIC("Cannot unlock gc mutex"); + } + + /* Allocate some storage to hold information about the stack: */ + stack = (struct stack *)malloc(sizeof (struct stack)); + if (stack == NULL) + return NULL; + + if (base != NULL) { + /* Use the user's storage */ + stack->base = base; + stack->size = size; + stack->redzone = NULL; + stack->storage = NULL; + return stack; + } + + /* Allocate some storage for the stack, with some overhead: */ + stack->storage = malloc(size + NBPG * 2); + if (stack->storage == NULL) { + free(stack); + return NULL; + } + + /* The red zone is the first physical page of the storage: */ + stack->redzone = (void*)(((int)stack->storage + NBPG - 1) & + ~(NBPG - 1)); + if (mprotect(stack->redzone, NBPG, 0) == -1) + PANIC("Cannot protect stack red zone"); + + /* Find the useful range of the stack. */ + stack->base = stack->redzone + NBPG; + stack->size = size; + + return stack; +} + +void +_thread_stack_free(stack) + struct stack *stack; +{ + /* Cache allocated stacks of default size. */ + if (stack->storage != NULL && stack->size == PTHREAD_STACK_DEFAULT) + SLIST_INSERT_HEAD(&_stackq, stack, qe); + else { + /* Restore storage protection to what malloc expects: */ + if (stack->redzone) + mprotect(stack->redzone, NBPG, PROT_READ|PROT_WRITE); + + /* Free storage */ + if (stack->storage) + free(stack->storage); + + /* Free stack information storage. */ + free(stack); + } +} |