17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
534709573Sraf  * Common Development and Distribution License (the "License").
634709573Sraf  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
2134709573Sraf 
227c478bd9Sstevel@tonic-gate /*
23d4204c85Sraf  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
27e56998eeSRobert Mustacchi /*
28ab618543SJohn Levon  * Copyright 2018, Joyent, Inc.
29e56998eeSRobert Mustacchi  */
30e56998eeSRobert Mustacchi 
317c478bd9Sstevel@tonic-gate #include "lint.h"
327c478bd9Sstevel@tonic-gate #include "thr_uberdata.h"
33ab618543SJohn Levon #include <sys/ctype.h>
34ab618543SJohn Levon #include <strings.h>
357c478bd9Sstevel@tonic-gate #include <sched.h>
367c478bd9Sstevel@tonic-gate 
3734709573Sraf /*
3834709573Sraf  * Default attribute object for pthread_create() with NULL attr pointer.
3934709573Sraf  * Note that the 'guardsize' field is initialized on the first call.
4034709573Sraf  */
4134709573Sraf const thrattr_t *
def_thrattr(void)4234709573Sraf def_thrattr(void)
4334709573Sraf {
4434709573Sraf 	static thrattr_t thrattr = {
4534709573Sraf 		0,				/* stksize */
4634709573Sraf 		NULL,				/* stkaddr */
4734709573Sraf 		PTHREAD_CREATE_JOINABLE,	/* detachstate */
4834709573Sraf 		PTHREAD_CREATE_NONDAEMON_NP,	/* daemonstate */
4934709573Sraf 		PTHREAD_SCOPE_PROCESS,		/* scope */
5034709573Sraf 		0,				/* prio */
5134709573Sraf 		SCHED_OTHER,			/* policy */
52d4204c85Sraf 		PTHREAD_INHERIT_SCHED,		/* inherit */
53ab618543SJohn Levon 		0,				/* guardsize */
54ab618543SJohn Levon 		{ 0 }				/* name */
5534709573Sraf 	};
5634709573Sraf 	if (thrattr.guardsize == 0)
5734709573Sraf 		thrattr.guardsize = _sysconf(_SC_PAGESIZE);
5834709573Sraf 	return (&thrattr);
5934709573Sraf }
6034709573Sraf 
617c478bd9Sstevel@tonic-gate /*
627c478bd9Sstevel@tonic-gate  * pthread_attr_init: allocates the attribute object and initializes it
637c478bd9Sstevel@tonic-gate  * with the default values.
647c478bd9Sstevel@tonic-gate  */
657257d1b4Sraf #pragma weak _pthread_attr_init = pthread_attr_init
667c478bd9Sstevel@tonic-gate int
pthread_attr_init(pthread_attr_t * attr)677257d1b4Sraf pthread_attr_init(pthread_attr_t *attr)
687c478bd9Sstevel@tonic-gate {
697c478bd9Sstevel@tonic-gate 	thrattr_t *ap;
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate 	if ((ap = lmalloc(sizeof (thrattr_t))) != NULL) {
7234709573Sraf 		*ap = *def_thrattr();
737c478bd9Sstevel@tonic-gate 		attr->__pthread_attrp = ap;
747c478bd9Sstevel@tonic-gate 		return (0);
757c478bd9Sstevel@tonic-gate 	}
767c478bd9Sstevel@tonic-gate 	return (ENOMEM);
777c478bd9Sstevel@tonic-gate }
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate /*
807c478bd9Sstevel@tonic-gate  * pthread_attr_destroy: frees the attribute object and invalidates it
817c478bd9Sstevel@tonic-gate  * with NULL value.
827c478bd9Sstevel@tonic-gate  */
837c478bd9Sstevel@tonic-gate int
pthread_attr_destroy(pthread_attr_t * attr)847257d1b4Sraf pthread_attr_destroy(pthread_attr_t *attr)
857c478bd9Sstevel@tonic-gate {
867c478bd9Sstevel@tonic-gate 	if (attr == NULL || attr->__pthread_attrp == NULL)
877c478bd9Sstevel@tonic-gate 		return (EINVAL);
887c478bd9Sstevel@tonic-gate 	lfree(attr->__pthread_attrp, sizeof (thrattr_t));
897c478bd9Sstevel@tonic-gate 	attr->__pthread_attrp = NULL;
907c478bd9Sstevel@tonic-gate 	return (0);
917c478bd9Sstevel@tonic-gate }
927c478bd9Sstevel@tonic-gate 
9334709573Sraf /*
947257d1b4Sraf  * pthread_attr_clone: make a copy of a pthread_attr_t.
9534709573Sraf  */
9634709573Sraf int
pthread_attr_clone(pthread_attr_t * attr,const pthread_attr_t * old_attr)977257d1b4Sraf pthread_attr_clone(pthread_attr_t *attr, const pthread_attr_t *old_attr)
9834709573Sraf {
9934709573Sraf 	thrattr_t *ap;
10034709573Sraf 	const thrattr_t *old_ap =
101ab618543SJohn Levon 	    old_attr ? old_attr->__pthread_attrp : def_thrattr();
10234709573Sraf 
10334709573Sraf 	if (old_ap == NULL)
10434709573Sraf 		return (EINVAL);
10534709573Sraf 	if ((ap = lmalloc(sizeof (thrattr_t))) == NULL)
10634709573Sraf 		return (ENOMEM);
10734709573Sraf 	*ap = *old_ap;
10834709573Sraf 	attr->__pthread_attrp = ap;
10934709573Sraf 	return (0);
11034709573Sraf }
11134709573Sraf 
11234709573Sraf /*
1137257d1b4Sraf  * pthread_attr_equal: compare two pthread_attr_t's, return 1 if equal.
11434709573Sraf  * A NULL pthread_attr_t pointer implies default attributes.
11534709573Sraf  * This is a consolidation-private interface, for librt.
11634709573Sraf  */
11734709573Sraf int
pthread_attr_equal(const pthread_attr_t * attr1,const pthread_attr_t * attr2)1187257d1b4Sraf pthread_attr_equal(const pthread_attr_t *attr1, const pthread_attr_t *attr2)
11934709573Sraf {
120ab618543SJohn Levon 	const thrattr_t *ap1 = attr1 ? attr1->__pthread_attrp : def_thrattr();
121ab618543SJohn Levon 	const thrattr_t *ap2 = attr2 ? attr2->__pthread_attrp : def_thrattr();
12234709573Sraf 
12334709573Sraf 	if (ap1 == NULL || ap2 == NULL)
12434709573Sraf 		return (0);
1258cd45542Sraf 	return (ap1 == ap2 || memcmp(ap1, ap2, sizeof (thrattr_t)) == 0);
12634709573Sraf }
12734709573Sraf 
1287c478bd9Sstevel@tonic-gate /*
1297c478bd9Sstevel@tonic-gate  * pthread_attr_setstacksize: sets the user stack size, minimum should
1307c478bd9Sstevel@tonic-gate  * be PTHREAD_STACK_MIN (MINSTACK).
1317c478bd9Sstevel@tonic-gate  * This is equivalent to stksize argument in thr_create().
1327c478bd9Sstevel@tonic-gate  */
1337c478bd9Sstevel@tonic-gate int
pthread_attr_setstacksize(pthread_attr_t * attr,size_t stacksize)1347257d1b4Sraf pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
1357c478bd9Sstevel@tonic-gate {
1367c478bd9Sstevel@tonic-gate 	thrattr_t *ap;
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
1397c478bd9Sstevel@tonic-gate 	    stacksize >= MINSTACK) {
1407c478bd9Sstevel@tonic-gate 		ap->stksize = stacksize;
1417c478bd9Sstevel@tonic-gate 		return (0);
1427c478bd9Sstevel@tonic-gate 	}
1437c478bd9Sstevel@tonic-gate 	return (EINVAL);
1447c478bd9Sstevel@tonic-gate }
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate /*
1477c478bd9Sstevel@tonic-gate  * pthread_attr_getstacksize: gets the user stack size.
1487c478bd9Sstevel@tonic-gate  */
1497257d1b4Sraf #pragma weak _pthread_attr_getstacksize = pthread_attr_getstacksize
1507c478bd9Sstevel@tonic-gate int
pthread_attr_getstacksize(const pthread_attr_t * attr,size_t * stacksize)1517257d1b4Sraf pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize)
1527c478bd9Sstevel@tonic-gate {
1537c478bd9Sstevel@tonic-gate 	thrattr_t *ap;
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
1567c478bd9Sstevel@tonic-gate 	    stacksize != NULL) {
1577c478bd9Sstevel@tonic-gate 		*stacksize = ap->stksize;
1587c478bd9Sstevel@tonic-gate 		return (0);
1597c478bd9Sstevel@tonic-gate 	}
1607c478bd9Sstevel@tonic-gate 	return (EINVAL);
1617c478bd9Sstevel@tonic-gate }
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate /*
1647c478bd9Sstevel@tonic-gate  * pthread_attr_setstackaddr: sets the user stack addr.
1657c478bd9Sstevel@tonic-gate  * This is equivalent to stkaddr argument in thr_create().
1667c478bd9Sstevel@tonic-gate  */
1677c478bd9Sstevel@tonic-gate int
pthread_attr_setstackaddr(pthread_attr_t * attr,void * stackaddr)1687257d1b4Sraf pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr)
1697c478bd9Sstevel@tonic-gate {
1707c478bd9Sstevel@tonic-gate 	thrattr_t *ap;
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL) {
1737c478bd9Sstevel@tonic-gate 		ap->stkaddr = stackaddr;
1747c478bd9Sstevel@tonic-gate 		return (0);
1757c478bd9Sstevel@tonic-gate 	}
1767c478bd9Sstevel@tonic-gate 	return (EINVAL);
1777c478bd9Sstevel@tonic-gate }
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate /*
1807c478bd9Sstevel@tonic-gate  * pthread_attr_getstackaddr: gets the user stack addr.
1817c478bd9Sstevel@tonic-gate  */
1827257d1b4Sraf #pragma weak _pthread_attr_getstackaddr = pthread_attr_getstackaddr
1837c478bd9Sstevel@tonic-gate int
pthread_attr_getstackaddr(const pthread_attr_t * attr,void ** stackaddr)1847257d1b4Sraf pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr)
1857c478bd9Sstevel@tonic-gate {
1867c478bd9Sstevel@tonic-gate 	thrattr_t *ap;
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
1897c478bd9Sstevel@tonic-gate 	    stackaddr != NULL) {
1907c478bd9Sstevel@tonic-gate 		*stackaddr = ap->stkaddr;
1917c478bd9Sstevel@tonic-gate 		return (0);
1927c478bd9Sstevel@tonic-gate 	}
1937c478bd9Sstevel@tonic-gate 	return (EINVAL);
1947c478bd9Sstevel@tonic-gate }
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate /*
19734709573Sraf  * pthread_attr_setdetachstate: sets the detach state to DETACHED or JOINABLE.
19834709573Sraf  * PTHREAD_CREATE_DETACHED is equivalent to thr_create(THR_DETACHED).
1997c478bd9Sstevel@tonic-gate  */
2007c478bd9Sstevel@tonic-gate int
pthread_attr_setdetachstate(pthread_attr_t * attr,int detachstate)2017257d1b4Sraf pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
2027c478bd9Sstevel@tonic-gate {
2037c478bd9Sstevel@tonic-gate 	thrattr_t *ap;
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
2067c478bd9Sstevel@tonic-gate 	    (detachstate == PTHREAD_CREATE_DETACHED ||
2077c478bd9Sstevel@tonic-gate 	    detachstate == PTHREAD_CREATE_JOINABLE)) {
2087c478bd9Sstevel@tonic-gate 		ap->detachstate = detachstate;
2097c478bd9Sstevel@tonic-gate 		return (0);
2107c478bd9Sstevel@tonic-gate 	}
2117c478bd9Sstevel@tonic-gate 	return (EINVAL);
2127c478bd9Sstevel@tonic-gate }
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate /*
2157c478bd9Sstevel@tonic-gate  * pthread_attr_getdetachstate: gets the detach state.
2167c478bd9Sstevel@tonic-gate  */
2177257d1b4Sraf #pragma weak _pthread_attr_getdetachstate = pthread_attr_getdetachstate
2187c478bd9Sstevel@tonic-gate int
pthread_attr_getdetachstate(const pthread_attr_t * attr,int * detachstate)2197257d1b4Sraf pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
2207c478bd9Sstevel@tonic-gate {
2217c478bd9Sstevel@tonic-gate 	thrattr_t *ap;
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
2247c478bd9Sstevel@tonic-gate 	    detachstate != NULL) {
2257c478bd9Sstevel@tonic-gate 		*detachstate = ap->detachstate;
2267c478bd9Sstevel@tonic-gate 		return (0);
2277c478bd9Sstevel@tonic-gate 	}
2287c478bd9Sstevel@tonic-gate 	return (EINVAL);
2297c478bd9Sstevel@tonic-gate }
2307c478bd9Sstevel@tonic-gate 
23134709573Sraf /*
23234709573Sraf  * pthread_attr_setdaemonstate_np: sets the daemon state to DAEMON or NONDAEMON.
23334709573Sraf  * PTHREAD_CREATE_DAEMON is equivalent to thr_create(THR_DAEMON).
234f841f6adSraf  * For now, this is a private interface in libc.
23534709573Sraf  */
23634709573Sraf int
pthread_attr_setdaemonstate_np(pthread_attr_t * attr,int daemonstate)2377257d1b4Sraf pthread_attr_setdaemonstate_np(pthread_attr_t *attr, int daemonstate)
23834709573Sraf {
23934709573Sraf 	thrattr_t *ap;
24034709573Sraf 
24134709573Sraf 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
24234709573Sraf 	    (daemonstate == PTHREAD_CREATE_DAEMON_NP ||
24334709573Sraf 	    daemonstate == PTHREAD_CREATE_NONDAEMON_NP)) {
24434709573Sraf 		ap->daemonstate = daemonstate;
24534709573Sraf 		return (0);
24634709573Sraf 	}
24734709573Sraf 	return (EINVAL);
24834709573Sraf }
24934709573Sraf 
25034709573Sraf /*
25134709573Sraf  * pthread_attr_getdaemonstate_np: gets the daemon state.
252e56998eeSRobert Mustacchi  * For now, this is a private interface in libc, but it is exposed in the
253e56998eeSRobert Mustacchi  * mapfile for the purposes of testing only.
25434709573Sraf  */
25534709573Sraf int
pthread_attr_getdaemonstate_np(const pthread_attr_t * attr,int * daemonstate)2567257d1b4Sraf pthread_attr_getdaemonstate_np(const pthread_attr_t *attr, int *daemonstate)
25734709573Sraf {
25834709573Sraf 	thrattr_t *ap;
25934709573Sraf 
26034709573Sraf 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
26134709573Sraf 	    daemonstate != NULL) {
26234709573Sraf 		*daemonstate = ap->daemonstate;
26334709573Sraf 		return (0);
26434709573Sraf 	}
26534709573Sraf 	return (EINVAL);
26634709573Sraf }
26734709573Sraf 
2687c478bd9Sstevel@tonic-gate /*
2697c478bd9Sstevel@tonic-gate  * pthread_attr_setscope: sets the scope to SYSTEM or PROCESS.
2707c478bd9Sstevel@tonic-gate  * This is equivalent to setting THR_BOUND flag in thr_create().
2717c478bd9Sstevel@tonic-gate  */
2727c478bd9Sstevel@tonic-gate int
pthread_attr_setscope(pthread_attr_t * attr,int scope)2737257d1b4Sraf pthread_attr_setscope(pthread_attr_t *attr, int scope)
2747c478bd9Sstevel@tonic-gate {
2757c478bd9Sstevel@tonic-gate 	thrattr_t *ap;
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
2787c478bd9Sstevel@tonic-gate 	    (scope == PTHREAD_SCOPE_SYSTEM ||
2797c478bd9Sstevel@tonic-gate 	    scope == PTHREAD_SCOPE_PROCESS)) {
2807c478bd9Sstevel@tonic-gate 		ap->scope = scope;
2817c478bd9Sstevel@tonic-gate 		return (0);
2827c478bd9Sstevel@tonic-gate 	}
2837c478bd9Sstevel@tonic-gate 	return (EINVAL);
2847c478bd9Sstevel@tonic-gate }
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate /*
2877c478bd9Sstevel@tonic-gate  * pthread_attr_getscope: gets the scheduling scope.
2887c478bd9Sstevel@tonic-gate  */
2897257d1b4Sraf #pragma weak _pthread_attr_getscope = pthread_attr_getscope
2907c478bd9Sstevel@tonic-gate int
pthread_attr_getscope(const pthread_attr_t * attr,int * scope)2917257d1b4Sraf pthread_attr_getscope(const pthread_attr_t *attr, int *scope)
2927c478bd9Sstevel@tonic-gate {
2937c478bd9Sstevel@tonic-gate 	thrattr_t *ap;
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
2967c478bd9Sstevel@tonic-gate 	    scope != NULL) {
2977c478bd9Sstevel@tonic-gate 		*scope = ap->scope;
2987c478bd9Sstevel@tonic-gate 		return (0);
2997c478bd9Sstevel@tonic-gate 	}
3007c478bd9Sstevel@tonic-gate 	return (EINVAL);
3017c478bd9Sstevel@tonic-gate }
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate /*
3047c478bd9Sstevel@tonic-gate  * pthread_attr_setinheritsched: sets the scheduling parameters to be
3057c478bd9Sstevel@tonic-gate  * EXPLICIT or INHERITED from parent thread.
3067c478bd9Sstevel@tonic-gate  */
3077c478bd9Sstevel@tonic-gate int
pthread_attr_setinheritsched(pthread_attr_t * attr,int inherit)3087257d1b4Sraf pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit)
3097c478bd9Sstevel@tonic-gate {
3107c478bd9Sstevel@tonic-gate 	thrattr_t *ap;
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
3137c478bd9Sstevel@tonic-gate 	    (inherit == PTHREAD_EXPLICIT_SCHED ||
3147c478bd9Sstevel@tonic-gate 	    inherit == PTHREAD_INHERIT_SCHED)) {
3157c478bd9Sstevel@tonic-gate 		ap->inherit = inherit;
3167c478bd9Sstevel@tonic-gate 		return (0);
3177c478bd9Sstevel@tonic-gate 	}
3187c478bd9Sstevel@tonic-gate 	return (EINVAL);
3197c478bd9Sstevel@tonic-gate }
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate /*
3227c478bd9Sstevel@tonic-gate  * pthread_attr_getinheritsched: gets the scheduling inheritance.
3237c478bd9Sstevel@tonic-gate  */
3247257d1b4Sraf #pragma weak _pthread_attr_getinheritsched = pthread_attr_getinheritsched
3257c478bd9Sstevel@tonic-gate int
pthread_attr_getinheritsched(const pthread_attr_t * attr,int * inherit)3267257d1b4Sraf pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inherit)
3277c478bd9Sstevel@tonic-gate {
3287c478bd9Sstevel@tonic-gate 	thrattr_t *ap;
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
3317c478bd9Sstevel@tonic-gate 	    inherit != NULL) {
3327c478bd9Sstevel@tonic-gate 		*inherit = ap->inherit;
3337c478bd9Sstevel@tonic-gate 		return (0);
3347c478bd9Sstevel@tonic-gate 	}
3357c478bd9Sstevel@tonic-gate 	return (EINVAL);
3367c478bd9Sstevel@tonic-gate }
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate /*
339d4204c85Sraf  * pthread_attr_setschedpolicy: sets the scheduling policy.
3407c478bd9Sstevel@tonic-gate  */
3417c478bd9Sstevel@tonic-gate int
pthread_attr_setschedpolicy(pthread_attr_t * attr,int policy)3427257d1b4Sraf pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
3437c478bd9Sstevel@tonic-gate {
3447c478bd9Sstevel@tonic-gate 	thrattr_t *ap;
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
347d4204c85Sraf 	    policy != SCHED_SYS && get_info_by_policy(policy) != NULL) {
3487c478bd9Sstevel@tonic-gate 		ap->policy = policy;
3497c478bd9Sstevel@tonic-gate 		return (0);
3507c478bd9Sstevel@tonic-gate 	}
3517c478bd9Sstevel@tonic-gate 	return (EINVAL);
3527c478bd9Sstevel@tonic-gate }
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate /*
3557c478bd9Sstevel@tonic-gate  * pthread_attr_getpolicy: gets the scheduling policy.
3567c478bd9Sstevel@tonic-gate  */
3577257d1b4Sraf #pragma weak _pthread_attr_getschedpolicy = pthread_attr_getschedpolicy
3587c478bd9Sstevel@tonic-gate int
pthread_attr_getschedpolicy(const pthread_attr_t * attr,int * policy)3597257d1b4Sraf pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
3607c478bd9Sstevel@tonic-gate {
3617c478bd9Sstevel@tonic-gate 	thrattr_t *ap;
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
3647c478bd9Sstevel@tonic-gate 	    policy != NULL) {
3657c478bd9Sstevel@tonic-gate 		*policy = ap->policy;
3667c478bd9Sstevel@tonic-gate 		return (0);
3677c478bd9Sstevel@tonic-gate 	}
3687c478bd9Sstevel@tonic-gate 	return (EINVAL);
3697c478bd9Sstevel@tonic-gate }
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate /*
3727c478bd9Sstevel@tonic-gate  * pthread_attr_setschedparam: sets the scheduling parameters.
3737c478bd9Sstevel@tonic-gate  * Currently, we support priority only.
3747c478bd9Sstevel@tonic-gate  */
3757c478bd9Sstevel@tonic-gate int
pthread_attr_setschedparam(pthread_attr_t * attr,const struct sched_param * param)3767257d1b4Sraf pthread_attr_setschedparam(pthread_attr_t *attr,
377e56998eeSRobert Mustacchi     const struct sched_param *param)
3787c478bd9Sstevel@tonic-gate {
3797c478bd9Sstevel@tonic-gate 	thrattr_t *ap;
3807c478bd9Sstevel@tonic-gate 
381d4204c85Sraf 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
382d4204c85Sraf 	    param != NULL) {
383d4204c85Sraf 		ap->prio = param->sched_priority;
384d4204c85Sraf 		return (0);
3857c478bd9Sstevel@tonic-gate 	}
386d4204c85Sraf 	return (EINVAL);
3877c478bd9Sstevel@tonic-gate }
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate /*
3907c478bd9Sstevel@tonic-gate  * pthread_attr_getschedparam: gets the scheduling parameters.
3917c478bd9Sstevel@tonic-gate  * Currently, only priority is defined as sched parameter.
3927c478bd9Sstevel@tonic-gate  */
3937257d1b4Sraf #pragma weak _pthread_attr_getschedparam = pthread_attr_getschedparam
3947c478bd9Sstevel@tonic-gate int
pthread_attr_getschedparam(const pthread_attr_t * attr,struct sched_param * param)3957257d1b4Sraf pthread_attr_getschedparam(const pthread_attr_t *attr,
396e56998eeSRobert Mustacchi     struct sched_param *param)
3977c478bd9Sstevel@tonic-gate {
3987c478bd9Sstevel@tonic-gate 	thrattr_t *ap;
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
4017c478bd9Sstevel@tonic-gate 	    param != NULL) {
4027c478bd9Sstevel@tonic-gate 		param->sched_priority = ap->prio;
4037c478bd9Sstevel@tonic-gate 		return (0);
4047c478bd9Sstevel@tonic-gate 	}
4057c478bd9Sstevel@tonic-gate 	return (EINVAL);
4067c478bd9Sstevel@tonic-gate }
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate /*
4097c478bd9Sstevel@tonic-gate  * UNIX98
4107c478bd9Sstevel@tonic-gate  * pthread_attr_setguardsize: sets the guardsize
4117c478bd9Sstevel@tonic-gate  */
4127c478bd9Sstevel@tonic-gate int
pthread_attr_setguardsize(pthread_attr_t * attr,size_t guardsize)4137257d1b4Sraf pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize)
4147c478bd9Sstevel@tonic-gate {
4157c478bd9Sstevel@tonic-gate 	thrattr_t *ap;
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL) {
4187c478bd9Sstevel@tonic-gate 		ap->guardsize = guardsize;
4197c478bd9Sstevel@tonic-gate 		return (0);
4207c478bd9Sstevel@tonic-gate 	}
4217c478bd9Sstevel@tonic-gate 	return (EINVAL);
4227c478bd9Sstevel@tonic-gate }
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate /*
4257c478bd9Sstevel@tonic-gate  * UNIX98
4267c478bd9Sstevel@tonic-gate  * pthread_attr_getguardsize: gets the guardsize
4277c478bd9Sstevel@tonic-gate  */
4287c478bd9Sstevel@tonic-gate int
pthread_attr_getguardsize(const pthread_attr_t * attr,size_t * guardsize)4297257d1b4Sraf pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize)
4307c478bd9Sstevel@tonic-gate {
4317c478bd9Sstevel@tonic-gate 	thrattr_t *ap;
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
4347c478bd9Sstevel@tonic-gate 	    guardsize != NULL) {
4357c478bd9Sstevel@tonic-gate 		*guardsize = ap->guardsize;
4367c478bd9Sstevel@tonic-gate 		return (0);
4377c478bd9Sstevel@tonic-gate 	}
4387c478bd9Sstevel@tonic-gate 	return (EINVAL);
4397c478bd9Sstevel@tonic-gate }
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate /*
4427c478bd9Sstevel@tonic-gate  * pthread_attr_setstack: sets the user stack addr and stack size.
4437c478bd9Sstevel@tonic-gate  * This is equivalent to the stack_base and stack_size arguments
4447c478bd9Sstevel@tonic-gate  * to thr_create().
4457c478bd9Sstevel@tonic-gate  */
4467c478bd9Sstevel@tonic-gate int
pthread_attr_setstack(pthread_attr_t * attr,void * stackaddr,size_t stacksize)4477257d1b4Sraf pthread_attr_setstack(pthread_attr_t *attr,
448e56998eeSRobert Mustacchi     void *stackaddr, size_t stacksize)
4497c478bd9Sstevel@tonic-gate {
4507c478bd9Sstevel@tonic-gate 	thrattr_t *ap;
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
4537c478bd9Sstevel@tonic-gate 	    stacksize >= MINSTACK) {
4547c478bd9Sstevel@tonic-gate 		ap->stkaddr = stackaddr;
4557c478bd9Sstevel@tonic-gate 		ap->stksize = stacksize;
456373d25a2SRoger A. Faulkner 		if (stackaddr != NULL &&
457373d25a2SRoger A. Faulkner 		    setup_top_frame(stackaddr, stacksize, NULL) == NULL)
458373d25a2SRoger A. Faulkner 			return (EACCES);
4597c478bd9Sstevel@tonic-gate 		return (0);
4607c478bd9Sstevel@tonic-gate 	}
4617c478bd9Sstevel@tonic-gate 	return (EINVAL);
4627c478bd9Sstevel@tonic-gate }
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate /*
4657c478bd9Sstevel@tonic-gate  * pthread_attr_getstack: gets the user stack addr and stack size.
4667c478bd9Sstevel@tonic-gate  */
4677c478bd9Sstevel@tonic-gate int
pthread_attr_getstack(const pthread_attr_t * attr,void ** stackaddr,size_t * stacksize)4687257d1b4Sraf pthread_attr_getstack(const pthread_attr_t *attr,
469e56998eeSRobert Mustacchi     void **stackaddr, size_t *stacksize)
4707c478bd9Sstevel@tonic-gate {
4717c478bd9Sstevel@tonic-gate 	thrattr_t *ap;
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
4747c478bd9Sstevel@tonic-gate 	    stackaddr != NULL && stacksize != NULL) {
4757c478bd9Sstevel@tonic-gate 		*stackaddr = ap->stkaddr;
4767c478bd9Sstevel@tonic-gate 		*stacksize = ap->stksize;
4777c478bd9Sstevel@tonic-gate 		return (0);
4787c478bd9Sstevel@tonic-gate 	}
4797c478bd9Sstevel@tonic-gate 	return (EINVAL);
4807c478bd9Sstevel@tonic-gate }
481e56998eeSRobert Mustacchi 
482ab618543SJohn Levon int
pthread_attr_setname_np(pthread_attr_t * attr,const char * name)483ab618543SJohn Levon pthread_attr_setname_np(pthread_attr_t *attr, const char *name)
484ab618543SJohn Levon {
485ab618543SJohn Levon 	thrattr_t *ap;
486ab618543SJohn Levon 
487ab618543SJohn Levon 	if (attr == NULL || (ap = attr->__pthread_attrp) == NULL)
488ab618543SJohn Levon 		return (EINVAL);
489ab618543SJohn Levon 
490ab618543SJohn Levon 	if (name == NULL) {
491ab618543SJohn Levon 		bzero(ap->name, sizeof (ap->name));
492ab618543SJohn Levon 		return (0);
493ab618543SJohn Levon 	}
494ab618543SJohn Levon 
495ab618543SJohn Levon 	if (strlen(name) >= sizeof (ap->name))
496ab618543SJohn Levon 		return (ERANGE);
497ab618543SJohn Levon 
498ab618543SJohn Levon 	/*
499ab618543SJohn Levon 	 * We really want the ASCII version of isprint() here...
500ab618543SJohn Levon 	 */
501ab618543SJohn Levon 	for (size_t i = 0; name[i] != '\0'; i++) {
502ab618543SJohn Levon 		if (!ISPRINT(name[i]))
503ab618543SJohn Levon 			return (EINVAL);
504ab618543SJohn Levon 	}
505ab618543SJohn Levon 
506ab618543SJohn Levon 	/*
507ab618543SJohn Levon 	 * not having garbage after the end of the string simplifies attr
508ab618543SJohn Levon 	 * comparison
509ab618543SJohn Levon 	 */
510ab618543SJohn Levon 	bzero(ap->name, sizeof (ap->name));
511ab618543SJohn Levon 	(void) strlcpy(ap->name, name, sizeof (ap->name));
512ab618543SJohn Levon 	return (0);
513ab618543SJohn Levon }
514ab618543SJohn Levon 
515ab618543SJohn Levon int
pthread_attr_getname_np(pthread_attr_t * attr,char * buf,size_t len)516ab618543SJohn Levon pthread_attr_getname_np(pthread_attr_t *attr, char *buf, size_t len)
517ab618543SJohn Levon {
518ab618543SJohn Levon 	thrattr_t *ap;
519ab618543SJohn Levon 
520ab618543SJohn Levon 	if (buf == NULL || attr == NULL ||
521ab618543SJohn Levon 	    (ap = attr->__pthread_attrp) == NULL)
522ab618543SJohn Levon 		return (EINVAL);
523ab618543SJohn Levon 
524ab618543SJohn Levon 	if (strlcpy(buf, ap->name, len) > len)
525ab618543SJohn Levon 		return (ERANGE);
526ab618543SJohn Levon 	return (0);
527ab618543SJohn Levon }
528ab618543SJohn Levon 
529e56998eeSRobert Mustacchi /*
530e56998eeSRobert Mustacchi  * This function is a common BSD extension to pthread which is used to obtain
531e56998eeSRobert Mustacchi  * the attributes of a thread that might have changed after its creation, for
532*25befe07SPeter Tribble  * example, its stack address.
533e56998eeSRobert Mustacchi  *
534e56998eeSRobert Mustacchi  * Note, there is no setattr analogue, nor do we desire to add one at this time.
535e56998eeSRobert Mustacchi  * Similarly there is no native threads API analogue (nor should we add one for
536e56998eeSRobert Mustacchi  * C11).
537e56998eeSRobert Mustacchi  *
538e56998eeSRobert Mustacchi  * The astute reader may note that there is a GNU version of this called
539*25befe07SPeter Tribble  * pthread_getattr_np(). The two functions are similar, but subtly different in
540*25befe07SPeter Tribble  * a rather important way. While pthread_attr_get_np() expects to be given
541*25befe07SPeter Tribble  * a pthread_attr_t that has had pthread_attr_init() called on it,
542e56998eeSRobert Mustacchi  * pthread_getattr_np() does not. However, on GNU systems, where the function
543e56998eeSRobert Mustacchi  * originates, the pthread_attr_t is not opaque and thus it is entirely safe to
544e56998eeSRobert Mustacchi  * both call pthread_attr_init() and then call pthread_getattr_np() on the same
545e56998eeSRobert Mustacchi  * attributes object. On illumos, since the pthread_attr_t is opaque, that would
546e56998eeSRobert Mustacchi  * be a memory leak. As such, we don't provide it.
547e56998eeSRobert Mustacchi  */
548e56998eeSRobert Mustacchi int
pthread_attr_get_np(pthread_t tid,pthread_attr_t * attr)549e56998eeSRobert Mustacchi pthread_attr_get_np(pthread_t tid, pthread_attr_t *attr)
550e56998eeSRobert Mustacchi {
551e56998eeSRobert Mustacchi 	int ret;
552e56998eeSRobert Mustacchi 	ulwp_t *self = curthread;
553e56998eeSRobert Mustacchi 	uberdata_t *udp = self->ul_uberdata;
554e56998eeSRobert Mustacchi 	ulwp_t *target = NULL;
555e56998eeSRobert Mustacchi 	thrattr_t *ap;
556e56998eeSRobert Mustacchi 
557e56998eeSRobert Mustacchi 	/*
558e56998eeSRobert Mustacchi 	 * To ensure that information about the target thread does not change or
559*25befe07SPeter Tribble 	 * disappear while we're trying to interrogate it, we grab the ulwp
560e56998eeSRobert Mustacchi 	 * lock.
561e56998eeSRobert Mustacchi 	 */
562e56998eeSRobert Mustacchi 	if (self->ul_lwpid == tid) {
563e56998eeSRobert Mustacchi 		ulwp_lock(self, udp);
564e56998eeSRobert Mustacchi 		target = self;
565e56998eeSRobert Mustacchi 	} else {
566e56998eeSRobert Mustacchi 		target = find_lwp(tid);
567e56998eeSRobert Mustacchi 		if (target == NULL)
568e56998eeSRobert Mustacchi 			return (ESRCH);
569e56998eeSRobert Mustacchi 	}
570e56998eeSRobert Mustacchi 
571e56998eeSRobert Mustacchi 	if (attr == NULL) {
572e56998eeSRobert Mustacchi 		ret = EINVAL;
573e56998eeSRobert Mustacchi 		goto out;
574e56998eeSRobert Mustacchi 	}
575e56998eeSRobert Mustacchi 
576e56998eeSRobert Mustacchi 	if ((ap = attr->__pthread_attrp) == NULL) {
577e56998eeSRobert Mustacchi 		ret = EINVAL;
578e56998eeSRobert Mustacchi 		goto out;
579e56998eeSRobert Mustacchi 	}
580e56998eeSRobert Mustacchi 
581e56998eeSRobert Mustacchi 	ap->stksize = target->ul_stksiz;
582e56998eeSRobert Mustacchi 	ap->stkaddr = target->ul_stk;
583e56998eeSRobert Mustacchi 	if (target->ul_usropts & THR_DETACHED) {
584e56998eeSRobert Mustacchi 		ap->detachstate = PTHREAD_CREATE_DETACHED;
585e56998eeSRobert Mustacchi 	} else {
586e56998eeSRobert Mustacchi 		ap->detachstate = PTHREAD_CREATE_JOINABLE;
587e56998eeSRobert Mustacchi 	}
588e56998eeSRobert Mustacchi 
589e56998eeSRobert Mustacchi 	if (target->ul_usropts & THR_DAEMON) {
590e56998eeSRobert Mustacchi 		ap->daemonstate = PTHREAD_CREATE_DAEMON_NP;
591e56998eeSRobert Mustacchi 	} else {
592e56998eeSRobert Mustacchi 		ap->daemonstate = PTHREAD_CREATE_NONDAEMON_NP;
593e56998eeSRobert Mustacchi 	}
594e56998eeSRobert Mustacchi 
595e56998eeSRobert Mustacchi 	if (target->ul_usropts & THR_BOUND) {
596e56998eeSRobert Mustacchi 		ap->scope = PTHREAD_SCOPE_SYSTEM;
597e56998eeSRobert Mustacchi 	} else {
598e56998eeSRobert Mustacchi 		ap->scope = PTHREAD_SCOPE_PROCESS;
599e56998eeSRobert Mustacchi 	}
600e56998eeSRobert Mustacchi 	ap->prio = target->ul_pri;
601e56998eeSRobert Mustacchi 	ap->policy = target->ul_policy;
602e56998eeSRobert Mustacchi 	ap->inherit = target->ul_ptinherit;
603e56998eeSRobert Mustacchi 	ap->guardsize = target->ul_guardsize;
604ab618543SJohn Levon 	(void) pthread_getname_np(tid, ap->name, sizeof (ap->name));
605e56998eeSRobert Mustacchi 
606e56998eeSRobert Mustacchi 	ret = 0;
607e56998eeSRobert Mustacchi out:
608e56998eeSRobert Mustacchi 	ulwp_unlock(target, udp);
609e56998eeSRobert Mustacchi 	return (ret);
610e56998eeSRobert Mustacchi }
611