xref: /openbsd-src/regress/lib/libpthread/stack/stack.c (revision 0eba73db19efecab8d11b91928dae628e5cacb64)
1*0eba73dbSguenther /* $OpenBSD: stack.c,v 1.4 2014/08/10 05:08:31 guenther Exp $ */
20ab44073Sguenther /* PUBLIC DOMAIN Feb 2012 <guenther@openbsd.org> */
30ab44073Sguenther 
40ab44073Sguenther /* Test the handling of the pthread_attr_t stack attributes */
5fc80f812Sguenther 
6fc80f812Sguenther #include <sys/types.h>
7fc80f812Sguenther #include <sys/mman.h>
8*0eba73dbSguenther #include <stdint.h>
9fc80f812Sguenther #include <limits.h>
10fc80f812Sguenther #include <pthread.h>
11fc80f812Sguenther #include <stdio.h>
12fc80f812Sguenther #include <stdlib.h>
13fc80f812Sguenther #include <string.h>
14fc80f812Sguenther #include <unistd.h>
15fc80f812Sguenther #include "test.h"
16fc80f812Sguenther 
17fc80f812Sguenther #define LARGE_SIZE	(1024 * 1024)
18fc80f812Sguenther 
19c187d929Sguenther /* thread main for plain location tests */
20c187d929Sguenther void *
tmain0(void * arg)21c187d929Sguenther tmain0(void *arg)
22c187d929Sguenther {
23c187d929Sguenther 	int s;
24c187d929Sguenther 
25c187d929Sguenther 	return (&s);
26c187d929Sguenther }
27c187d929Sguenther 
28fc80f812Sguenther /* thread main for testing a large buffer on the stack */
29fc80f812Sguenther void *
tmain1(void * arg)30fc80f812Sguenther tmain1(void *arg)
31fc80f812Sguenther {
32fc80f812Sguenther 	char buf[LARGE_SIZE];
33fc80f812Sguenther 
34fc80f812Sguenther 	memset(buf, 0xd0, sizeof(buf));
35fc80f812Sguenther 	return (buf + LARGE_SIZE/2);
36fc80f812Sguenther }
37fc80f812Sguenther 
38fc80f812Sguenther /*
39fc80f812Sguenther  * struct and thread main for testing that a thread's stack is where
40fc80f812Sguenther  * we put it
41fc80f812Sguenther  */
42fc80f812Sguenther struct st
43fc80f812Sguenther {
44fc80f812Sguenther 	char *addr;
45fc80f812Sguenther 	size_t size;
46fc80f812Sguenther };
47fc80f812Sguenther void *
tmain2(void * arg)48fc80f812Sguenther tmain2(void *arg)
49fc80f812Sguenther {
50fc80f812Sguenther 	struct st *s = arg;
51fc80f812Sguenther 
52fc80f812Sguenther 	ASSERT((char *)&s >= s->addr && (char *)&s - s->addr < s->size);
53fc80f812Sguenther 	return (NULL);
54fc80f812Sguenther }
55fc80f812Sguenther 
56fc80f812Sguenther int
main(void)57fc80f812Sguenther main(void)
58fc80f812Sguenther {
59fc80f812Sguenther 	pthread_attr_t attr;
60fc80f812Sguenther 	pthread_t t;
61fc80f812Sguenther 	struct st thread_stack;
62fc80f812Sguenther 	void *addr, *addr2;
63fc80f812Sguenther 	size_t size, size2, pagesize;
64fc80f812Sguenther 	int err;
65fc80f812Sguenther 
66fc80f812Sguenther 	pagesize = (size_t)sysconf(_SC_PAGESIZE);
67fc80f812Sguenther 
68fc80f812Sguenther 	CHECKr(pthread_attr_init(&attr));
69fc80f812Sguenther 
70fc80f812Sguenther 	/* verify that the initial values are what we expect */
71fc80f812Sguenther 	size = 1;
72fc80f812Sguenther 	CHECKr(pthread_attr_getguardsize(&attr, &size));
73fc80f812Sguenther 	ASSERT(size != 1);		/* must have changed */
74fc80f812Sguenther 	ASSERT(size != 0);		/* we default to having a guardpage */
75fc80f812Sguenther 
76fc80f812Sguenther 	size = 1;
77fc80f812Sguenther 	CHECKr(pthread_attr_getstacksize(&attr, &size));
78fc80f812Sguenther 	ASSERT(size >= PTHREAD_STACK_MIN);
79fc80f812Sguenther 
80fc80f812Sguenther 	addr = &addr;
81fc80f812Sguenther 	CHECKr(pthread_attr_getstackaddr(&attr, &addr));
82fc80f812Sguenther 	ASSERT(addr == NULL);		/* default must be NULL */
83fc80f812Sguenther 
84fc80f812Sguenther 	addr2 = &addr;
85fc80f812Sguenther 	size2 = 1;
86fc80f812Sguenther 	CHECKr(pthread_attr_getstack(&attr, &addr2, &size2));
87fc80f812Sguenther 	ASSERT(addr2 == addr);		/* must match the other calls */
88fc80f812Sguenther 	ASSERT(size2 == size);
89fc80f812Sguenther 
90fc80f812Sguenther 	/* verify that too small a size is rejected */
91fc80f812Sguenther 	err = pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN - 1);
92fc80f812Sguenther 	ASSERT(err == EINVAL);
93fc80f812Sguenther 	CHECKr(pthread_attr_getstacksize(&attr, &size2));
94fc80f812Sguenther 	ASSERT(size2 == size);
95fc80f812Sguenther 
96fc80f812Sguenther 
97c187d929Sguenther 	/* create a thread with the default stack attr so we can test reuse */
98c187d929Sguenther 	CHECKr(pthread_create(&t, NULL, &tmain0, NULL));
99c187d929Sguenther 	sleep(1);
100c187d929Sguenther 	CHECKr(pthread_join(t, &addr));
101c187d929Sguenther 
102c187d929Sguenther 	/*
103c187d929Sguenther 	 * verify that the stack has *not* been freed: we expect it to be
104c187d929Sguenther 	 * cached for reuse.  This is unportable for the same reasons as
105c187d929Sguenther 	 * the mquery() test below.  :-/
106c187d929Sguenther 	 */
107c187d929Sguenther 	*(int *)addr = 100;
108c187d929Sguenther 
109c187d929Sguenther 
110c187d929Sguenther 	/* do the above again and make sure the stack got reused */
111c187d929Sguenther 	CHECKr(pthread_create(&t, NULL, &tmain0, NULL));
112c187d929Sguenther 	sleep(1);
113c187d929Sguenther 	CHECKr(pthread_join(t, &addr2));
114c187d929Sguenther 	ASSERT(addr == addr2);
115c187d929Sguenther 
116c187d929Sguenther 
117fc80f812Sguenther 	/*
118fc80f812Sguenther 	 * increase the stacksize, then verify that the change sticks,
119fc80f812Sguenther 	 * and that a large buffer fits on the resulting thread's stack
120fc80f812Sguenther 	 */
121fc80f812Sguenther 	size2 += LARGE_SIZE;
122fc80f812Sguenther 	CHECKr(pthread_attr_setstacksize(&attr, size2));
123fc80f812Sguenther 	CHECKr(pthread_attr_getstacksize(&attr, &size));
124fc80f812Sguenther 	ASSERT(size == size2);
125fc80f812Sguenther 
126fc80f812Sguenther 	CHECKr(pthread_create(&t, &attr, &tmain1, NULL));
127fc80f812Sguenther 	sleep(1);
128fc80f812Sguenther 	CHECKr(pthread_join(t, &addr));
129fc80f812Sguenther 
130fc80f812Sguenther 	/* test whether the stack has been freed */
131fc80f812Sguenther 	/* XXX yow, this is grossly unportable, as it depends on the stack
132fc80f812Sguenther 	 * not being cached, the thread being marked freeable before
133fc80f812Sguenther 	 * pthread_join() calls the gc routine (thus the sleep), and this
134fc80f812Sguenther 	 * being testable by mquery */
135fc80f812Sguenther 	addr = (void *)((uintptr_t)addr & ~(pagesize - 1));
136fc80f812Sguenther 	ASSERT(mquery(addr, pagesize, PROT_READ, MAP_FIXED|MAP_ANON, -1, 0)
137fc80f812Sguenther 	    == addr);
138fc80f812Sguenther 
139fc80f812Sguenther 	/* the attr wasn't modified by pthread_create, right? */
140fc80f812Sguenther 	size = 1;
141fc80f812Sguenther 	CHECKr(pthread_attr_getstacksize(&attr, &size));
142fc80f812Sguenther 	ASSERT(size == size2);
143fc80f812Sguenther 
144fc80f812Sguenther 
145fc80f812Sguenther 	/* allocate our own stack and verify the thread uses it */
146fc80f812Sguenther 	size = pagesize * 4;
147fc80f812Sguenther 	addr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE,
148fc80f812Sguenther 	    -1, 0);
149fc80f812Sguenther 	ASSERT(addr != MAP_FAILED);
150fc80f812Sguenther 	memset(addr, 0xd0, size);
151fc80f812Sguenther 	CHECKr(pthread_attr_setstack(&attr, addr, size));
152fc80f812Sguenther 
153fc80f812Sguenther 	CHECKr(pthread_attr_getstacksize(&attr, &size2));
154fc80f812Sguenther 	ASSERT(size2 == size);
155fc80f812Sguenther 	CHECKr(pthread_attr_getstackaddr(&attr, &addr2));
156fc80f812Sguenther 	ASSERT(addr2 == addr);
157fc80f812Sguenther 	CHECKr(pthread_attr_getstack(&attr, &addr2, &size2));
158fc80f812Sguenther 	ASSERT(addr2 == addr);
159fc80f812Sguenther 	ASSERT(size2 == size);
160fc80f812Sguenther 
161fc80f812Sguenther 	thread_stack.addr = addr;
162fc80f812Sguenther 	thread_stack.size = size;
163fc80f812Sguenther 	CHECKr(pthread_create(&t, &attr, &tmain2, &thread_stack));
164fc80f812Sguenther 	sleep(1);
165fc80f812Sguenther 	CHECKr(pthread_join(t, NULL));
166fc80f812Sguenther 
167fc80f812Sguenther 	/* verify that the stack we allocated was *not* freed */
168fc80f812Sguenther 	memset(addr, 0xd0, size);
169fc80f812Sguenther 
170fc80f812Sguenther 	return (0);
171fc80f812Sguenther }
172