1*c1e618aaSbluhm /* $OpenBSD: rthread_attr.c,v 1.25 2018/05/02 14:06:00 bluhm Exp $ */
21a251377Stedu /*
355aa0b8cStedu * Copyright (c) 2004,2005 Ted Unangst <tedu@openbsd.org>
41a251377Stedu * All Rights Reserved.
51a251377Stedu *
61a251377Stedu * Permission to use, copy, modify, and distribute this software for any
71a251377Stedu * purpose with or without fee is hereby granted, provided that the above
81a251377Stedu * copyright notice and this permission notice appear in all copies.
91a251377Stedu *
101a251377Stedu * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
111a251377Stedu * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
121a251377Stedu * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
131a251377Stedu * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
141a251377Stedu * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
151a251377Stedu * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
161a251377Stedu * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
171a251377Stedu */
181a251377Stedu /*
191a251377Stedu * generic attribute support
201a251377Stedu */
211a251377Stedu
222d9f5a38Sderaadt #include <sys/mman.h>
232d9f5a38Sderaadt
2402303b0dSguenther #include <stdint.h>
251a251377Stedu #include <stdlib.h>
262d9f5a38Sderaadt #include <syslog.h>
271a251377Stedu #include <unistd.h>
281a251377Stedu #include <errno.h>
291a251377Stedu
301a251377Stedu #include <pthread.h>
31e10ae76eSmarc #include <pthread_np.h>
321a251377Stedu
331a251377Stedu #include "rthread.h"
341a251377Stedu
352b8233b0Smarc /*
362b8233b0Smarc * Note: stack_size + guard_size == total stack used
372b8233b0Smarc *
382b8233b0Smarc * pthread_attr_init MUST be called before any other attribute function
392b8233b0Smarc * for proper operation.
402b8233b0Smarc *
412b8233b0Smarc * Every call to pthread_attr_init MUST be matched with a call to
422b8233b0Smarc * pthread_attr_destroy to avoid leaking memory. This is an implementation
432b8233b0Smarc * requirement, not a POSIX requirement.
442b8233b0Smarc */
452b8233b0Smarc
461a251377Stedu int
pthread_attr_init(pthread_attr_t * attrp)471a251377Stedu pthread_attr_init(pthread_attr_t *attrp)
481a251377Stedu {
491a251377Stedu pthread_attr_t attr;
50a0a47db2Sguenther
51a0a47db2Sguenther /* make sure _rthread_attr_default has been initialized */
52a0a47db2Sguenther if (!_threads_ready)
53fe38b55cSguenther _rthread_init();
541a251377Stedu
5551223f90Skevlo attr = calloc(1, sizeof(*attr));
561a251377Stedu if (!attr)
571a251377Stedu return (errno);
5858dbb15cSguenther *attr = _rthread_attr_default;
591a251377Stedu *attrp = attr;
601a251377Stedu
611a251377Stedu return (0);
621a251377Stedu }
631a251377Stedu
641a251377Stedu int
pthread_attr_destroy(pthread_attr_t * attrp)651a251377Stedu pthread_attr_destroy(pthread_attr_t *attrp)
661a251377Stedu {
671a251377Stedu free(*attrp);
681a251377Stedu *attrp = NULL;
691a251377Stedu
701a251377Stedu return (0);
711a251377Stedu }
721a251377Stedu
731a251377Stedu int
pthread_attr_getguardsize(const pthread_attr_t * attrp,size_t * guardsize)742b8233b0Smarc pthread_attr_getguardsize(const pthread_attr_t *attrp, size_t *guardsize)
752b8233b0Smarc {
762b8233b0Smarc *guardsize = (*attrp)->guard_size;
772b8233b0Smarc
782b8233b0Smarc return (0);
792b8233b0Smarc }
802b8233b0Smarc
812b8233b0Smarc int
pthread_attr_setguardsize(pthread_attr_t * attrp,size_t guardsize)822b8233b0Smarc pthread_attr_setguardsize(pthread_attr_t *attrp, size_t guardsize)
832b8233b0Smarc {
842b8233b0Smarc (*attrp)->guard_size = guardsize;
852b8233b0Smarc
868e28ab97Sguenther return (0);
872b8233b0Smarc }
882b8233b0Smarc
892b8233b0Smarc int
pthread_attr_getdetachstate(const pthread_attr_t * attrp,int * detachstate)901a251377Stedu pthread_attr_getdetachstate(const pthread_attr_t *attrp, int *detachstate)
911a251377Stedu {
921a251377Stedu *detachstate = (*attrp)->detach_state;
931a251377Stedu
941a251377Stedu return (0);
951a251377Stedu }
961a251377Stedu
971a251377Stedu int
pthread_attr_setdetachstate(pthread_attr_t * attrp,int detachstate)981a251377Stedu pthread_attr_setdetachstate(pthread_attr_t *attrp, int detachstate)
991a251377Stedu {
1008e28ab97Sguenther int error;
10162feea1bSmarc
1028e28ab97Sguenther error = (detachstate == PTHREAD_CREATE_DETACHED ||
10362feea1bSmarc detachstate == PTHREAD_CREATE_JOINABLE) ? 0 : EINVAL;
1048e28ab97Sguenther if (error == 0)
1051a251377Stedu (*attrp)->detach_state = detachstate;
1061a251377Stedu
1078e28ab97Sguenther return (error);
1081a251377Stedu }
1091a251377Stedu
1101a251377Stedu int
pthread_attr_getstack(const pthread_attr_t * attrp,void ** stackaddr,size_t * stacksize)111ee620e50Stedu pthread_attr_getstack(const pthread_attr_t *attrp, void **stackaddr,
112ee620e50Stedu size_t *stacksize)
113ee620e50Stedu {
114ee620e50Stedu *stackaddr = (*attrp)->stack_addr;
115a0a47db2Sguenther *stacksize = (*attrp)->stack_size;
116ee620e50Stedu
117ee620e50Stedu return (0);
118ee620e50Stedu }
119ee620e50Stedu
120ee620e50Stedu int
pthread_attr_setstack(pthread_attr_t * attrp,void * stackaddr,size_t stacksize)121ee620e50Stedu pthread_attr_setstack(pthread_attr_t *attrp, void *stackaddr, size_t stacksize)
122ee620e50Stedu {
1238e28ab97Sguenther int error;
1242d9f5a38Sderaadt volatile char *p = stackaddr;
1252d9f5a38Sderaadt size_t i;
1262d9f5a38Sderaadt struct syslog_data data = SYSLOG_DATA_INIT;
1272d9f5a38Sderaadt
1282d9f5a38Sderaadt if (stacksize < PTHREAD_STACK_MIN) {
129*c1e618aaSbluhm syslog_r(LOG_ERR, &data,
1302d9f5a38Sderaadt "pthread_attr_setstack(%p, %zu): "
1312d9f5a38Sderaadt "stack size below min size %d",
1322d9f5a38Sderaadt stackaddr, stacksize, PTHREAD_STACK_MIN);
1332d9f5a38Sderaadt return (EINVAL);
1342d9f5a38Sderaadt }
135400e7491Sotto
13658dbb15cSguenther /*
1372d9f5a38Sderaadt * Make sure that the stack is page-aligned and a multiple
1382d9f5a38Sderaadt * of the page size
13958dbb15cSguenther */
1402d9f5a38Sderaadt if (((uintptr_t)stackaddr % PTHREAD_STACK_MIN) != 0
1412d9f5a38Sderaadt || (stacksize % PTHREAD_STACK_MIN) != 0) {
142*c1e618aaSbluhm syslog_r(LOG_ERR, &data,
1432d9f5a38Sderaadt "pthread_attr_setstack(%p, 0x%zx): "
1442d9f5a38Sderaadt "unaligned thread stack start and/or size",
1452d9f5a38Sderaadt stackaddr, stacksize);
14658dbb15cSguenther return (EINVAL);
1472d9f5a38Sderaadt }
1482d9f5a38Sderaadt
1492d9f5a38Sderaadt /*
1502d9f5a38Sderaadt * We are going to re-mmap() stackaddr to MAP_STACK, but only
1512d9f5a38Sderaadt * if the entire range [stackaddr, stackaddr+stacksize) consists
1522d9f5a38Sderaadt * of valid address that are mapped PROT_READ|PROT_WRITE.
1532d9f5a38Sderaadt * Test this by reading and writing every page.
1542d9f5a38Sderaadt *
1552d9f5a38Sderaadt * XXX: What if the caller has SIGSEGV blocked or ignored?
1562d9f5a38Sderaadt * Then we won't crash here when entering an invalid mapping.
1572d9f5a38Sderaadt */
1582d9f5a38Sderaadt for (i = 0; i < stacksize; i += PTHREAD_STACK_MIN) {
1592d9f5a38Sderaadt char val = p[i];
1602d9f5a38Sderaadt
1612d9f5a38Sderaadt p[i] = val;
1622d9f5a38Sderaadt }
1632d9f5a38Sderaadt
1642d9f5a38Sderaadt if (mmap(stackaddr, stacksize, PROT_READ|PROT_WRITE,
1652d9f5a38Sderaadt MAP_FIXED|MAP_STACK|MAP_ANON|MAP_PRIVATE, -1, 0) == MAP_FAILED) {
166*c1e618aaSbluhm syslog_r(LOG_ERR, &data,
1672d9f5a38Sderaadt "pthread_attr_setstack(%p, %zu): mmap error %m",
1682d9f5a38Sderaadt stackaddr, stacksize);
1692d9f5a38Sderaadt return (errno);
1702d9f5a38Sderaadt }
1712d9f5a38Sderaadt
1728e28ab97Sguenther if ((error = pthread_attr_setstackaddr(attrp, stackaddr)))
1738e28ab97Sguenther return (error);
174ee620e50Stedu (*attrp)->stack_size = stacksize;
175ee620e50Stedu
176ee620e50Stedu return (0);
177ee620e50Stedu }
178ee620e50Stedu
179ee620e50Stedu int
pthread_attr_getstacksize(const pthread_attr_t * attrp,size_t * stacksize)1801a251377Stedu pthread_attr_getstacksize(const pthread_attr_t *attrp, size_t *stacksize)
1811a251377Stedu {
18258dbb15cSguenther *stacksize = (*attrp)->stack_size;
1831a251377Stedu
1841a251377Stedu return (0);
1851a251377Stedu }
1861a251377Stedu
1871a251377Stedu int
pthread_attr_setstacksize(pthread_attr_t * attrp,size_t stacksize)1881a251377Stedu pthread_attr_setstacksize(pthread_attr_t *attrp, size_t stacksize)
1891a251377Stedu {
190a5511fa9Sguenther if (!_threads_ready) /* for ROUND_TO_PAGE */
191a5511fa9Sguenther _rthread_init();
192a5511fa9Sguenther
19358dbb15cSguenther if (stacksize < PTHREAD_STACK_MIN ||
19458dbb15cSguenther stacksize > ROUND_TO_PAGE(stacksize))
19558dbb15cSguenther return (EINVAL);
1961a251377Stedu (*attrp)->stack_size = stacksize;
1971a251377Stedu
1981a251377Stedu return (0);
1991a251377Stedu }
2001a251377Stedu
2011a251377Stedu int
pthread_attr_getstackaddr(const pthread_attr_t * attrp,void ** stackaddr)202ee620e50Stedu pthread_attr_getstackaddr(const pthread_attr_t *attrp, void **stackaddr)
203ee620e50Stedu {
204ee620e50Stedu *stackaddr = (*attrp)->stack_addr;
205ee620e50Stedu
206ee620e50Stedu return (0);
207ee620e50Stedu }
208ee620e50Stedu
209ee620e50Stedu int
pthread_attr_setstackaddr(pthread_attr_t * attrp,void * stackaddr)210ee620e50Stedu pthread_attr_setstackaddr(pthread_attr_t *attrp, void *stackaddr)
211ee620e50Stedu {
212a5511fa9Sguenther if (!_threads_ready)
213a5511fa9Sguenther _rthread_init(); /* for _thread_pagesize */
214a5511fa9Sguenther
21558dbb15cSguenther if (stackaddr == NULL || (uintptr_t)stackaddr & (_thread_pagesize - 1))
2168e28ab97Sguenther return (EINVAL);
217ee620e50Stedu (*attrp)->stack_addr = stackaddr;
218ee620e50Stedu
219ee620e50Stedu return (0);
220ee620e50Stedu }
2217567a0bfSguenther DEF_NONSTD(pthread_attr_setstackaddr);
222ee620e50Stedu
223ee620e50Stedu int
pthread_attr_getscope(const pthread_attr_t * attrp,int * contentionscope)2241a251377Stedu pthread_attr_getscope(const pthread_attr_t *attrp, int *contentionscope)
2251a251377Stedu {
2261a251377Stedu *contentionscope = (*attrp)->contention_scope;
2271a251377Stedu
2281a251377Stedu return (0);
2291a251377Stedu }
2301a251377Stedu
2311a251377Stedu int
pthread_attr_setscope(pthread_attr_t * attrp,int contentionscope)2321a251377Stedu pthread_attr_setscope(pthread_attr_t *attrp, int contentionscope)
2331a251377Stedu {
234b34e03caSfgsch if (contentionscope != PTHREAD_SCOPE_SYSTEM &&
235e9783381Sguenther contentionscope != PTHREAD_SCOPE_PROCESS)
236e9783381Sguenther return (EINVAL);
2371a251377Stedu (*attrp)->contention_scope = contentionscope;
2381a251377Stedu
2391a251377Stedu return (0);
2401a251377Stedu }
2418af1ee89Sotto
242