xref: /openbsd-src/lib/librthread/rthread_attr.c (revision c1e618aa95b061890a098580771ae05e12a10408)
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