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