1 /* $OpenBSD: rthread_attr.c,v 1.25 2018/05/02 14:06:00 bluhm Exp $ */ 2 /* 3 * Copyright (c) 2004,2005 Ted Unangst <tedu@openbsd.org> 4 * All Rights Reserved. 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 /* 19 * generic attribute support 20 */ 21 22 #include <sys/mman.h> 23 24 #include <stdint.h> 25 #include <stdlib.h> 26 #include <syslog.h> 27 #include <unistd.h> 28 #include <errno.h> 29 30 #include <pthread.h> 31 #include <pthread_np.h> 32 33 #include "rthread.h" 34 35 /* 36 * Note: stack_size + guard_size == total stack used 37 * 38 * pthread_attr_init MUST be called before any other attribute function 39 * for proper operation. 40 * 41 * Every call to pthread_attr_init MUST be matched with a call to 42 * pthread_attr_destroy to avoid leaking memory. This is an implementation 43 * requirement, not a POSIX requirement. 44 */ 45 46 int 47 pthread_attr_init(pthread_attr_t *attrp) 48 { 49 pthread_attr_t attr; 50 51 /* make sure _rthread_attr_default has been initialized */ 52 if (!_threads_ready) 53 _rthread_init(); 54 55 attr = calloc(1, sizeof(*attr)); 56 if (!attr) 57 return (errno); 58 *attr = _rthread_attr_default; 59 *attrp = attr; 60 61 return (0); 62 } 63 64 int 65 pthread_attr_destroy(pthread_attr_t *attrp) 66 { 67 free(*attrp); 68 *attrp = NULL; 69 70 return (0); 71 } 72 73 int 74 pthread_attr_getguardsize(const pthread_attr_t *attrp, size_t *guardsize) 75 { 76 *guardsize = (*attrp)->guard_size; 77 78 return (0); 79 } 80 81 int 82 pthread_attr_setguardsize(pthread_attr_t *attrp, size_t guardsize) 83 { 84 (*attrp)->guard_size = guardsize; 85 86 return (0); 87 } 88 89 int 90 pthread_attr_getdetachstate(const pthread_attr_t *attrp, int *detachstate) 91 { 92 *detachstate = (*attrp)->detach_state; 93 94 return (0); 95 } 96 97 int 98 pthread_attr_setdetachstate(pthread_attr_t *attrp, int detachstate) 99 { 100 int error; 101 102 error = (detachstate == PTHREAD_CREATE_DETACHED || 103 detachstate == PTHREAD_CREATE_JOINABLE) ? 0 : EINVAL; 104 if (error == 0) 105 (*attrp)->detach_state = detachstate; 106 107 return (error); 108 } 109 110 int 111 pthread_attr_getstack(const pthread_attr_t *attrp, void **stackaddr, 112 size_t *stacksize) 113 { 114 *stackaddr = (*attrp)->stack_addr; 115 *stacksize = (*attrp)->stack_size; 116 117 return (0); 118 } 119 120 int 121 pthread_attr_setstack(pthread_attr_t *attrp, void *stackaddr, size_t stacksize) 122 { 123 int error; 124 volatile char *p = stackaddr; 125 size_t i; 126 struct syslog_data data = SYSLOG_DATA_INIT; 127 128 if (stacksize < PTHREAD_STACK_MIN) { 129 syslog_r(LOG_ERR, &data, 130 "pthread_attr_setstack(%p, %zu): " 131 "stack size below min size %d", 132 stackaddr, stacksize, PTHREAD_STACK_MIN); 133 return (EINVAL); 134 } 135 136 /* 137 * Make sure that the stack is page-aligned and a multiple 138 * of the page size 139 */ 140 if (((uintptr_t)stackaddr % PTHREAD_STACK_MIN) != 0 141 || (stacksize % PTHREAD_STACK_MIN) != 0) { 142 syslog_r(LOG_ERR, &data, 143 "pthread_attr_setstack(%p, 0x%zx): " 144 "unaligned thread stack start and/or size", 145 stackaddr, stacksize); 146 return (EINVAL); 147 } 148 149 /* 150 * We are going to re-mmap() stackaddr to MAP_STACK, but only 151 * if the entire range [stackaddr, stackaddr+stacksize) consists 152 * of valid address that are mapped PROT_READ|PROT_WRITE. 153 * Test this by reading and writing every page. 154 * 155 * XXX: What if the caller has SIGSEGV blocked or ignored? 156 * Then we won't crash here when entering an invalid mapping. 157 */ 158 for (i = 0; i < stacksize; i += PTHREAD_STACK_MIN) { 159 char val = p[i]; 160 161 p[i] = val; 162 } 163 164 if (mmap(stackaddr, stacksize, PROT_READ|PROT_WRITE, 165 MAP_FIXED|MAP_STACK|MAP_ANON|MAP_PRIVATE, -1, 0) == MAP_FAILED) { 166 syslog_r(LOG_ERR, &data, 167 "pthread_attr_setstack(%p, %zu): mmap error %m", 168 stackaddr, stacksize); 169 return (errno); 170 } 171 172 if ((error = pthread_attr_setstackaddr(attrp, stackaddr))) 173 return (error); 174 (*attrp)->stack_size = stacksize; 175 176 return (0); 177 } 178 179 int 180 pthread_attr_getstacksize(const pthread_attr_t *attrp, size_t *stacksize) 181 { 182 *stacksize = (*attrp)->stack_size; 183 184 return (0); 185 } 186 187 int 188 pthread_attr_setstacksize(pthread_attr_t *attrp, size_t stacksize) 189 { 190 if (!_threads_ready) /* for ROUND_TO_PAGE */ 191 _rthread_init(); 192 193 if (stacksize < PTHREAD_STACK_MIN || 194 stacksize > ROUND_TO_PAGE(stacksize)) 195 return (EINVAL); 196 (*attrp)->stack_size = stacksize; 197 198 return (0); 199 } 200 201 int 202 pthread_attr_getstackaddr(const pthread_attr_t *attrp, void **stackaddr) 203 { 204 *stackaddr = (*attrp)->stack_addr; 205 206 return (0); 207 } 208 209 int 210 pthread_attr_setstackaddr(pthread_attr_t *attrp, void *stackaddr) 211 { 212 if (!_threads_ready) 213 _rthread_init(); /* for _thread_pagesize */ 214 215 if (stackaddr == NULL || (uintptr_t)stackaddr & (_thread_pagesize - 1)) 216 return (EINVAL); 217 (*attrp)->stack_addr = stackaddr; 218 219 return (0); 220 } 221 DEF_NONSTD(pthread_attr_setstackaddr); 222 223 int 224 pthread_attr_getscope(const pthread_attr_t *attrp, int *contentionscope) 225 { 226 *contentionscope = (*attrp)->contention_scope; 227 228 return (0); 229 } 230 231 int 232 pthread_attr_setscope(pthread_attr_t *attrp, int contentionscope) 233 { 234 if (contentionscope != PTHREAD_SCOPE_SYSTEM && 235 contentionscope != PTHREAD_SCOPE_PROCESS) 236 return (EINVAL); 237 (*attrp)->contention_scope = contentionscope; 238 239 return (0); 240 } 241 242