8158 Want named threads API
[unleashed.git] / usr / src / lib / libc / port / threads / pthr_attr.c
blob7cfc9701209b3758f61057fafb388a42b092a0a1
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 2018, Joyent, Inc.
31 #include "lint.h"
32 #include "thr_uberdata.h"
33 #include <sys/ctype.h>
34 #include <strings.h>
35 #include <sched.h>
38 * Default attribute object for pthread_create() with NULL attr pointer.
39 * Note that the 'guardsize' field is initialized on the first call.
41 const thrattr_t *
42 def_thrattr(void)
44 static thrattr_t thrattr = {
45 0, /* stksize */
46 NULL, /* stkaddr */
47 PTHREAD_CREATE_JOINABLE, /* detachstate */
48 PTHREAD_CREATE_NONDAEMON_NP, /* daemonstate */
49 PTHREAD_SCOPE_PROCESS, /* scope */
50 0, /* prio */
51 SCHED_OTHER, /* policy */
52 PTHREAD_INHERIT_SCHED, /* inherit */
53 0, /* guardsize */
54 { 0 } /* name */
56 if (thrattr.guardsize == 0)
57 thrattr.guardsize = _sysconf(_SC_PAGESIZE);
58 return (&thrattr);
62 * pthread_attr_init: allocates the attribute object and initializes it
63 * with the default values.
65 #pragma weak _pthread_attr_init = pthread_attr_init
66 int
67 pthread_attr_init(pthread_attr_t *attr)
69 thrattr_t *ap;
71 if ((ap = lmalloc(sizeof (thrattr_t))) != NULL) {
72 *ap = *def_thrattr();
73 attr->__pthread_attrp = ap;
74 return (0);
76 return (ENOMEM);
80 * pthread_attr_destroy: frees the attribute object and invalidates it
81 * with NULL value.
83 int
84 pthread_attr_destroy(pthread_attr_t *attr)
86 if (attr == NULL || attr->__pthread_attrp == NULL)
87 return (EINVAL);
88 lfree(attr->__pthread_attrp, sizeof (thrattr_t));
89 attr->__pthread_attrp = NULL;
90 return (0);
94 * pthread_attr_clone: make a copy of a pthread_attr_t.
96 int
97 pthread_attr_clone(pthread_attr_t *attr, const pthread_attr_t *old_attr)
99 thrattr_t *ap;
100 const thrattr_t *old_ap =
101 old_attr ? old_attr->__pthread_attrp : def_thrattr();
103 if (old_ap == NULL)
104 return (EINVAL);
105 if ((ap = lmalloc(sizeof (thrattr_t))) == NULL)
106 return (ENOMEM);
107 *ap = *old_ap;
108 attr->__pthread_attrp = ap;
109 return (0);
113 * pthread_attr_equal: compare two pthread_attr_t's, return 1 if equal.
114 * A NULL pthread_attr_t pointer implies default attributes.
115 * This is a consolidation-private interface, for librt.
118 pthread_attr_equal(const pthread_attr_t *attr1, const pthread_attr_t *attr2)
120 const thrattr_t *ap1 = attr1 ? attr1->__pthread_attrp : def_thrattr();
121 const thrattr_t *ap2 = attr2 ? attr2->__pthread_attrp : def_thrattr();
123 if (ap1 == NULL || ap2 == NULL)
124 return (0);
125 return (ap1 == ap2 || memcmp(ap1, ap2, sizeof (thrattr_t)) == 0);
129 * pthread_attr_setstacksize: sets the user stack size, minimum should
130 * be PTHREAD_STACK_MIN (MINSTACK).
131 * This is equivalent to stksize argument in thr_create().
134 pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
136 thrattr_t *ap;
138 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
139 stacksize >= MINSTACK) {
140 ap->stksize = stacksize;
141 return (0);
143 return (EINVAL);
147 * pthread_attr_getstacksize: gets the user stack size.
149 #pragma weak _pthread_attr_getstacksize = pthread_attr_getstacksize
151 pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize)
153 thrattr_t *ap;
155 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
156 stacksize != NULL) {
157 *stacksize = ap->stksize;
158 return (0);
160 return (EINVAL);
164 * pthread_attr_setstackaddr: sets the user stack addr.
165 * This is equivalent to stkaddr argument in thr_create().
168 pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr)
170 thrattr_t *ap;
172 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL) {
173 ap->stkaddr = stackaddr;
174 return (0);
176 return (EINVAL);
180 * pthread_attr_getstackaddr: gets the user stack addr.
182 #pragma weak _pthread_attr_getstackaddr = pthread_attr_getstackaddr
184 pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr)
186 thrattr_t *ap;
188 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
189 stackaddr != NULL) {
190 *stackaddr = ap->stkaddr;
191 return (0);
193 return (EINVAL);
197 * pthread_attr_setdetachstate: sets the detach state to DETACHED or JOINABLE.
198 * PTHREAD_CREATE_DETACHED is equivalent to thr_create(THR_DETACHED).
201 pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
203 thrattr_t *ap;
205 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
206 (detachstate == PTHREAD_CREATE_DETACHED ||
207 detachstate == PTHREAD_CREATE_JOINABLE)) {
208 ap->detachstate = detachstate;
209 return (0);
211 return (EINVAL);
215 * pthread_attr_getdetachstate: gets the detach state.
217 #pragma weak _pthread_attr_getdetachstate = pthread_attr_getdetachstate
219 pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
221 thrattr_t *ap;
223 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
224 detachstate != NULL) {
225 *detachstate = ap->detachstate;
226 return (0);
228 return (EINVAL);
232 * pthread_attr_setdaemonstate_np: sets the daemon state to DAEMON or NONDAEMON.
233 * PTHREAD_CREATE_DAEMON is equivalent to thr_create(THR_DAEMON).
234 * For now, this is a private interface in libc.
237 pthread_attr_setdaemonstate_np(pthread_attr_t *attr, int daemonstate)
239 thrattr_t *ap;
241 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
242 (daemonstate == PTHREAD_CREATE_DAEMON_NP ||
243 daemonstate == PTHREAD_CREATE_NONDAEMON_NP)) {
244 ap->daemonstate = daemonstate;
245 return (0);
247 return (EINVAL);
251 * pthread_attr_getdaemonstate_np: gets the daemon state.
252 * For now, this is a private interface in libc, but it is exposed in the
253 * mapfile for the purposes of testing only.
256 pthread_attr_getdaemonstate_np(const pthread_attr_t *attr, int *daemonstate)
258 thrattr_t *ap;
260 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
261 daemonstate != NULL) {
262 *daemonstate = ap->daemonstate;
263 return (0);
265 return (EINVAL);
269 * pthread_attr_setscope: sets the scope to SYSTEM or PROCESS.
270 * This is equivalent to setting THR_BOUND flag in thr_create().
273 pthread_attr_setscope(pthread_attr_t *attr, int scope)
275 thrattr_t *ap;
277 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
278 (scope == PTHREAD_SCOPE_SYSTEM ||
279 scope == PTHREAD_SCOPE_PROCESS)) {
280 ap->scope = scope;
281 return (0);
283 return (EINVAL);
287 * pthread_attr_getscope: gets the scheduling scope.
289 #pragma weak _pthread_attr_getscope = pthread_attr_getscope
291 pthread_attr_getscope(const pthread_attr_t *attr, int *scope)
293 thrattr_t *ap;
295 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
296 scope != NULL) {
297 *scope = ap->scope;
298 return (0);
300 return (EINVAL);
304 * pthread_attr_setinheritsched: sets the scheduling parameters to be
305 * EXPLICIT or INHERITED from parent thread.
308 pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit)
310 thrattr_t *ap;
312 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
313 (inherit == PTHREAD_EXPLICIT_SCHED ||
314 inherit == PTHREAD_INHERIT_SCHED)) {
315 ap->inherit = inherit;
316 return (0);
318 return (EINVAL);
322 * pthread_attr_getinheritsched: gets the scheduling inheritance.
324 #pragma weak _pthread_attr_getinheritsched = pthread_attr_getinheritsched
326 pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inherit)
328 thrattr_t *ap;
330 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
331 inherit != NULL) {
332 *inherit = ap->inherit;
333 return (0);
335 return (EINVAL);
339 * pthread_attr_setschedpolicy: sets the scheduling policy.
342 pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
344 thrattr_t *ap;
346 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
347 policy != SCHED_SYS && get_info_by_policy(policy) != NULL) {
348 ap->policy = policy;
349 return (0);
351 return (EINVAL);
355 * pthread_attr_getpolicy: gets the scheduling policy.
357 #pragma weak _pthread_attr_getschedpolicy = pthread_attr_getschedpolicy
359 pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
361 thrattr_t *ap;
363 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
364 policy != NULL) {
365 *policy = ap->policy;
366 return (0);
368 return (EINVAL);
372 * pthread_attr_setschedparam: sets the scheduling parameters.
373 * Currently, we support priority only.
376 pthread_attr_setschedparam(pthread_attr_t *attr,
377 const struct sched_param *param)
379 thrattr_t *ap;
381 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
382 param != NULL) {
383 ap->prio = param->sched_priority;
384 return (0);
386 return (EINVAL);
390 * pthread_attr_getschedparam: gets the scheduling parameters.
391 * Currently, only priority is defined as sched parameter.
393 #pragma weak _pthread_attr_getschedparam = pthread_attr_getschedparam
395 pthread_attr_getschedparam(const pthread_attr_t *attr,
396 struct sched_param *param)
398 thrattr_t *ap;
400 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
401 param != NULL) {
402 param->sched_priority = ap->prio;
403 return (0);
405 return (EINVAL);
409 * UNIX98
410 * pthread_attr_setguardsize: sets the guardsize
413 pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize)
415 thrattr_t *ap;
417 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL) {
418 ap->guardsize = guardsize;
419 return (0);
421 return (EINVAL);
425 * UNIX98
426 * pthread_attr_getguardsize: gets the guardsize
429 pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize)
431 thrattr_t *ap;
433 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
434 guardsize != NULL) {
435 *guardsize = ap->guardsize;
436 return (0);
438 return (EINVAL);
442 * pthread_attr_setstack: sets the user stack addr and stack size.
443 * This is equivalent to the stack_base and stack_size arguments
444 * to thr_create().
447 pthread_attr_setstack(pthread_attr_t *attr,
448 void *stackaddr, size_t stacksize)
450 thrattr_t *ap;
452 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
453 stacksize >= MINSTACK) {
454 ap->stkaddr = stackaddr;
455 ap->stksize = stacksize;
456 if (stackaddr != NULL &&
457 setup_top_frame(stackaddr, stacksize, NULL) == NULL)
458 return (EACCES);
459 return (0);
461 return (EINVAL);
465 * pthread_attr_getstack: gets the user stack addr and stack size.
468 pthread_attr_getstack(const pthread_attr_t *attr,
469 void **stackaddr, size_t *stacksize)
471 thrattr_t *ap;
473 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
474 stackaddr != NULL && stacksize != NULL) {
475 *stackaddr = ap->stkaddr;
476 *stacksize = ap->stksize;
477 return (0);
479 return (EINVAL);
483 pthread_attr_setname_np(pthread_attr_t *attr, const char *name)
485 thrattr_t *ap;
487 if (attr == NULL || (ap = attr->__pthread_attrp) == NULL)
488 return (EINVAL);
490 if (name == NULL) {
491 bzero(ap->name, sizeof (ap->name));
492 return (0);
495 if (strlen(name) >= sizeof (ap->name))
496 return (ERANGE);
499 * We really want the ASCII version of isprint() here...
501 for (size_t i = 0; name[i] != '\0'; i++) {
502 if (!ISPRINT(name[i]))
503 return (EINVAL);
507 * not having garbage after the end of the string simplifies attr
508 * comparison
510 bzero(ap->name, sizeof (ap->name));
511 (void) strlcpy(ap->name, name, sizeof (ap->name));
512 return (0);
516 pthread_attr_getname_np(pthread_attr_t *attr, char *buf, size_t len)
518 thrattr_t *ap;
520 if (buf == NULL || attr == NULL ||
521 (ap = attr->__pthread_attrp) == NULL)
522 return (EINVAL);
524 if (strlcpy(buf, ap->name, len) > len)
525 return (ERANGE);
526 return (0);
530 * This function is a common BSD extension to pthread which is used to obtain
531 * the attributes of a thread that might have changed after its creation, for
532 * example, it's stack address.
534 * Note, there is no setattr analogue, nor do we desire to add one at this time.
535 * Similarly there is no native threads API analogue (nor should we add one for
536 * C11).
538 * The astute reader may note that there is a GNU version of this called
539 * pthread_getattr_np(). The two functions are similar, but subtley different in
540 * a rather important way. While the pthread_attr_get_np() expects to be given
541 * a pthread_attr_t that has had pthread_attr_init() called on in,
542 * pthread_getattr_np() does not. However, on GNU systems, where the function
543 * originates, the pthread_attr_t is not opaque and thus it is entirely safe to
544 * both call pthread_attr_init() and then call pthread_getattr_np() on the same
545 * attributes object. On illumos, since the pthread_attr_t is opaque, that would
546 * be a memory leak. As such, we don't provide it.
549 pthread_attr_get_np(pthread_t tid, pthread_attr_t *attr)
551 int ret;
552 ulwp_t *self = curthread;
553 uberdata_t *udp = self->ul_uberdata;
554 ulwp_t *target = NULL;
555 thrattr_t *ap;
558 * To ensure that information about the target thread does not change or
559 * disappear while we're trying to interrogate it, we grab the uwlp
560 * lock.
562 if (self->ul_lwpid == tid) {
563 ulwp_lock(self, udp);
564 target = self;
565 } else {
566 target = find_lwp(tid);
567 if (target == NULL)
568 return (ESRCH);
571 if (attr == NULL) {
572 ret = EINVAL;
573 goto out;
576 if ((ap = attr->__pthread_attrp) == NULL) {
577 ret = EINVAL;
578 goto out;
581 ap->stksize = target->ul_stksiz;
582 ap->stkaddr = target->ul_stk;
583 if (target->ul_usropts & THR_DETACHED) {
584 ap->detachstate = PTHREAD_CREATE_DETACHED;
585 } else {
586 ap->detachstate = PTHREAD_CREATE_JOINABLE;
589 if (target->ul_usropts & THR_DAEMON) {
590 ap->daemonstate = PTHREAD_CREATE_DAEMON_NP;
591 } else {
592 ap->daemonstate = PTHREAD_CREATE_NONDAEMON_NP;
595 if (target->ul_usropts & THR_BOUND) {
596 ap->scope = PTHREAD_SCOPE_SYSTEM;
597 } else {
598 ap->scope = PTHREAD_SCOPE_PROCESS;
600 ap->prio = target->ul_pri;
601 ap->policy = target->ul_policy;
602 ap->inherit = target->ul_ptinherit;
603 ap->guardsize = target->ul_guardsize;
604 (void) pthread_getname_np(tid, ap->name, sizeof (ap->name));
606 ret = 0;
607 out:
608 ulwp_unlock(target, udp);
609 return (ret);