import less(1)
[unleashed/tickless.git] / usr / src / lib / libc / port / threads / pthr_attr.c
blobb04bcdba7c01c6dffb6151dbc179722a9947ffc9
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * Copyright 2015, Joyent, Inc.
31 #include "lint.h"
32 #include "thr_uberdata.h"
33 #include <sched.h>
36 * Default attribute object for pthread_create() with NULL attr pointer.
37 * Note that the 'guardsize' field is initialized on the first call.
39 const thrattr_t *
40 def_thrattr(void)
42 static thrattr_t thrattr = {
43 0, /* stksize */
44 NULL, /* stkaddr */
45 PTHREAD_CREATE_JOINABLE, /* detachstate */
46 PTHREAD_CREATE_NONDAEMON_NP, /* daemonstate */
47 PTHREAD_SCOPE_PROCESS, /* scope */
48 0, /* prio */
49 SCHED_OTHER, /* policy */
50 PTHREAD_INHERIT_SCHED, /* inherit */
51 0 /* guardsize */
53 if (thrattr.guardsize == 0)
54 thrattr.guardsize = _sysconf(_SC_PAGESIZE);
55 return (&thrattr);
59 * pthread_attr_init: allocates the attribute object and initializes it
60 * with the default values.
62 #pragma weak _pthread_attr_init = pthread_attr_init
63 int
64 pthread_attr_init(pthread_attr_t *attr)
66 thrattr_t *ap;
68 if ((ap = lmalloc(sizeof (thrattr_t))) != NULL) {
69 *ap = *def_thrattr();
70 attr->__pthread_attrp = ap;
71 return (0);
73 return (ENOMEM);
77 * pthread_attr_destroy: frees the attribute object and invalidates it
78 * with NULL value.
80 int
81 pthread_attr_destroy(pthread_attr_t *attr)
83 if (attr == NULL || attr->__pthread_attrp == NULL)
84 return (EINVAL);
85 lfree(attr->__pthread_attrp, sizeof (thrattr_t));
86 attr->__pthread_attrp = NULL;
87 return (0);
91 * pthread_attr_clone: make a copy of a pthread_attr_t.
93 int
94 pthread_attr_clone(pthread_attr_t *attr, const pthread_attr_t *old_attr)
96 thrattr_t *ap;
97 const thrattr_t *old_ap =
98 old_attr? old_attr->__pthread_attrp : def_thrattr();
100 if (old_ap == NULL)
101 return (EINVAL);
102 if ((ap = lmalloc(sizeof (thrattr_t))) == NULL)
103 return (ENOMEM);
104 *ap = *old_ap;
105 attr->__pthread_attrp = ap;
106 return (0);
110 * pthread_attr_equal: compare two pthread_attr_t's, return 1 if equal.
111 * A NULL pthread_attr_t pointer implies default attributes.
112 * This is a consolidation-private interface, for librt.
115 pthread_attr_equal(const pthread_attr_t *attr1, const pthread_attr_t *attr2)
117 const thrattr_t *ap1 = attr1? attr1->__pthread_attrp : def_thrattr();
118 const thrattr_t *ap2 = attr2? attr2->__pthread_attrp : def_thrattr();
120 if (ap1 == NULL || ap2 == NULL)
121 return (0);
122 return (ap1 == ap2 || memcmp(ap1, ap2, sizeof (thrattr_t)) == 0);
126 * pthread_attr_setstacksize: sets the user stack size, minimum should
127 * be PTHREAD_STACK_MIN (MINSTACK).
128 * This is equivalent to stksize argument in thr_create().
131 pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
133 thrattr_t *ap;
135 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
136 stacksize >= MINSTACK) {
137 ap->stksize = stacksize;
138 return (0);
140 return (EINVAL);
144 * pthread_attr_getstacksize: gets the user stack size.
146 #pragma weak _pthread_attr_getstacksize = pthread_attr_getstacksize
148 pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize)
150 thrattr_t *ap;
152 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
153 stacksize != NULL) {
154 *stacksize = ap->stksize;
155 return (0);
157 return (EINVAL);
161 * pthread_attr_setstackaddr: sets the user stack addr.
162 * This is equivalent to stkaddr argument in thr_create().
165 pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr)
167 thrattr_t *ap;
169 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL) {
170 ap->stkaddr = stackaddr;
171 return (0);
173 return (EINVAL);
177 * pthread_attr_getstackaddr: gets the user stack addr.
179 #pragma weak _pthread_attr_getstackaddr = pthread_attr_getstackaddr
181 pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr)
183 thrattr_t *ap;
185 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
186 stackaddr != NULL) {
187 *stackaddr = ap->stkaddr;
188 return (0);
190 return (EINVAL);
194 * pthread_attr_setdetachstate: sets the detach state to DETACHED or JOINABLE.
195 * PTHREAD_CREATE_DETACHED is equivalent to thr_create(THR_DETACHED).
198 pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
200 thrattr_t *ap;
202 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
203 (detachstate == PTHREAD_CREATE_DETACHED ||
204 detachstate == PTHREAD_CREATE_JOINABLE)) {
205 ap->detachstate = detachstate;
206 return (0);
208 return (EINVAL);
212 * pthread_attr_getdetachstate: gets the detach state.
214 #pragma weak _pthread_attr_getdetachstate = pthread_attr_getdetachstate
216 pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
218 thrattr_t *ap;
220 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
221 detachstate != NULL) {
222 *detachstate = ap->detachstate;
223 return (0);
225 return (EINVAL);
229 * pthread_attr_setdaemonstate_np: sets the daemon state to DAEMON or NONDAEMON.
230 * PTHREAD_CREATE_DAEMON is equivalent to thr_create(THR_DAEMON).
231 * For now, this is a private interface in libc.
234 pthread_attr_setdaemonstate_np(pthread_attr_t *attr, int daemonstate)
236 thrattr_t *ap;
238 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
239 (daemonstate == PTHREAD_CREATE_DAEMON_NP ||
240 daemonstate == PTHREAD_CREATE_NONDAEMON_NP)) {
241 ap->daemonstate = daemonstate;
242 return (0);
244 return (EINVAL);
248 * pthread_attr_getdaemonstate_np: gets the daemon state.
249 * For now, this is a private interface in libc, but it is exposed in the
250 * mapfile for the purposes of testing only.
253 pthread_attr_getdaemonstate_np(const pthread_attr_t *attr, int *daemonstate)
255 thrattr_t *ap;
257 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
258 daemonstate != NULL) {
259 *daemonstate = ap->daemonstate;
260 return (0);
262 return (EINVAL);
266 * pthread_attr_setscope: sets the scope to SYSTEM or PROCESS.
267 * This is equivalent to setting THR_BOUND flag in thr_create().
270 pthread_attr_setscope(pthread_attr_t *attr, int scope)
272 thrattr_t *ap;
274 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
275 (scope == PTHREAD_SCOPE_SYSTEM ||
276 scope == PTHREAD_SCOPE_PROCESS)) {
277 ap->scope = scope;
278 return (0);
280 return (EINVAL);
284 * pthread_attr_getscope: gets the scheduling scope.
286 #pragma weak _pthread_attr_getscope = pthread_attr_getscope
288 pthread_attr_getscope(const pthread_attr_t *attr, int *scope)
290 thrattr_t *ap;
292 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
293 scope != NULL) {
294 *scope = ap->scope;
295 return (0);
297 return (EINVAL);
301 * pthread_attr_setinheritsched: sets the scheduling parameters to be
302 * EXPLICIT or INHERITED from parent thread.
305 pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit)
307 thrattr_t *ap;
309 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
310 (inherit == PTHREAD_EXPLICIT_SCHED ||
311 inherit == PTHREAD_INHERIT_SCHED)) {
312 ap->inherit = inherit;
313 return (0);
315 return (EINVAL);
319 * pthread_attr_getinheritsched: gets the scheduling inheritance.
321 #pragma weak _pthread_attr_getinheritsched = pthread_attr_getinheritsched
323 pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inherit)
325 thrattr_t *ap;
327 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
328 inherit != NULL) {
329 *inherit = ap->inherit;
330 return (0);
332 return (EINVAL);
336 * pthread_attr_setschedpolicy: sets the scheduling policy.
339 pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
341 thrattr_t *ap;
343 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
344 policy != SCHED_SYS && get_info_by_policy(policy) != NULL) {
345 ap->policy = policy;
346 return (0);
348 return (EINVAL);
352 * pthread_attr_getpolicy: gets the scheduling policy.
354 #pragma weak _pthread_attr_getschedpolicy = pthread_attr_getschedpolicy
356 pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
358 thrattr_t *ap;
360 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
361 policy != NULL) {
362 *policy = ap->policy;
363 return (0);
365 return (EINVAL);
369 * pthread_attr_setschedparam: sets the scheduling parameters.
370 * Currently, we support priority only.
373 pthread_attr_setschedparam(pthread_attr_t *attr,
374 const struct sched_param *param)
376 thrattr_t *ap;
378 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
379 param != NULL) {
380 ap->prio = param->sched_priority;
381 return (0);
383 return (EINVAL);
387 * pthread_attr_getschedparam: gets the scheduling parameters.
388 * Currently, only priority is defined as sched parameter.
390 #pragma weak _pthread_attr_getschedparam = pthread_attr_getschedparam
392 pthread_attr_getschedparam(const pthread_attr_t *attr,
393 struct sched_param *param)
395 thrattr_t *ap;
397 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
398 param != NULL) {
399 param->sched_priority = ap->prio;
400 return (0);
402 return (EINVAL);
406 * UNIX98
407 * pthread_attr_setguardsize: sets the guardsize
410 pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize)
412 thrattr_t *ap;
414 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL) {
415 ap->guardsize = guardsize;
416 return (0);
418 return (EINVAL);
422 * UNIX98
423 * pthread_attr_getguardsize: gets the guardsize
426 pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize)
428 thrattr_t *ap;
430 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
431 guardsize != NULL) {
432 *guardsize = ap->guardsize;
433 return (0);
435 return (EINVAL);
439 * pthread_attr_setstack: sets the user stack addr and stack size.
440 * This is equivalent to the stack_base and stack_size arguments
441 * to thr_create().
444 pthread_attr_setstack(pthread_attr_t *attr,
445 void *stackaddr, size_t stacksize)
447 thrattr_t *ap;
449 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
450 stacksize >= MINSTACK) {
451 ap->stkaddr = stackaddr;
452 ap->stksize = stacksize;
453 if (stackaddr != NULL &&
454 setup_top_frame(stackaddr, stacksize, NULL) == NULL)
455 return (EACCES);
456 return (0);
458 return (EINVAL);
462 * pthread_attr_getstack: gets the user stack addr and stack size.
465 pthread_attr_getstack(const pthread_attr_t *attr,
466 void **stackaddr, size_t *stacksize)
468 thrattr_t *ap;
470 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
471 stackaddr != NULL && stacksize != NULL) {
472 *stackaddr = ap->stkaddr;
473 *stacksize = ap->stksize;
474 return (0);
476 return (EINVAL);
480 * This function is a common BSD extension to pthread which is used to obtain
481 * the attributes of a thread that might have changed after its creation, for
482 * example, it's stack address.
484 * Note, there is no setattr analogue, nor do we desire to add one at this time.
485 * Similarly there is no native threads API analogue (nor should we add one for
486 * C11).
488 * The astute reader may note that there is a GNU version of this called
489 * pthread_getattr_np(). The two functions are similar, but subtley different in
490 * a rather important way. While the pthread_attr_get_np() expects to be given
491 * a pthread_attr_t that has had pthread_attr_init() called on in,
492 * pthread_getattr_np() does not. However, on GNU systems, where the function
493 * originates, the pthread_attr_t is not opaque and thus it is entirely safe to
494 * both call pthread_attr_init() and then call pthread_getattr_np() on the same
495 * attributes object. On illumos, since the pthread_attr_t is opaque, that would
496 * be a memory leak. As such, we don't provide it.
499 pthread_attr_get_np(pthread_t tid, pthread_attr_t *attr)
501 int ret;
502 ulwp_t *self = curthread;
503 uberdata_t *udp = self->ul_uberdata;
504 ulwp_t *target = NULL;
505 thrattr_t *ap;
508 * To ensure that information about the target thread does not change or
509 * disappear while we're trying to interrogate it, we grab the uwlp
510 * lock.
512 if (self->ul_lwpid == tid) {
513 ulwp_lock(self, udp);
514 target = self;
515 } else {
516 target = find_lwp(tid);
517 if (target == NULL)
518 return (ESRCH);
521 if (attr == NULL) {
522 ret = EINVAL;
523 goto out;
526 if ((ap = attr->__pthread_attrp) == NULL) {
527 ret = EINVAL;
528 goto out;
531 ap->stksize = target->ul_stksiz;
532 ap->stkaddr = target->ul_stk;
533 if (target->ul_usropts & THR_DETACHED) {
534 ap->detachstate = PTHREAD_CREATE_DETACHED;
535 } else {
536 ap->detachstate = PTHREAD_CREATE_JOINABLE;
539 if (target->ul_usropts & THR_DAEMON) {
540 ap->daemonstate = PTHREAD_CREATE_DAEMON_NP;
541 } else {
542 ap->daemonstate = PTHREAD_CREATE_NONDAEMON_NP;
545 if (target->ul_usropts & THR_BOUND) {
546 ap->scope = PTHREAD_SCOPE_SYSTEM;
547 } else {
548 ap->scope = PTHREAD_SCOPE_PROCESS;
550 ap->prio = target->ul_pri;
551 ap->policy = target->ul_policy;
552 ap->inherit = target->ul_ptinherit;
553 ap->guardsize = target->ul_guardsize;
555 ret = 0;
556 out:
557 ulwp_unlock(target, udp);
558 return (ret);