1 2 #include <sys/types.h> 3 #include <sys/mman.h> 4 #include <inttypes.h> 5 #include <limits.h> 6 #include <pthread.h> 7 #include <stdio.h> 8 #include <stdlib.h> 9 #include <string.h> 10 #include <unistd.h> 11 #include "test.h" 12 13 #define LARGE_SIZE (1024 * 1024) 14 15 /* thread main for testing a large buffer on the stack */ 16 void * 17 tmain1(void *arg) 18 { 19 char buf[LARGE_SIZE]; 20 21 memset(buf, 0xd0, sizeof(buf)); 22 return (buf + LARGE_SIZE/2); 23 } 24 25 /* 26 * struct and thread main for testing that a thread's stack is where 27 * we put it 28 */ 29 struct st 30 { 31 char *addr; 32 size_t size; 33 }; 34 void * 35 tmain2(void *arg) 36 { 37 struct st *s = arg; 38 39 ASSERT((char *)&s >= s->addr && (char *)&s - s->addr < s->size); 40 return (NULL); 41 } 42 43 int 44 main(void) 45 { 46 pthread_attr_t attr; 47 pthread_t t; 48 struct st thread_stack; 49 void *addr, *addr2; 50 size_t size, size2, pagesize; 51 int err; 52 53 pagesize = (size_t)sysconf(_SC_PAGESIZE); 54 55 CHECKr(pthread_attr_init(&attr)); 56 57 /* verify that the initial values are what we expect */ 58 size = 1; 59 CHECKr(pthread_attr_getguardsize(&attr, &size)); 60 ASSERT(size != 1); /* must have changed */ 61 ASSERT(size != 0); /* we default to having a guardpage */ 62 63 size = 1; 64 CHECKr(pthread_attr_getstacksize(&attr, &size)); 65 ASSERT(size >= PTHREAD_STACK_MIN); 66 67 addr = &addr; 68 CHECKr(pthread_attr_getstackaddr(&attr, &addr)); 69 ASSERT(addr == NULL); /* default must be NULL */ 70 71 addr2 = &addr; 72 size2 = 1; 73 CHECKr(pthread_attr_getstack(&attr, &addr2, &size2)); 74 ASSERT(addr2 == addr); /* must match the other calls */ 75 ASSERT(size2 == size); 76 77 /* verify that too small a size is rejected */ 78 err = pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN - 1); 79 ASSERT(err == EINVAL); 80 CHECKr(pthread_attr_getstacksize(&attr, &size2)); 81 ASSERT(size2 == size); 82 83 84 /* 85 * increase the stacksize, then verify that the change sticks, 86 * and that a large buffer fits on the resulting thread's stack 87 */ 88 size2 += LARGE_SIZE; 89 CHECKr(pthread_attr_setstacksize(&attr, size2)); 90 CHECKr(pthread_attr_getstacksize(&attr, &size)); 91 ASSERT(size == size2); 92 93 CHECKr(pthread_create(&t, &attr, &tmain1, NULL)); 94 sleep(1); 95 CHECKr(pthread_join(t, &addr)); 96 97 /* test whether the stack has been freed */ 98 /* XXX yow, this is grossly unportable, as it depends on the stack 99 * not being cached, the thread being marked freeable before 100 * pthread_join() calls the gc routine (thus the sleep), and this 101 * being testable by mquery */ 102 addr = (void *)((uintptr_t)addr & ~(pagesize - 1)); 103 ASSERT(mquery(addr, pagesize, PROT_READ, MAP_FIXED|MAP_ANON, -1, 0) 104 == addr); 105 106 /* the attr wasn't modified by pthread_create, right? */ 107 size = 1; 108 CHECKr(pthread_attr_getstacksize(&attr, &size)); 109 ASSERT(size == size2); 110 111 112 /* allocate our own stack and verify the thread uses it */ 113 size = pagesize * 4; 114 addr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, 115 -1, 0); 116 ASSERT(addr != MAP_FAILED); 117 memset(addr, 0xd0, size); 118 CHECKr(pthread_attr_setstack(&attr, addr, size)); 119 120 CHECKr(pthread_attr_getstacksize(&attr, &size2)); 121 ASSERT(size2 == size); 122 CHECKr(pthread_attr_getstackaddr(&attr, &addr2)); 123 ASSERT(addr2 == addr); 124 CHECKr(pthread_attr_getstack(&attr, &addr2, &size2)); 125 ASSERT(addr2 == addr); 126 ASSERT(size2 == size); 127 128 thread_stack.addr = addr; 129 thread_stack.size = size; 130 CHECKr(pthread_create(&t, &attr, &tmain2, &thread_stack)); 131 sleep(1); 132 CHECKr(pthread_join(t, NULL)); 133 134 /* verify that the stack we allocated was *not* freed */ 135 memset(addr, 0xd0, size); 136 137 return (0); 138 } 139