diff options
author | Philip Guenthe <guenther@cvs.openbsd.org> | 2012-02-19 06:47:32 +0000 |
---|---|---|
committer | Philip Guenthe <guenther@cvs.openbsd.org> | 2012-02-19 06:47:32 +0000 |
commit | 1a8f98c00c2140eac602330559a9d09a7865d26f (patch) | |
tree | 30de86b87eb74bafdf6bba2a0eaa876a705df13d /regress | |
parent | ab2d957b344c41d8b49efc3989b2b8cf2b628aa3 (diff) |
Add regress test for stack attributes
Disable some tests that depended on uthread's particular undefined behavior
Diffstat (limited to 'regress')
-rw-r--r-- | regress/lib/libpthread/Makefile | 9 | ||||
-rw-r--r-- | regress/lib/libpthread/stack/Makefile | 5 | ||||
-rw-r--r-- | regress/lib/libpthread/stack/stack.c | 138 |
3 files changed, 149 insertions, 3 deletions
diff --git a/regress/lib/libpthread/Makefile b/regress/lib/libpthread/Makefile index 35609683862..41e9ec199dc 100644 --- a/regress/lib/libpthread/Makefile +++ b/regress/lib/libpthread/Makefile @@ -1,13 +1,16 @@ -# $OpenBSD: Makefile,v 1.30 2012/01/04 17:38:24 mpi Exp $ +# $OpenBSD: Makefile,v 1.31 2012/02/19 06:47:31 guenther Exp $ -SUBDIR= blocked_close blocked_dup2 blocked_shutdown cancel cancel2 \ +# disabled because they assume uthread's particular undefined behavior; +# blocked_close blocked_dup2 blocked_shutdown + +SUBDIR= cancel cancel2 \ close close_race closefrom cwd dup2_race execve fork \ group malloc_duel netdb pcap poll preemption preemption_float \ pthread_atfork pthread_cond_timedwait pthread_create \ pthread_join pthread_kill pthread_mutex pthread_specific \ readdir restart select semaphore setjmp setsockopt sigdeliver siginfo \ siginterrupt signal signals signodefer sigsuspend sigwait sleep \ - socket stdarg stdio switch system + socket stack stdarg stdio switch system # Not available or disabled: fcntl, getaddrinfo, pause, pw, sigmask, stdfiles diff --git a/regress/lib/libpthread/stack/Makefile b/regress/lib/libpthread/stack/Makefile new file mode 100644 index 00000000000..e7be9a885d4 --- /dev/null +++ b/regress/lib/libpthread/stack/Makefile @@ -0,0 +1,5 @@ +# $OpenBSD: Makefile,v 1.1 2012/02/19 06:47:31 guenther Exp $ + +PROG= stack + +.include <bsd.regress.mk> diff --git a/regress/lib/libpthread/stack/stack.c b/regress/lib/libpthread/stack/stack.c new file mode 100644 index 00000000000..f7d4fb2d036 --- /dev/null +++ b/regress/lib/libpthread/stack/stack.c @@ -0,0 +1,138 @@ + +#include <sys/types.h> +#include <sys/mman.h> +#include <inttypes.h> +#include <limits.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "test.h" + +#define LARGE_SIZE (1024 * 1024) + +/* thread main for testing a large buffer on the stack */ +void * +tmain1(void *arg) +{ + char buf[LARGE_SIZE]; + + memset(buf, 0xd0, sizeof(buf)); + return (buf + LARGE_SIZE/2); +} + +/* + * struct and thread main for testing that a thread's stack is where + * we put it + */ +struct st +{ + char *addr; + size_t size; +}; +void * +tmain2(void *arg) +{ + struct st *s = arg; + + ASSERT((char *)&s >= s->addr && (char *)&s - s->addr < s->size); + return (NULL); +} + +int +main(void) +{ + pthread_attr_t attr; + pthread_t t; + struct st thread_stack; + void *addr, *addr2; + size_t size, size2, pagesize; + int err; + + pagesize = (size_t)sysconf(_SC_PAGESIZE); + + CHECKr(pthread_attr_init(&attr)); + + /* verify that the initial values are what we expect */ + size = 1; + CHECKr(pthread_attr_getguardsize(&attr, &size)); + ASSERT(size != 1); /* must have changed */ + ASSERT(size != 0); /* we default to having a guardpage */ + + size = 1; + CHECKr(pthread_attr_getstacksize(&attr, &size)); + ASSERT(size >= PTHREAD_STACK_MIN); + + addr = &addr; + CHECKr(pthread_attr_getstackaddr(&attr, &addr)); + ASSERT(addr == NULL); /* default must be NULL */ + + addr2 = &addr; + size2 = 1; + CHECKr(pthread_attr_getstack(&attr, &addr2, &size2)); + ASSERT(addr2 == addr); /* must match the other calls */ + ASSERT(size2 == size); + + /* verify that too small a size is rejected */ + err = pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN - 1); + ASSERT(err == EINVAL); + CHECKr(pthread_attr_getstacksize(&attr, &size2)); + ASSERT(size2 == size); + + + /* + * increase the stacksize, then verify that the change sticks, + * and that a large buffer fits on the resulting thread's stack + */ + size2 += LARGE_SIZE; + CHECKr(pthread_attr_setstacksize(&attr, size2)); + CHECKr(pthread_attr_getstacksize(&attr, &size)); + ASSERT(size == size2); + + CHECKr(pthread_create(&t, &attr, &tmain1, NULL)); + sleep(1); + CHECKr(pthread_join(t, &addr)); + + /* test whether the stack has been freed */ + /* XXX yow, this is grossly unportable, as it depends on the stack + * not being cached, the thread being marked freeable before + * pthread_join() calls the gc routine (thus the sleep), and this + * being testable by mquery */ + addr = (void *)((uintptr_t)addr & ~(pagesize - 1)); + ASSERT(mquery(addr, pagesize, PROT_READ, MAP_FIXED|MAP_ANON, -1, 0) + == addr); + + /* the attr wasn't modified by pthread_create, right? */ + size = 1; + CHECKr(pthread_attr_getstacksize(&attr, &size)); + ASSERT(size == size2); + + + /* allocate our own stack and verify the thread uses it */ + size = pagesize * 4; + addr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, + -1, 0); + ASSERT(addr != MAP_FAILED); + memset(addr, 0xd0, size); + CHECKr(pthread_attr_setstack(&attr, addr, size)); + + CHECKr(pthread_attr_getstacksize(&attr, &size2)); + ASSERT(size2 == size); + CHECKr(pthread_attr_getstackaddr(&attr, &addr2)); + ASSERT(addr2 == addr); + CHECKr(pthread_attr_getstack(&attr, &addr2, &size2)); + ASSERT(addr2 == addr); + ASSERT(size2 == size); + + thread_stack.addr = addr; + thread_stack.size = size; + CHECKr(pthread_create(&t, &attr, &tmain2, &thread_stack)); + sleep(1); + CHECKr(pthread_join(t, NULL)); + + /* verify that the stack we allocated was *not* freed */ + memset(addr, 0xd0, size); + + return (0); +} |