summaryrefslogtreecommitdiff
path: root/regress
diff options
context:
space:
mode:
authorPhilip Guenthe <guenther@cvs.openbsd.org>2012-02-19 06:47:32 +0000
committerPhilip Guenthe <guenther@cvs.openbsd.org>2012-02-19 06:47:32 +0000
commit1a8f98c00c2140eac602330559a9d09a7865d26f (patch)
tree30de86b87eb74bafdf6bba2a0eaa876a705df13d /regress
parentab2d957b344c41d8b49efc3989b2b8cf2b628aa3 (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/Makefile9
-rw-r--r--regress/lib/libpthread/stack/Makefile5
-rw-r--r--regress/lib/libpthread/stack/stack.c138
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);
+}