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  */
26e56998eeSRobert Mustacchi /*
27ab618543SJohn Levon  * Copyright 2018 Joyent, Inc.
28e56998eeSRobert Mustacchi  */
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate #include "lint.h"
317c478bd9Sstevel@tonic-gate #include "thr_uberdata.h"
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate /*
347c478bd9Sstevel@tonic-gate  * pthread_once related data
357c478bd9Sstevel@tonic-gate  * This structure is exported as pthread_once_t in pthread.h.
367c478bd9Sstevel@tonic-gate  * We export only the size of this structure. so check
377c478bd9Sstevel@tonic-gate  * pthread_once_t in pthread.h before making a change here.
387c478bd9Sstevel@tonic-gate  */
397c478bd9Sstevel@tonic-gate typedef struct  __once {
407c478bd9Sstevel@tonic-gate 	mutex_t	mlock;
417c478bd9Sstevel@tonic-gate 	union {
427c478bd9Sstevel@tonic-gate 		uint32_t	pad32_flag[2];
437c478bd9Sstevel@tonic-gate 		uint64_t	pad64_flag;
447c478bd9Sstevel@tonic-gate 	} oflag;
457c478bd9Sstevel@tonic-gate } __once_t;
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate #define	once_flag	oflag.pad32_flag[1]
487c478bd9Sstevel@tonic-gate 
49e56998eeSRobert Mustacchi static int
_thr_setinherit(pthread_t tid,int inherit)50e56998eeSRobert Mustacchi _thr_setinherit(pthread_t tid, int inherit)
51e56998eeSRobert Mustacchi {
52e56998eeSRobert Mustacchi 	ulwp_t *ulwp;
53e56998eeSRobert Mustacchi 	int error = 0;
54e56998eeSRobert Mustacchi 
55e56998eeSRobert Mustacchi 	if ((ulwp = find_lwp(tid)) == NULL) {
56e56998eeSRobert Mustacchi 		error = ESRCH;
57e56998eeSRobert Mustacchi 	} else {
58e56998eeSRobert Mustacchi 		ulwp->ul_ptinherit = inherit;
59e56998eeSRobert Mustacchi 		ulwp_unlock(ulwp, curthread->ul_uberdata);
60e56998eeSRobert Mustacchi 	}
61e56998eeSRobert Mustacchi 
62e56998eeSRobert Mustacchi 	return (error);
63e56998eeSRobert Mustacchi }
64e56998eeSRobert Mustacchi 
65d4204c85Sraf static int
_thr_setparam(pthread_t tid,int policy,int prio)66d4204c85Sraf _thr_setparam(pthread_t tid, int policy, int prio)
67d4204c85Sraf {
68d4204c85Sraf 	ulwp_t *ulwp;
69d4204c85Sraf 	id_t cid;
70d4204c85Sraf 	int error = 0;
71d4204c85Sraf 
72d4204c85Sraf 	if ((ulwp = find_lwp(tid)) == NULL) {
73d4204c85Sraf 		error = ESRCH;
74d4204c85Sraf 	} else {
75d4204c85Sraf 		if (policy == ulwp->ul_policy &&
76d4204c85Sraf 		    (policy == SCHED_FIFO || policy == SCHED_RR) &&
77d4204c85Sraf 		    ulwp->ul_epri != 0) {
78d4204c85Sraf 			/*
79d4204c85Sraf 			 * Don't change the ceiling priority,
80d4204c85Sraf 			 * just the base priority.
81d4204c85Sraf 			 */
82d4204c85Sraf 			if (prio > ulwp->ul_epri)
83d4204c85Sraf 				error = EPERM;
84d4204c85Sraf 			else
85d4204c85Sraf 				ulwp->ul_pri = prio;
86d4204c85Sraf 		} else if ((cid = setparam(P_LWPID, tid, policy, prio)) == -1) {
87d4204c85Sraf 			error = errno;
88d4204c85Sraf 		} else {
89e84487aeSraf 			if (policy == SCHED_FIFO || policy == SCHED_RR)
90e84487aeSraf 				ulwp->ul_rtclassid = cid;
91d4204c85Sraf 			ulwp->ul_cid = cid;
92d4204c85Sraf 			ulwp->ul_pri = prio;
937257d1b4Sraf 			membar_producer();
94d4204c85Sraf 			ulwp->ul_policy = policy;
95d4204c85Sraf 		}
96d4204c85Sraf 		ulwp_unlock(ulwp, curthread->ul_uberdata);
97d4204c85Sraf 	}
98d4204c85Sraf 	return (error);
99d4204c85Sraf }
100d4204c85Sraf 
1017c478bd9Sstevel@tonic-gate /*
1027c478bd9Sstevel@tonic-gate  * pthread_create: creates a thread in the current process.
1037c478bd9Sstevel@tonic-gate  * calls common _thrp_create() after copying the attributes.
1047c478bd9Sstevel@tonic-gate  */
1057257d1b4Sraf #pragma weak _pthread_create = pthread_create
1067c478bd9Sstevel@tonic-gate int
pthread_create(pthread_t * thread,const pthread_attr_t * attr,void * (* start_routine)(void *),void * arg)1077257d1b4Sraf pthread_create(pthread_t *thread, const pthread_attr_t *attr,
108e56998eeSRobert Mustacchi     void * (*start_routine)(void *), void *arg)
1097c478bd9Sstevel@tonic-gate {
1107c478bd9Sstevel@tonic-gate 	ulwp_t		*self = curthread;
11134709573Sraf 	const thrattr_t	*ap = attr? attr->__pthread_attrp : def_thrattr();
112d4204c85Sraf 	const pcclass_t	*pccp;
1137c478bd9Sstevel@tonic-gate 	long		flag;
1147c478bd9Sstevel@tonic-gate 	pthread_t	tid;
1157c478bd9Sstevel@tonic-gate 	int		error;
116d4204c85Sraf 
117d4204c85Sraf 	update_sched(self);
1187c478bd9Sstevel@tonic-gate 
11934709573Sraf 	if (ap == NULL)
1207c478bd9Sstevel@tonic-gate 		return (EINVAL);
1217c478bd9Sstevel@tonic-gate 
122d4204c85Sraf 	/* validate explicit scheduling attributes */
123d4204c85Sraf 	if (ap->inherit == PTHREAD_EXPLICIT_SCHED &&
124d4204c85Sraf 	    (ap->policy == SCHED_SYS ||
125d4204c85Sraf 	    (pccp = get_info_by_policy(ap->policy)) == NULL ||
126d4204c85Sraf 	    ap->prio < pccp->pcc_primin || ap->prio > pccp->pcc_primax))
127d4204c85Sraf 		return (EINVAL);
1287c478bd9Sstevel@tonic-gate 
12934709573Sraf 	flag = ap->scope | ap->detachstate | ap->daemonstate | THR_SUSPENDED;
1307c478bd9Sstevel@tonic-gate 	error = _thrp_create(ap->stkaddr, ap->stksize, start_routine, arg,
131ab618543SJohn Levon 	    flag, &tid, ap->guardsize, ap->name);
1327c478bd9Sstevel@tonic-gate 	if (error == 0) {
133e56998eeSRobert Mustacchi 		/*
134*25befe07SPeter Tribble 		 * Record the original inheritance value for
135*25befe07SPeter Tribble 		 * pthread_attr_get_np(). We should always be able to find the
136e56998eeSRobert Mustacchi 		 * thread.
137e56998eeSRobert Mustacchi 		 */
138e56998eeSRobert Mustacchi 		(void) _thr_setinherit(tid, ap->inherit);
139e56998eeSRobert Mustacchi 
140d4204c85Sraf 		if (ap->inherit == PTHREAD_EXPLICIT_SCHED &&
141d4204c85Sraf 		    (ap->policy != self->ul_policy ||
142e56998eeSRobert Mustacchi 		    ap->prio != (self->ul_epri ? self->ul_epri :
143e56998eeSRobert Mustacchi 		    self->ul_pri))) {
144d4204c85Sraf 			/*
145d4204c85Sraf 			 * The SUSv3 specification requires pthread_create()
146d4204c85Sraf 			 * to fail with EPERM if it cannot set the scheduling
147d4204c85Sraf 			 * policy and parameters on the new thread.
148d4204c85Sraf 			 */
149d4204c85Sraf 			error = _thr_setparam(tid, ap->policy, ap->prio);
150e56998eeSRobert Mustacchi 		}
151e56998eeSRobert Mustacchi 
152d4204c85Sraf 		if (error) {
153d4204c85Sraf 			/*
154d4204c85Sraf 			 * We couldn't determine this error before
155d4204c85Sraf 			 * actually creating the thread.  To recover,
156d4204c85Sraf 			 * mark the thread detached and cancel it.
157d4204c85Sraf 			 * It is as though it was never created.
158d4204c85Sraf 			 */
1597c478bd9Sstevel@tonic-gate 			ulwp_t *ulwp = find_lwp(tid);
160d4204c85Sraf 			if (ulwp->ul_detached == 0) {
161d4204c85Sraf 				ulwp->ul_detached = 1;
162d4204c85Sraf 				ulwp->ul_usropts |= THR_DETACHED;
163d4204c85Sraf 				(void) __lwp_detach(tid);
164d4204c85Sraf 			}
165d4204c85Sraf 			ulwp->ul_cancel_pending = 2; /* cancelled on creation */
166d4204c85Sraf 			ulwp->ul_cancel_disabled = 0;
167d4204c85Sraf 			ulwp_unlock(ulwp, self->ul_uberdata);
168d4204c85Sraf 		} else if (thread) {
1697c478bd9Sstevel@tonic-gate 			*thread = tid;
170d4204c85Sraf 		}
1717257d1b4Sraf 		(void) thr_continue(tid);
1727c478bd9Sstevel@tonic-gate 	}
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 	/* posix version expects EAGAIN for lack of memory */
1757c478bd9Sstevel@tonic-gate 	if (error == ENOMEM)
1767c478bd9Sstevel@tonic-gate 		error = EAGAIN;
1777c478bd9Sstevel@tonic-gate 	return (error);
1787c478bd9Sstevel@tonic-gate }
1797c478bd9Sstevel@tonic-gate 
180adc04c2dSToomas Soome static void
_mutex_unlock_wrap(void * ptr)181adc04c2dSToomas Soome _mutex_unlock_wrap(void *ptr)
182adc04c2dSToomas Soome {
183adc04c2dSToomas Soome 	mutex_t *mp = ptr;
184adc04c2dSToomas Soome 
185adc04c2dSToomas Soome 	(void) mutex_unlock(mp);
186adc04c2dSToomas Soome }
187adc04c2dSToomas Soome 
1887c478bd9Sstevel@tonic-gate /*
1897c478bd9Sstevel@tonic-gate  * pthread_once: calls given function only once.
1907c478bd9Sstevel@tonic-gate  * it synchronizes via mutex in pthread_once_t structure
1917c478bd9Sstevel@tonic-gate  */
1927c478bd9Sstevel@tonic-gate int
pthread_once(pthread_once_t * once_control,void (* init_routine)(void))1937257d1b4Sraf pthread_once(pthread_once_t *once_control, void (*init_routine)(void))
1947c478bd9Sstevel@tonic-gate {
1957c478bd9Sstevel@tonic-gate 	__once_t *once = (__once_t *)once_control;
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 	if (once == NULL || init_routine == NULL)
1987c478bd9Sstevel@tonic-gate 		return (EINVAL);
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate 	if (once->once_flag == PTHREAD_ONCE_NOTDONE) {
2018cd45542Sraf 		(void) mutex_lock(&once->mlock);
2027c478bd9Sstevel@tonic-gate 		if (once->once_flag == PTHREAD_ONCE_NOTDONE) {
203adc04c2dSToomas Soome 			pthread_cleanup_push(_mutex_unlock_wrap, &once->mlock);
2047c478bd9Sstevel@tonic-gate 			(*init_routine)();
2057c478bd9Sstevel@tonic-gate 			pthread_cleanup_pop(0);
2067257d1b4Sraf 			membar_producer();
2077c478bd9Sstevel@tonic-gate 			once->once_flag = PTHREAD_ONCE_DONE;
2087c478bd9Sstevel@tonic-gate 		}
2098cd45542Sraf 		(void) mutex_unlock(&once->mlock);
2107c478bd9Sstevel@tonic-gate 	}
2117257d1b4Sraf 	membar_consumer();
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate 	return (0);
2147c478bd9Sstevel@tonic-gate }
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate /*
2177c478bd9Sstevel@tonic-gate  * pthread_equal: equates two thread ids.
2187c478bd9Sstevel@tonic-gate  */
2197c478bd9Sstevel@tonic-gate int
pthread_equal(pthread_t t1,pthread_t t2)2207257d1b4Sraf pthread_equal(pthread_t t1, pthread_t t2)
2217c478bd9Sstevel@tonic-gate {
2227c478bd9Sstevel@tonic-gate 	return (t1 == t2);
2237c478bd9Sstevel@tonic-gate }
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate /*
226d4204c85Sraf  * pthread_getschedparam: get the thread's sched parameters.
2277c478bd9Sstevel@tonic-gate  */
2287257d1b4Sraf #pragma weak _pthread_getschedparam = pthread_getschedparam
2297c478bd9Sstevel@tonic-gate int
pthread_getschedparam(pthread_t tid,int * policy,struct sched_param * param)2307257d1b4Sraf pthread_getschedparam(pthread_t tid, int *policy, struct sched_param *param)
2317c478bd9Sstevel@tonic-gate {
2327c478bd9Sstevel@tonic-gate 	ulwp_t *ulwp;
233d4204c85Sraf 	id_t cid;
2347c478bd9Sstevel@tonic-gate 	int error = 0;
2357c478bd9Sstevel@tonic-gate 
236d4204c85Sraf 	if ((ulwp = find_lwp(tid)) == NULL) {
2377c478bd9Sstevel@tonic-gate 		error = ESRCH;
238d4204c85Sraf 	} else {
239d4204c85Sraf 		cid = getparam(P_LWPID, ulwp->ul_lwpid, policy, param);
240d4204c85Sraf 		if (cid == -1) {
241d4204c85Sraf 			error = errno;
242d4204c85Sraf 		} else if (*policy == ulwp->ul_policy && cid == ulwp->ul_cid &&
243d4204c85Sraf 		    (*policy == SCHED_FIFO || *policy == SCHED_RR)) {
244d4204c85Sraf 			/*
245d4204c85Sraf 			 * Return the defined priority, not the effective
246d4204c85Sraf 			 * priority from priority ceiling mutexes.
247d4204c85Sraf 			 */
2487c478bd9Sstevel@tonic-gate 			param->sched_priority = ulwp->ul_pri;
249d4204c85Sraf 		} else {
250e84487aeSraf 			if (*policy == SCHED_FIFO || *policy == SCHED_RR)
251e84487aeSraf 				ulwp->ul_rtclassid = cid;
252d4204c85Sraf 			ulwp->ul_cid = cid;
253d4204c85Sraf 			ulwp->ul_pri = param->sched_priority;
2547257d1b4Sraf 			membar_producer();
255d4204c85Sraf 			ulwp->ul_policy = *policy;
256d4204c85Sraf 		}
257d4204c85Sraf 		ulwp_unlock(ulwp, curthread->ul_uberdata);
2587c478bd9Sstevel@tonic-gate 	}
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate 	return (error);
2617c478bd9Sstevel@tonic-gate }
2627c478bd9Sstevel@tonic-gate 
2637257d1b4Sraf #pragma weak _thr_getprio = thr_getprio
2647c478bd9Sstevel@tonic-gate int
thr_getprio(thread_t tid,int * priority)2657257d1b4Sraf thr_getprio(thread_t tid, int *priority)
2667c478bd9Sstevel@tonic-gate {
267d4204c85Sraf 	struct sched_param param;
268d4204c85Sraf 	int policy;
269d4204c85Sraf 	int error;
2709acbbeafSnn 
2717257d1b4Sraf 	if ((error = pthread_getschedparam(tid, &policy, &param)) == 0)
272d4204c85Sraf 		*priority = param.sched_priority;
2737c478bd9Sstevel@tonic-gate 	return (error);
2747c478bd9Sstevel@tonic-gate }
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate /*
2777c478bd9Sstevel@tonic-gate  * pthread_setschedparam: sets the sched parameters for a thread.
2787c478bd9Sstevel@tonic-gate  */
2797c478bd9Sstevel@tonic-gate int
pthread_setschedparam(pthread_t tid,int policy,const struct sched_param * param)2807257d1b4Sraf pthread_setschedparam(pthread_t tid,
281e56998eeSRobert Mustacchi     int policy, const struct sched_param *param)
2827c478bd9Sstevel@tonic-gate {
283d4204c85Sraf 	return (_thr_setparam(tid, policy, param->sched_priority));
284d4204c85Sraf }
285d4204c85Sraf 
2867257d1b4Sraf #pragma weak pthread_setschedprio = thr_setprio
287d4204c85Sraf int
thr_setprio(thread_t tid,int prio)2887257d1b4Sraf thr_setprio(thread_t tid, int prio)
289d4204c85Sraf {
290d4204c85Sraf 	struct sched_param param;
291d4204c85Sraf 	int policy;
292d4204c85Sraf 	int error;
293d4204c85Sraf 
294d4204c85Sraf 	/*
2957257d1b4Sraf 	 * pthread_getschedparam() has the side-effect of setting
296d4204c85Sraf 	 * the target thread's ul_policy, ul_pri and ul_cid correctly.
297d4204c85Sraf 	 */
2987257d1b4Sraf 	if ((error = pthread_getschedparam(tid, &policy, &param)) != 0)
299d4204c85Sraf 		return (error);
300d4204c85Sraf 	if (param.sched_priority == prio)	/* no change */
301d4204c85Sraf 		return (0);
302d4204c85Sraf 	return (_thr_setparam(tid, policy, prio));
3037c478bd9Sstevel@tonic-gate }
304