17c478bdstevel@tonic-gate/*
27c478bdstevel@tonic-gate * CDDL HEADER START
37c478bdstevel@tonic-gate *
47c478bdstevel@tonic-gate * The contents of this file are subject to the terms of the
53470957raf * Common Development and Distribution License (the "License").
63470957raf * You may not use this file except in compliance with the License.
77c478bdstevel@tonic-gate *
87c478bdstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bdstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bdstevel@tonic-gate * See the License for the specific language governing permissions
117c478bdstevel@tonic-gate * and limitations under the License.
127c478bdstevel@tonic-gate *
137c478bdstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bdstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bdstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bdstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bdstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bdstevel@tonic-gate *
197c478bdstevel@tonic-gate * CDDL HEADER END
207c478bdstevel@tonic-gate */
213470957raf
227c478bdstevel@tonic-gate/*
23d4204c8raf * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
247c478bdstevel@tonic-gate * Use is subject to license terms.
257c478bdstevel@tonic-gate */
26e56998eRobert Mustacchi/*
27ab61854John Levon * Copyright 2018 Joyent, Inc.
28e56998eRobert Mustacchi */
297c478bdstevel@tonic-gate
307c478bdstevel@tonic-gate#include "lint.h"
317c478bdstevel@tonic-gate#include "thr_uberdata.h"
327c478bdstevel@tonic-gate
337c478bdstevel@tonic-gate/*
347c478bdstevel@tonic-gate * pthread_once related data
357c478bdstevel@tonic-gate * This structure is exported as pthread_once_t in pthread.h.
367c478bdstevel@tonic-gate * We export only the size of this structure. so check
377c478bdstevel@tonic-gate * pthread_once_t in pthread.h before making a change here.
387c478bdstevel@tonic-gate */
397c478bdstevel@tonic-gatetypedef struct  __once {
407c478bdstevel@tonic-gate	mutex_t	mlock;
417c478bdstevel@tonic-gate	union {
427c478bdstevel@tonic-gate		uint32_t	pad32_flag[2];
437c478bdstevel@tonic-gate		uint64_t	pad64_flag;
447c478bdstevel@tonic-gate	} oflag;
457c478bdstevel@tonic-gate} __once_t;
467c478bdstevel@tonic-gate
477c478bdstevel@tonic-gate#define	once_flag	oflag.pad32_flag[1]
487c478bdstevel@tonic-gate
49d4204c8rafstatic int
50e56998eRobert Mustacchi_thr_setinherit(pthread_t tid, int inherit)
51e56998eRobert Mustacchi{
52e56998eRobert Mustacchi	ulwp_t *ulwp;
53e56998eRobert Mustacchi	int error = 0;
54e56998eRobert Mustacchi
55e56998eRobert Mustacchi	if ((ulwp = find_lwp(tid)) == NULL) {
56e56998eRobert Mustacchi		error = ESRCH;
57e56998eRobert Mustacchi	} else {
58e56998eRobert Mustacchi		ulwp->ul_ptinherit = inherit;
59e56998eRobert Mustacchi		ulwp_unlock(ulwp, curthread->ul_uberdata);
60e56998eRobert Mustacchi	}
61e56998eRobert Mustacchi
62e56998eRobert Mustacchi	return (error);
63e56998eRobert Mustacchi}
64e56998eRobert Mustacchi
65e56998eRobert Mustacchistatic int
66d4204c8raf_thr_setparam(pthread_t tid, int policy, int prio)
67d4204c8raf{
68d4204c8raf	ulwp_t *ulwp;
69d4204c8raf	id_t cid;
70d4204c8raf	int error = 0;
71d4204c8raf
72d4204c8raf	if ((ulwp = find_lwp(tid)) == NULL) {
73d4204c8raf		error = ESRCH;
74d4204c8raf	} else {
75d4204c8raf		if (policy == ulwp->ul_policy &&
76d4204c8raf		    (policy == SCHED_FIFO || policy == SCHED_RR) &&
77d4204c8raf		    ulwp->ul_epri != 0) {
78d4204c8raf			/*
79d4204c8raf			 * Don't change the ceiling priority,
80d4204c8raf			 * just the base priority.
81d4204c8raf			 */
82d4204c8raf			if (prio > ulwp->ul_epri)
83d4204c8raf				error = EPERM;
84d4204c8raf			else
85d4204c8raf				ulwp->ul_pri = prio;
86d4204c8raf		} else if ((cid = setparam(P_LWPID, tid, policy, prio)) == -1) {
87d4204c8raf			error = errno;
88d4204c8raf		} else {
89e84487araf			if (policy == SCHED_FIFO || policy == SCHED_RR)
90e84487araf				ulwp->ul_rtclassid = cid;
91d4204c8raf			ulwp->ul_cid = cid;
92d4204c8raf			ulwp->ul_pri = prio;
937257d1braf			membar_producer();
94d4204c8raf			ulwp->ul_policy = policy;
95d4204c8raf		}
96d4204c8raf		ulwp_unlock(ulwp, curthread->ul_uberdata);
97d4204c8raf	}
98d4204c8raf	return (error);
99d4204c8raf}
100d4204c8raf
1017c478bdstevel@tonic-gate/*
1027c478bdstevel@tonic-gate * pthread_create: creates a thread in the current process.
1037c478bdstevel@tonic-gate * calls common _thrp_create() after copying the attributes.
1047c478bdstevel@tonic-gate */
1057257d1braf#pragma weak _pthread_create = pthread_create
1067c478bdstevel@tonic-gateint
1077257d1brafpthread_create(pthread_t *thread, const pthread_attr_t *attr,
108e56998eRobert Mustacchi    void * (*start_routine)(void *), void *arg)
1097c478bdstevel@tonic-gate{
1107c478bdstevel@tonic-gate	ulwp_t		*self = curthread;
1113470957raf	const thrattr_t	*ap = attr? attr->__pthread_attrp : def_thrattr();
112d4204c8raf	const pcclass_t	*pccp;
1137c478bdstevel@tonic-gate	long		flag;
1147c478bdstevel@tonic-gate	pthread_t	tid;
1157c478bdstevel@tonic-gate	int		error;
116d4204c8raf
117d4204c8raf	update_sched(self);
1187c478bdstevel@tonic-gate
1193470957raf	if (ap == NULL)
1207c478bdstevel@tonic-gate		return (EINVAL);
1217c478bdstevel@tonic-gate
122d4204c8raf	/* validate explicit scheduling attributes */
123d4204c8raf	if (ap->inherit == PTHREAD_EXPLICIT_SCHED &&
124d4204c8raf	    (ap->policy == SCHED_SYS ||
125d4204c8raf	    (pccp = get_info_by_policy(ap->policy)) == NULL ||
126d4204c8raf	    ap->prio < pccp->pcc_primin || ap->prio > pccp->pcc_primax))
127d4204c8raf		return (EINVAL);
1287c478bdstevel@tonic-gate
1293470957raf	flag = ap->scope | ap->detachstate | ap->daemonstate | THR_SUSPENDED;
1307c478bdstevel@tonic-gate	error = _thrp_create(ap->stkaddr, ap->stksize, start_routine, arg,
131ab61854John Levon	    flag, &tid, ap->guardsize, ap->name);
1327c478bdstevel@tonic-gate	if (error == 0) {
133e56998eRobert Mustacchi		/*
134e56998eRobert Mustacchi		 * Record the original inheritence value for
135e56998eRobert Mustacchi		 * pthread_getattr_np(). We should always be able to find the
136e56998eRobert Mustacchi		 * thread.
137e56998eRobert Mustacchi		 */
138e56998eRobert Mustacchi		(void) _thr_setinherit(tid, ap->inherit);
139e56998eRobert Mustacchi
140d4204c8raf		if (ap->inherit == PTHREAD_EXPLICIT_SCHED &&
141d4204c8raf		    (ap->policy != self->ul_policy ||
142e56998eRobert Mustacchi		    ap->prio != (self->ul_epri ? self->ul_epri :
143e56998eRobert Mustacchi		    self->ul_pri))) {
144d4204c8raf			/*
145d4204c8raf			 * The SUSv3 specification requires pthread_create()
146d4204c8raf			 * to fail with EPERM if it cannot set the scheduling
147d4204c8raf			 * policy and parameters on the new thread.
148d4204c8raf			 */
149d4204c8raf			error = _thr_setparam(tid, ap->policy, ap->prio);
150e56998eRobert Mustacchi		}
151e56998eRobert Mustacchi
152d4204c8raf		if (error) {
153d4204c8raf			/*
154d4204c8raf			 * We couldn't determine this error before
155d4204c8raf			 * actually creating the thread.  To recover,
156d4204c8raf			 * mark the thread detached and cancel it.
157d4204c8raf			 * It is as though it was never created.
158d4204c8raf			 */
1597c478bdstevel@tonic-gate			ulwp_t *ulwp = find_lwp(tid);
160d4204c8raf			if (ulwp->ul_detached == 0) {
161d4204c8raf				ulwp->ul_detached = 1;
162d4204c8raf				ulwp->ul_usropts |= THR_DETACHED;
163d4204c8raf				(void) __lwp_detach(tid);
164d4204c8raf			}
165d4204c8raf			ulwp->ul_cancel_pending = 2; /* cancelled on creation */
166d4204c8raf			ulwp->ul_cancel_disabled = 0;
167d4204c8raf			ulwp_unlock(ulwp, self->ul_uberdata);
168d4204c8raf		} else if (thread) {
1697c478bdstevel@tonic-gate			*thread = tid;
170d4204c8raf		}
1717257d1braf		(void) thr_continue(tid);
1727c478bdstevel@tonic-gate	}
1737c478bdstevel@tonic-gate
1747c478bdstevel@tonic-gate	/* posix version expects EAGAIN for lack of memory */
1757c478bdstevel@tonic-gate	if (error == ENOMEM)
1767c478bdstevel@tonic-gate		error = EAGAIN;
1777c478bdstevel@tonic-gate	return (error);
1787c478bdstevel@tonic-gate}
1797c478bdstevel@tonic-gate
180adc04c2Toomas Soomestatic void
181adc04c2Toomas Soome_mutex_unlock_wrap(void *ptr)
182adc04c2Toomas Soome{
183adc04c2Toomas Soome	mutex_t *mp = ptr;
184adc04c2Toomas Soome
185adc04c2Toomas Soome	(void) mutex_unlock(mp);
186adc04c2Toomas Soome}
187adc04c2Toomas Soome
1887c478bdstevel@tonic-gate/*
1897c478bdstevel@tonic-gate * pthread_once: calls given function only once.
1907c478bdstevel@tonic-gate * it synchronizes via mutex in pthread_once_t structure
1917c478bdstevel@tonic-gate */
1927c478bdstevel@tonic-gateint
1937257d1brafpthread_once(pthread_once_t *once_control, void (*init_routine)(void))
1947c478bdstevel@tonic-gate{
1957c478bdstevel@tonic-gate	__once_t *once = (__once_t *)once_control;
1967c478bdstevel@tonic-gate
1977c478bdstevel@tonic-gate	if (once == NULL || init_routine == NULL)
1987c478bdstevel@tonic-gate		return (EINVAL);
1997c478bdstevel@tonic-gate
2007c478bdstevel@tonic-gate	if (once->once_flag == PTHREAD_ONCE_NOTDONE) {
2018cd4554raf		(void) mutex_lock(&once->mlock);
2027c478bdstevel@tonic-gate		if (once->once_flag == PTHREAD_ONCE_NOTDONE) {
203adc04c2Toomas Soome			pthread_cleanup_push(_mutex_unlock_wrap, &once->mlock);
2047c478bdstevel@tonic-gate			(*init_routine)();
2057c478bdstevel@tonic-gate			pthread_cleanup_pop(0);
2067257d1braf			membar_producer();
2077c478bdstevel@tonic-gate			once->once_flag = PTHREAD_ONCE_DONE;
2087c478bdstevel@tonic-gate		}
2098cd4554raf		(void) mutex_unlock(&once->mlock);
2107c478bdstevel@tonic-gate	}
2117257d1braf	membar_consumer();
2127c478bdstevel@tonic-gate
2137c478bdstevel@tonic-gate	return (0);
2147c478bdstevel@tonic-gate}
2157c478bdstevel@tonic-gate
2167c478bdstevel@tonic-gate/*
2177c478bdstevel@tonic-gate * pthread_equal: equates two thread ids.
2187c478bdstevel@tonic-gate */
2197c478bdstevel@tonic-gateint
2207257d1brafpthread_equal(pthread_t t1, pthread_t t2)
2217c478bdstevel@tonic-gate{
2227c478bdstevel@tonic-gate	return (t1 == t2);
2237c478bdstevel@tonic-gate}
2247c478bdstevel@tonic-gate
2257c478bdstevel@tonic-gate/*
226d4204c8raf * pthread_getschedparam: get the thread's sched parameters.
2277c478bdstevel@tonic-gate */
2287257d1braf#pragma weak _pthread_getschedparam = pthread_getschedparam
2297c478bdstevel@tonic-gateint
2307257d1brafpthread_getschedparam(pthread_t tid, int *policy, struct sched_param *param)
2317c478bdstevel@tonic-gate{
2327c478bdstevel@tonic-gate	ulwp_t *ulwp;
233d4204c8raf	id_t cid;
2347c478bdstevel@tonic-gate	int error = 0;
2357c478bdstevel@tonic-gate
236d4204c8raf	if ((ulwp = find_lwp(tid)) == NULL) {
2377c478bdstevel@tonic-gate		error = ESRCH;
238d4204c8raf	} else {
239d4204c8raf		cid = getparam(P_LWPID, ulwp->ul_lwpid, policy, param);
240d4204c8raf		if (cid == -1) {
241d4204c8raf			error = errno;
242d4204c8raf		} else if (*policy == ulwp->ul_policy && cid == ulwp->ul_cid &&
243d4204c8raf		    (*policy == SCHED_FIFO || *policy == SCHED_RR)) {
244d4204c8raf			/*
245d4204c8raf			 * Return the defined priority, not the effective
246d4204c8raf			 * priority from priority ceiling mutexes.
247d4204c8raf			 */
2487c478bdstevel@tonic-gate			param->sched_priority = ulwp->ul_pri;
249d4204c8raf		} else {
250e84487araf			if (*policy == SCHED_FIFO || *policy == SCHED_RR)
251e84487araf				ulwp->ul_rtclassid = cid;
252d4204c8raf			ulwp->ul_cid = cid;
253d4204c8raf			ulwp->ul_pri = param->sched_priority;
2547257d1braf			membar_producer();
255d4204c8raf			ulwp->ul_policy = *policy;
256d4204c8raf		}
257d4204c8raf		ulwp_unlock(ulwp, curthread->ul_uberdata);
2587c478bdstevel@tonic-gate	}
2597c478bdstevel@tonic-gate
2607c478bdstevel@tonic-gate	return (error);
2617c478bdstevel@tonic-gate}
2627c478bdstevel@tonic-gate
2637257d1braf#pragma weak _thr_getprio = thr_getprio
2647c478bdstevel@tonic-gateint
2657257d1brafthr_getprio(thread_t tid, int *priority)
2667c478bdstevel@tonic-gate{
267d4204c8raf	struct sched_param param;
268d4204c8raf	int policy;
269d4204c8raf	int error;
2709acbbeann
2717257d1braf	if ((error = pthread_getschedparam(tid, &policy, &param)) == 0)
272d4204c8raf		*priority = param.sched_priority;
2737c478bdstevel@tonic-gate	return (error);
2747c478bdstevel@tonic-gate}
2757c478bdstevel@tonic-gate
2767c478bdstevel@tonic-gate/*
2777c478bdstevel@tonic-gate * pthread_setschedparam: sets the sched parameters for a thread.
2787c478bdstevel@tonic-gate */
2797c478bdstevel@tonic-gateint
2807257d1brafpthread_setschedparam(pthread_t tid,
281e56998eRobert Mustacchi    int policy, const struct sched_param *param)
2827c478bdstevel@tonic-gate{
283d4204c8raf	return (_thr_setparam(tid, policy, param->sched_priority));
284d4204c8raf}
285d4204c8raf
2867257d1braf#pragma weak pthread_setschedprio = thr_setprio
287d4204c8rafint
2887257d1brafthr_setprio(thread_t tid, int prio)
289d4204c8raf{
290d4204c8raf	struct sched_param param;
291d4204c8raf	int policy;
292d4204c8raf	int error;
293d4204c8raf
294d4204c8raf	/*
2957257d1braf	 * pthread_getschedparam() has the side-effect of setting
296d4204c8raf	 * the target thread's ul_policy, ul_pri and ul_cid correctly.
297d4204c8raf	 */
2987257d1braf	if ((error = pthread_getschedparam(tid, &policy, &param)) != 0)
299d4204c8raf		return (error);
300d4204c8raf	if (param.sched_priority == prio)	/* no change */
301d4204c8raf		return (0);
302d4204c8raf	return (_thr_setparam(tid, policy, prio));
3037c478bdstevel@tonic-gate}
304