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