jcs's openbsd hax
openbsd
at jcs 241 lines 5.6 kB view raw
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 46int 47pthread_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 64int 65pthread_attr_destroy(pthread_attr_t *attrp) 66{ 67 free(*attrp); 68 *attrp = NULL; 69 70 return (0); 71} 72 73int 74pthread_attr_getguardsize(const pthread_attr_t *attrp, size_t *guardsize) 75{ 76 *guardsize = (*attrp)->guard_size; 77 78 return (0); 79} 80 81int 82pthread_attr_setguardsize(pthread_attr_t *attrp, size_t guardsize) 83{ 84 (*attrp)->guard_size = guardsize; 85 86 return (0); 87} 88 89int 90pthread_attr_getdetachstate(const pthread_attr_t *attrp, int *detachstate) 91{ 92 *detachstate = (*attrp)->detach_state; 93 94 return (0); 95} 96 97int 98pthread_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 110int 111pthread_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 120int 121pthread_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 179int 180pthread_attr_getstacksize(const pthread_attr_t *attrp, size_t *stacksize) 181{ 182 *stacksize = (*attrp)->stack_size; 183 184 return (0); 185} 186 187int 188pthread_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 201int 202pthread_attr_getstackaddr(const pthread_attr_t *attrp, void **stackaddr) 203{ 204 *stackaddr = (*attrp)->stack_addr; 205 206 return (0); 207} 208 209int 210pthread_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} 221DEF_NONSTD(pthread_attr_setstackaddr); 222 223int 224pthread_attr_getscope(const pthread_attr_t *attrp, int *contentionscope) 225{ 226 *contentionscope = (*attrp)->contention_scope; 227 228 return (0); 229} 230 231int 232pthread_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