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