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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * Copyright 2015, Joyent, Inc.
29 */
30
31 #include "lint.h"
32 #include "thr_uberdata.h"
33 #include <sched.h>
34
35 /*
36 * Default attribute object for pthread_create() with NULL attr pointer.
37 * Note that the 'guardsize' field is initialized on the first call.
38 */
39 const thrattr_t *
40 def_thrattr(void)
41 {
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 */
52 };
53 if (thrattr.guardsize == 0)
54 thrattr.guardsize = _sysconf(_SC_PAGESIZE);
55 return (&thrattr);
56 }
57
58 /*
59 * pthread_attr_init: allocates the attribute object and initializes it
60 * with the default values.
61 */
62 #pragma weak _pthread_attr_init = pthread_attr_init
63 int
64 pthread_attr_init(pthread_attr_t *attr)
65 {
66 thrattr_t *ap;
67
68 if ((ap = lmalloc(sizeof (thrattr_t))) != NULL) {
69 *ap = *def_thrattr();
70 attr->__pthread_attrp = ap;
71 return (0);
78 * with NULL value.
79 */
80 int
81 pthread_attr_destroy(pthread_attr_t *attr)
82 {
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);
88 }
89
90 /*
91 * pthread_attr_clone: make a copy of a pthread_attr_t.
92 */
93 int
94 pthread_attr_clone(pthread_attr_t *attr, const pthread_attr_t *old_attr)
95 {
96 thrattr_t *ap;
97 const thrattr_t *old_ap =
98 old_attr? old_attr->__pthread_attrp : def_thrattr();
99
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);
107 }
108
109 /*
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.
113 */
114 int
115 pthread_attr_equal(const pthread_attr_t *attr1, const pthread_attr_t *attr2)
116 {
117 const thrattr_t *ap1 = attr1? attr1->__pthread_attrp : def_thrattr();
118 const thrattr_t *ap2 = attr2? attr2->__pthread_attrp : def_thrattr();
119
120 if (ap1 == NULL || ap2 == NULL)
121 return (0);
122 return (ap1 == ap2 || memcmp(ap1, ap2, sizeof (thrattr_t)) == 0);
123 }
124
125 /*
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().
129 */
130 int
131 pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
132 {
133 thrattr_t *ap;
134
135 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
136 stacksize >= MINSTACK) {
137 ap->stksize = stacksize;
138 return (0);
459 }
460
461 /*
462 * pthread_attr_getstack: gets the user stack addr and stack size.
463 */
464 int
465 pthread_attr_getstack(const pthread_attr_t *attr,
466 void **stackaddr, size_t *stacksize)
467 {
468 thrattr_t *ap;
469
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);
475 }
476 return (EINVAL);
477 }
478
479 /*
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.
483 *
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).
487 *
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.
497 */
498 int
534 ap->detachstate = PTHREAD_CREATE_DETACHED;
535 } else {
536 ap->detachstate = PTHREAD_CREATE_JOINABLE;
537 }
538
539 if (target->ul_usropts & THR_DAEMON) {
540 ap->daemonstate = PTHREAD_CREATE_DAEMON_NP;
541 } else {
542 ap->daemonstate = PTHREAD_CREATE_NONDAEMON_NP;
543 }
544
545 if (target->ul_usropts & THR_BOUND) {
546 ap->scope = PTHREAD_SCOPE_SYSTEM;
547 } else {
548 ap->scope = PTHREAD_SCOPE_PROCESS;
549 }
550 ap->prio = target->ul_pri;
551 ap->policy = target->ul_policy;
552 ap->inherit = target->ul_ptinherit;
553 ap->guardsize = target->ul_guardsize;
554
555 ret = 0;
556 out:
557 ulwp_unlock(target, udp);
558 return (ret);
559 }
|
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * Copyright 2018, Joyent, Inc.
29 */
30
31 #include "lint.h"
32 #include "thr_uberdata.h"
33 #include <sys/ctype.h>
34 #include <strings.h>
35 #include <sched.h>
36
37 /*
38 * Default attribute object for pthread_create() with NULL attr pointer.
39 * Note that the 'guardsize' field is initialized on the first call.
40 */
41 const thrattr_t *
42 def_thrattr(void)
43 {
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 */
55 };
56 if (thrattr.guardsize == 0)
57 thrattr.guardsize = _sysconf(_SC_PAGESIZE);
58 return (&thrattr);
59 }
60
61 /*
62 * pthread_attr_init: allocates the attribute object and initializes it
63 * with the default values.
64 */
65 #pragma weak _pthread_attr_init = pthread_attr_init
66 int
67 pthread_attr_init(pthread_attr_t *attr)
68 {
69 thrattr_t *ap;
70
71 if ((ap = lmalloc(sizeof (thrattr_t))) != NULL) {
72 *ap = *def_thrattr();
73 attr->__pthread_attrp = ap;
74 return (0);
81 * with NULL value.
82 */
83 int
84 pthread_attr_destroy(pthread_attr_t *attr)
85 {
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);
91 }
92
93 /*
94 * pthread_attr_clone: make a copy of a pthread_attr_t.
95 */
96 int
97 pthread_attr_clone(pthread_attr_t *attr, const pthread_attr_t *old_attr)
98 {
99 thrattr_t *ap;
100 const thrattr_t *old_ap =
101 old_attr ? old_attr->__pthread_attrp : def_thrattr();
102
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);
110 }
111
112 /*
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.
116 */
117 int
118 pthread_attr_equal(const pthread_attr_t *attr1, const pthread_attr_t *attr2)
119 {
120 const thrattr_t *ap1 = attr1 ? attr1->__pthread_attrp : def_thrattr();
121 const thrattr_t *ap2 = attr2 ? attr2->__pthread_attrp : def_thrattr();
122
123 if (ap1 == NULL || ap2 == NULL)
124 return (0);
125 return (ap1 == ap2 || memcmp(ap1, ap2, sizeof (thrattr_t)) == 0);
126 }
127
128 /*
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().
132 */
133 int
134 pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
135 {
136 thrattr_t *ap;
137
138 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
139 stacksize >= MINSTACK) {
140 ap->stksize = stacksize;
141 return (0);
462 }
463
464 /*
465 * pthread_attr_getstack: gets the user stack addr and stack size.
466 */
467 int
468 pthread_attr_getstack(const pthread_attr_t *attr,
469 void **stackaddr, size_t *stacksize)
470 {
471 thrattr_t *ap;
472
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);
478 }
479 return (EINVAL);
480 }
481
482 int
483 pthread_attr_setname_np(pthread_attr_t *attr, const char *name)
484 {
485 thrattr_t *ap;
486
487 if (attr == NULL || (ap = attr->__pthread_attrp) == NULL)
488 return (EINVAL);
489
490 if (name == NULL) {
491 bzero(ap->name, sizeof (ap->name));
492 return (0);
493 }
494
495 if (strlen(name) >= sizeof (ap->name))
496 return (ERANGE);
497
498 /*
499 * We really want the ASCII version of isprint() here...
500 */
501 for (size_t i = 0; name[i] != '\0'; i++) {
502 if (!ISPRINT(name[i]))
503 return (EINVAL);
504 }
505
506 /*
507 * not having garbage after the end of the string simplifies attr
508 * comparison
509 */
510 bzero(ap->name, sizeof (ap->name));
511 (void) strlcpy(ap->name, name, sizeof (ap->name));
512 return (0);
513 }
514
515 int
516 pthread_attr_getname_np(pthread_attr_t *attr, char *buf, size_t len)
517 {
518 thrattr_t *ap;
519
520 if (buf == NULL || attr == NULL ||
521 (ap = attr->__pthread_attrp) == NULL)
522 return (EINVAL);
523
524 if (strlcpy(buf, ap->name, len) > len)
525 return (ERANGE);
526 return (0);
527 }
528
529 /*
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.
533 *
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).
537 *
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.
547 */
548 int
584 ap->detachstate = PTHREAD_CREATE_DETACHED;
585 } else {
586 ap->detachstate = PTHREAD_CREATE_JOINABLE;
587 }
588
589 if (target->ul_usropts & THR_DAEMON) {
590 ap->daemonstate = PTHREAD_CREATE_DAEMON_NP;
591 } else {
592 ap->daemonstate = PTHREAD_CREATE_NONDAEMON_NP;
593 }
594
595 if (target->ul_usropts & THR_BOUND) {
596 ap->scope = PTHREAD_SCOPE_SYSTEM;
597 } else {
598 ap->scope = PTHREAD_SCOPE_PROCESS;
599 }
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));
605
606 ret = 0;
607 out:
608 ulwp_unlock(target, udp);
609 return (ret);
610 }
|