4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 * Copyright 2016 Joyent, Inc.
31 #include "thr_uberdata.h"
34 * pthread_once related data
35 * This structure is exported as pthread_once_t in pthread.h.
36 * We export only the size of this structure. so check
37 * pthread_once_t in pthread.h before making a change here.
39 typedef struct __once
{
42 uint32_t pad32_flag
[2];
47 #define once_flag oflag.pad32_flag[1]
50 _thr_setinherit(pthread_t tid
, int inherit
)
55 if ((ulwp
= find_lwp(tid
)) == NULL
) {
58 ulwp
->ul_ptinherit
= inherit
;
59 ulwp_unlock(ulwp
, curthread
->ul_uberdata
);
66 _thr_setparam(pthread_t tid
, int policy
, int prio
)
72 if ((ulwp
= find_lwp(tid
)) == NULL
) {
75 if (policy
== ulwp
->ul_policy
&&
76 (policy
== SCHED_FIFO
|| policy
== SCHED_RR
) &&
79 * Don't change the ceiling priority,
80 * just the base priority.
82 if (prio
> ulwp
->ul_epri
)
86 } else if ((cid
= setparam(P_LWPID
, tid
, policy
, prio
)) == -1) {
89 if (policy
== SCHED_FIFO
|| policy
== SCHED_RR
)
90 ulwp
->ul_rtclassid
= cid
;
94 ulwp
->ul_policy
= policy
;
96 ulwp_unlock(ulwp
, curthread
->ul_uberdata
);
102 * pthread_create: creates a thread in the current process.
103 * calls common _thrp_create() after copying the attributes.
105 #pragma weak _pthread_create = pthread_create
107 pthread_create(pthread_t
*thread
, const pthread_attr_t
*attr
,
108 void * (*start_routine
)(void *), void *arg
)
110 ulwp_t
*self
= curthread
;
111 const thrattr_t
*ap
= attr
? attr
->__pthread_attrp
: def_thrattr();
112 const pcclass_t
*pccp
;
122 /* validate explicit scheduling attributes */
123 if (ap
->inherit
== PTHREAD_EXPLICIT_SCHED
&&
124 (ap
->policy
== SCHED_SYS
||
125 (pccp
= get_info_by_policy(ap
->policy
)) == NULL
||
126 ap
->prio
< pccp
->pcc_primin
|| ap
->prio
> pccp
->pcc_primax
))
129 flag
= ap
->scope
| ap
->detachstate
| ap
->daemonstate
| THR_SUSPENDED
;
130 error
= _thrp_create(ap
->stkaddr
, ap
->stksize
, start_routine
, arg
,
131 flag
, &tid
, ap
->guardsize
);
134 * Record the original inheritence value for
135 * pthread_getattr_np(). We should always be able to find the
138 (void) _thr_setinherit(tid
, ap
->inherit
);
140 if (ap
->inherit
== PTHREAD_EXPLICIT_SCHED
&&
141 (ap
->policy
!= self
->ul_policy
||
142 ap
->prio
!= (self
->ul_epri
? self
->ul_epri
:
145 * The SUSv3 specification requires pthread_create()
146 * to fail with EPERM if it cannot set the scheduling
147 * policy and parameters on the new thread.
149 error
= _thr_setparam(tid
, ap
->policy
, ap
->prio
);
154 * We couldn't determine this error before
155 * actually creating the thread. To recover,
156 * mark the thread detached and cancel it.
157 * It is as though it was never created.
159 ulwp_t
*ulwp
= find_lwp(tid
);
160 if (ulwp
->ul_detached
== 0) {
161 ulwp
->ul_detached
= 1;
162 ulwp
->ul_usropts
|= THR_DETACHED
;
163 (void) __lwp_detach(tid
);
165 ulwp
->ul_cancel_pending
= 2; /* cancelled on creation */
166 ulwp
->ul_cancel_disabled
= 0;
167 ulwp_unlock(ulwp
, self
->ul_uberdata
);
171 (void) thr_continue(tid
);
174 /* posix version expects EAGAIN for lack of memory */
181 * pthread_once: calls given function only once.
182 * it synchronizes via mutex in pthread_once_t structure
185 pthread_once(pthread_once_t
*once_control
, void (*init_routine
)(void))
187 __once_t
*once
= (__once_t
*)once_control
;
189 if (once
== NULL
|| init_routine
== NULL
)
192 if (once
->once_flag
== PTHREAD_ONCE_NOTDONE
) {
193 (void) mutex_lock(&once
->mlock
);
194 if (once
->once_flag
== PTHREAD_ONCE_NOTDONE
) {
195 pthread_cleanup_push(mutex_unlock
, &once
->mlock
);
197 pthread_cleanup_pop(0);
199 once
->once_flag
= PTHREAD_ONCE_DONE
;
201 (void) mutex_unlock(&once
->mlock
);
209 * pthread_equal: equates two thread ids.
212 pthread_equal(pthread_t t1
, pthread_t t2
)
218 * pthread_getschedparam: get the thread's sched parameters.
220 #pragma weak _pthread_getschedparam = pthread_getschedparam
222 pthread_getschedparam(pthread_t tid
, int *policy
, struct sched_param
*param
)
228 if ((ulwp
= find_lwp(tid
)) == NULL
) {
231 cid
= getparam(P_LWPID
, ulwp
->ul_lwpid
, policy
, param
);
234 } else if (*policy
== ulwp
->ul_policy
&& cid
== ulwp
->ul_cid
&&
235 (*policy
== SCHED_FIFO
|| *policy
== SCHED_RR
)) {
237 * Return the defined priority, not the effective
238 * priority from priority ceiling mutexes.
240 param
->sched_priority
= ulwp
->ul_pri
;
242 if (*policy
== SCHED_FIFO
|| *policy
== SCHED_RR
)
243 ulwp
->ul_rtclassid
= cid
;
245 ulwp
->ul_pri
= param
->sched_priority
;
247 ulwp
->ul_policy
= *policy
;
249 ulwp_unlock(ulwp
, curthread
->ul_uberdata
);
255 #pragma weak _thr_getprio = thr_getprio
257 thr_getprio(thread_t tid
, int *priority
)
259 struct sched_param param
;
263 if ((error
= pthread_getschedparam(tid
, &policy
, ¶m
)) == 0)
264 *priority
= param
.sched_priority
;
269 * pthread_setschedparam: sets the sched parameters for a thread.
272 pthread_setschedparam(pthread_t tid
,
273 int policy
, const struct sched_param
*param
)
275 return (_thr_setparam(tid
, policy
, param
->sched_priority
));
278 #pragma weak pthread_setschedprio = thr_setprio
280 thr_setprio(thread_t tid
, int prio
)
282 struct sched_param param
;
287 * pthread_getschedparam() has the side-effect of setting
288 * the target thread's ul_policy, ul_pri and ul_cid correctly.
290 if ((error
= pthread_getschedparam(tid
, &policy
, ¶m
)) != 0)
292 if (param
.sched_priority
== prio
) /* no change */
294 return (_thr_setparam(tid
, policy
, prio
));