1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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 *
def_thrattr(void)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
pthread_attr_init(pthread_attr_t * attr)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);
75 }
76 return (ENOMEM);
77 }
78
79 /*
80 * pthread_attr_destroy: frees the attribute object and invalidates it
81 * with NULL value.
82 */
83 int
pthread_attr_destroy(pthread_attr_t * attr)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
pthread_attr_clone(pthread_attr_t * attr,const pthread_attr_t * old_attr)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
pthread_attr_equal(const pthread_attr_t * attr1,const pthread_attr_t * attr2)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
pthread_attr_setstacksize(pthread_attr_t * attr,size_t stacksize)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);
142 }
143 return (EINVAL);
144 }
145
146 /*
147 * pthread_attr_getstacksize: gets the user stack size.
148 */
149 #pragma weak _pthread_attr_getstacksize = pthread_attr_getstacksize
150 int
pthread_attr_getstacksize(const pthread_attr_t * attr,size_t * stacksize)151 pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize)
152 {
153 thrattr_t *ap;
154
155 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
156 stacksize != NULL) {
157 *stacksize = ap->stksize;
158 return (0);
159 }
160 return (EINVAL);
161 }
162
163 /*
164 * pthread_attr_setstackaddr: sets the user stack addr.
165 * This is equivalent to stkaddr argument in thr_create().
166 */
167 int
pthread_attr_setstackaddr(pthread_attr_t * attr,void * stackaddr)168 pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr)
169 {
170 thrattr_t *ap;
171
172 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL) {
173 ap->stkaddr = stackaddr;
174 return (0);
175 }
176 return (EINVAL);
177 }
178
179 /*
180 * pthread_attr_getstackaddr: gets the user stack addr.
181 */
182 #pragma weak _pthread_attr_getstackaddr = pthread_attr_getstackaddr
183 int
pthread_attr_getstackaddr(const pthread_attr_t * attr,void ** stackaddr)184 pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr)
185 {
186 thrattr_t *ap;
187
188 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
189 stackaddr != NULL) {
190 *stackaddr = ap->stkaddr;
191 return (0);
192 }
193 return (EINVAL);
194 }
195
196 /*
197 * pthread_attr_setdetachstate: sets the detach state to DETACHED or JOINABLE.
198 * PTHREAD_CREATE_DETACHED is equivalent to thr_create(THR_DETACHED).
199 */
200 int
pthread_attr_setdetachstate(pthread_attr_t * attr,int detachstate)201 pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
202 {
203 thrattr_t *ap;
204
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);
210 }
211 return (EINVAL);
212 }
213
214 /*
215 * pthread_attr_getdetachstate: gets the detach state.
216 */
217 #pragma weak _pthread_attr_getdetachstate = pthread_attr_getdetachstate
218 int
pthread_attr_getdetachstate(const pthread_attr_t * attr,int * detachstate)219 pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
220 {
221 thrattr_t *ap;
222
223 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
224 detachstate != NULL) {
225 *detachstate = ap->detachstate;
226 return (0);
227 }
228 return (EINVAL);
229 }
230
231 /*
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.
235 */
236 int
pthread_attr_setdaemonstate_np(pthread_attr_t * attr,int daemonstate)237 pthread_attr_setdaemonstate_np(pthread_attr_t *attr, int daemonstate)
238 {
239 thrattr_t *ap;
240
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);
246 }
247 return (EINVAL);
248 }
249
250 /*
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.
254 */
255 int
pthread_attr_getdaemonstate_np(const pthread_attr_t * attr,int * daemonstate)256 pthread_attr_getdaemonstate_np(const pthread_attr_t *attr, int *daemonstate)
257 {
258 thrattr_t *ap;
259
260 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
261 daemonstate != NULL) {
262 *daemonstate = ap->daemonstate;
263 return (0);
264 }
265 return (EINVAL);
266 }
267
268 /*
269 * pthread_attr_setscope: sets the scope to SYSTEM or PROCESS.
270 * This is equivalent to setting THR_BOUND flag in thr_create().
271 */
272 int
pthread_attr_setscope(pthread_attr_t * attr,int scope)273 pthread_attr_setscope(pthread_attr_t *attr, int scope)
274 {
275 thrattr_t *ap;
276
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);
282 }
283 return (EINVAL);
284 }
285
286 /*
287 * pthread_attr_getscope: gets the scheduling scope.
288 */
289 #pragma weak _pthread_attr_getscope = pthread_attr_getscope
290 int
pthread_attr_getscope(const pthread_attr_t * attr,int * scope)291 pthread_attr_getscope(const pthread_attr_t *attr, int *scope)
292 {
293 thrattr_t *ap;
294
295 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
296 scope != NULL) {
297 *scope = ap->scope;
298 return (0);
299 }
300 return (EINVAL);
301 }
302
303 /*
304 * pthread_attr_setinheritsched: sets the scheduling parameters to be
305 * EXPLICIT or INHERITED from parent thread.
306 */
307 int
pthread_attr_setinheritsched(pthread_attr_t * attr,int inherit)308 pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit)
309 {
310 thrattr_t *ap;
311
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);
317 }
318 return (EINVAL);
319 }
320
321 /*
322 * pthread_attr_getinheritsched: gets the scheduling inheritance.
323 */
324 #pragma weak _pthread_attr_getinheritsched = pthread_attr_getinheritsched
325 int
pthread_attr_getinheritsched(const pthread_attr_t * attr,int * inherit)326 pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inherit)
327 {
328 thrattr_t *ap;
329
330 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
331 inherit != NULL) {
332 *inherit = ap->inherit;
333 return (0);
334 }
335 return (EINVAL);
336 }
337
338 /*
339 * pthread_attr_setschedpolicy: sets the scheduling policy.
340 */
341 int
pthread_attr_setschedpolicy(pthread_attr_t * attr,int policy)342 pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
343 {
344 thrattr_t *ap;
345
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);
350 }
351 return (EINVAL);
352 }
353
354 /*
355 * pthread_attr_getpolicy: gets the scheduling policy.
356 */
357 #pragma weak _pthread_attr_getschedpolicy = pthread_attr_getschedpolicy
358 int
pthread_attr_getschedpolicy(const pthread_attr_t * attr,int * policy)359 pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
360 {
361 thrattr_t *ap;
362
363 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
364 policy != NULL) {
365 *policy = ap->policy;
366 return (0);
367 }
368 return (EINVAL);
369 }
370
371 /*
372 * pthread_attr_setschedparam: sets the scheduling parameters.
373 * Currently, we support priority only.
374 */
375 int
pthread_attr_setschedparam(pthread_attr_t * attr,const struct sched_param * param)376 pthread_attr_setschedparam(pthread_attr_t *attr,
377 const struct sched_param *param)
378 {
379 thrattr_t *ap;
380
381 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
382 param != NULL) {
383 ap->prio = param->sched_priority;
384 return (0);
385 }
386 return (EINVAL);
387 }
388
389 /*
390 * pthread_attr_getschedparam: gets the scheduling parameters.
391 * Currently, only priority is defined as sched parameter.
392 */
393 #pragma weak _pthread_attr_getschedparam = pthread_attr_getschedparam
394 int
pthread_attr_getschedparam(const pthread_attr_t * attr,struct sched_param * param)395 pthread_attr_getschedparam(const pthread_attr_t *attr,
396 struct sched_param *param)
397 {
398 thrattr_t *ap;
399
400 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
401 param != NULL) {
402 param->sched_priority = ap->prio;
403 return (0);
404 }
405 return (EINVAL);
406 }
407
408 /*
409 * UNIX98
410 * pthread_attr_setguardsize: sets the guardsize
411 */
412 int
pthread_attr_setguardsize(pthread_attr_t * attr,size_t guardsize)413 pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize)
414 {
415 thrattr_t *ap;
416
417 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL) {
418 ap->guardsize = guardsize;
419 return (0);
420 }
421 return (EINVAL);
422 }
423
424 /*
425 * UNIX98
426 * pthread_attr_getguardsize: gets the guardsize
427 */
428 int
pthread_attr_getguardsize(const pthread_attr_t * attr,size_t * guardsize)429 pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize)
430 {
431 thrattr_t *ap;
432
433 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
434 guardsize != NULL) {
435 *guardsize = ap->guardsize;
436 return (0);
437 }
438 return (EINVAL);
439 }
440
441 /*
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().
445 */
446 int
pthread_attr_setstack(pthread_attr_t * attr,void * stackaddr,size_t stacksize)447 pthread_attr_setstack(pthread_attr_t *attr,
448 void *stackaddr, size_t stacksize)
449 {
450 thrattr_t *ap;
451
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);
460 }
461 return (EINVAL);
462 }
463
464 /*
465 * pthread_attr_getstack: gets the user stack addr and stack size.
466 */
467 int
pthread_attr_getstack(const pthread_attr_t * attr,void ** stackaddr,size_t * stacksize)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
pthread_attr_setname_np(pthread_attr_t * attr,const char * name)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
pthread_attr_getname_np(pthread_attr_t * attr,char * buf,size_t len)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, its 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 subtly different in
540 * a rather important way. While pthread_attr_get_np() expects to be given
541 * a pthread_attr_t that has had pthread_attr_init() called on it,
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
pthread_attr_get_np(pthread_t tid,pthread_attr_t * attr)549 pthread_attr_get_np(pthread_t tid, pthread_attr_t *attr)
550 {
551 int ret;
552 ulwp_t *self = curthread;
553 uberdata_t *udp = self->ul_uberdata;
554 ulwp_t *target = NULL;
555 thrattr_t *ap;
556
557 /*
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 ulwp
560 * lock.
561 */
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);
569 }
570
571 if (attr == NULL) {
572 ret = EINVAL;
573 goto out;
574 }
575
576 if ((ap = attr->__pthread_attrp) == NULL) {
577 ret = EINVAL;
578 goto out;
579 }
580
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;
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 }
611