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 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 *
def_thrattr(void)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
pthread_attr_init(pthread_attr_t * attr)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);
72 }
73 return (ENOMEM);
74 }
75
76 /*
77 * pthread_attr_destroy: frees the attribute object and invalidates it
78 * with NULL value.
79 */
80 int
pthread_attr_destroy(pthread_attr_t * attr)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
pthread_attr_clone(pthread_attr_t * attr,const pthread_attr_t * old_attr)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
pthread_attr_equal(const pthread_attr_t * attr1,const pthread_attr_t * attr2)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
pthread_attr_setstacksize(pthread_attr_t * attr,size_t stacksize)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);
139 }
140 return (EINVAL);
141 }
142
143 /*
144 * pthread_attr_getstacksize: gets the user stack size.
145 */
146 #pragma weak _pthread_attr_getstacksize = pthread_attr_getstacksize
147 int
pthread_attr_getstacksize(const pthread_attr_t * attr,size_t * stacksize)148 pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize)
149 {
150 thrattr_t *ap;
151
152 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
153 stacksize != NULL) {
154 *stacksize = ap->stksize;
155 return (0);
156 }
157 return (EINVAL);
158 }
159
160 /*
161 * pthread_attr_setstackaddr: sets the user stack addr.
162 * This is equivalent to stkaddr argument in thr_create().
163 */
164 int
pthread_attr_setstackaddr(pthread_attr_t * attr,void * stackaddr)165 pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr)
166 {
167 thrattr_t *ap;
168
169 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL) {
170 ap->stkaddr = stackaddr;
171 return (0);
172 }
173 return (EINVAL);
174 }
175
176 /*
177 * pthread_attr_getstackaddr: gets the user stack addr.
178 */
179 #pragma weak _pthread_attr_getstackaddr = pthread_attr_getstackaddr
180 int
pthread_attr_getstackaddr(const pthread_attr_t * attr,void ** stackaddr)181 pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr)
182 {
183 thrattr_t *ap;
184
185 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
186 stackaddr != NULL) {
187 *stackaddr = ap->stkaddr;
188 return (0);
189 }
190 return (EINVAL);
191 }
192
193 /*
194 * pthread_attr_setdetachstate: sets the detach state to DETACHED or JOINABLE.
195 * PTHREAD_CREATE_DETACHED is equivalent to thr_create(THR_DETACHED).
196 */
197 int
pthread_attr_setdetachstate(pthread_attr_t * attr,int detachstate)198 pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
199 {
200 thrattr_t *ap;
201
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);
207 }
208 return (EINVAL);
209 }
210
211 /*
212 * pthread_attr_getdetachstate: gets the detach state.
213 */
214 #pragma weak _pthread_attr_getdetachstate = pthread_attr_getdetachstate
215 int
pthread_attr_getdetachstate(const pthread_attr_t * attr,int * detachstate)216 pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
217 {
218 thrattr_t *ap;
219
220 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
221 detachstate != NULL) {
222 *detachstate = ap->detachstate;
223 return (0);
224 }
225 return (EINVAL);
226 }
227
228 /*
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.
232 */
233 int
pthread_attr_setdaemonstate_np(pthread_attr_t * attr,int daemonstate)234 pthread_attr_setdaemonstate_np(pthread_attr_t *attr, int daemonstate)
235 {
236 thrattr_t *ap;
237
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);
243 }
244 return (EINVAL);
245 }
246
247 /*
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.
251 */
252 int
pthread_attr_getdaemonstate_np(const pthread_attr_t * attr,int * daemonstate)253 pthread_attr_getdaemonstate_np(const pthread_attr_t *attr, int *daemonstate)
254 {
255 thrattr_t *ap;
256
257 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
258 daemonstate != NULL) {
259 *daemonstate = ap->daemonstate;
260 return (0);
261 }
262 return (EINVAL);
263 }
264
265 /*
266 * pthread_attr_setscope: sets the scope to SYSTEM or PROCESS.
267 * This is equivalent to setting THR_BOUND flag in thr_create().
268 */
269 int
pthread_attr_setscope(pthread_attr_t * attr,int scope)270 pthread_attr_setscope(pthread_attr_t *attr, int scope)
271 {
272 thrattr_t *ap;
273
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);
279 }
280 return (EINVAL);
281 }
282
283 /*
284 * pthread_attr_getscope: gets the scheduling scope.
285 */
286 #pragma weak _pthread_attr_getscope = pthread_attr_getscope
287 int
pthread_attr_getscope(const pthread_attr_t * attr,int * scope)288 pthread_attr_getscope(const pthread_attr_t *attr, int *scope)
289 {
290 thrattr_t *ap;
291
292 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
293 scope != NULL) {
294 *scope = ap->scope;
295 return (0);
296 }
297 return (EINVAL);
298 }
299
300 /*
301 * pthread_attr_setinheritsched: sets the scheduling parameters to be
302 * EXPLICIT or INHERITED from parent thread.
303 */
304 int
pthread_attr_setinheritsched(pthread_attr_t * attr,int inherit)305 pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit)
306 {
307 thrattr_t *ap;
308
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);
314 }
315 return (EINVAL);
316 }
317
318 /*
319 * pthread_attr_getinheritsched: gets the scheduling inheritance.
320 */
321 #pragma weak _pthread_attr_getinheritsched = pthread_attr_getinheritsched
322 int
pthread_attr_getinheritsched(const pthread_attr_t * attr,int * inherit)323 pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inherit)
324 {
325 thrattr_t *ap;
326
327 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
328 inherit != NULL) {
329 *inherit = ap->inherit;
330 return (0);
331 }
332 return (EINVAL);
333 }
334
335 /*
336 * pthread_attr_setschedpolicy: sets the scheduling policy.
337 */
338 int
pthread_attr_setschedpolicy(pthread_attr_t * attr,int policy)339 pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
340 {
341 thrattr_t *ap;
342
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);
347 }
348 return (EINVAL);
349 }
350
351 /*
352 * pthread_attr_getpolicy: gets the scheduling policy.
353 */
354 #pragma weak _pthread_attr_getschedpolicy = pthread_attr_getschedpolicy
355 int
pthread_attr_getschedpolicy(const pthread_attr_t * attr,int * policy)356 pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
357 {
358 thrattr_t *ap;
359
360 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
361 policy != NULL) {
362 *policy = ap->policy;
363 return (0);
364 }
365 return (EINVAL);
366 }
367
368 /*
369 * pthread_attr_setschedparam: sets the scheduling parameters.
370 * Currently, we support priority only.
371 */
372 int
pthread_attr_setschedparam(pthread_attr_t * attr,const struct sched_param * param)373 pthread_attr_setschedparam(pthread_attr_t *attr,
374 const struct sched_param *param)
375 {
376 thrattr_t *ap;
377
378 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
379 param != NULL) {
380 ap->prio = param->sched_priority;
381 return (0);
382 }
383 return (EINVAL);
384 }
385
386 /*
387 * pthread_attr_getschedparam: gets the scheduling parameters.
388 * Currently, only priority is defined as sched parameter.
389 */
390 #pragma weak _pthread_attr_getschedparam = pthread_attr_getschedparam
391 int
pthread_attr_getschedparam(const pthread_attr_t * attr,struct sched_param * param)392 pthread_attr_getschedparam(const pthread_attr_t *attr,
393 struct sched_param *param)
394 {
395 thrattr_t *ap;
396
397 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
398 param != NULL) {
399 param->sched_priority = ap->prio;
400 return (0);
401 }
402 return (EINVAL);
403 }
404
405 /*
406 * UNIX98
407 * pthread_attr_setguardsize: sets the guardsize
408 */
409 int
pthread_attr_setguardsize(pthread_attr_t * attr,size_t guardsize)410 pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize)
411 {
412 thrattr_t *ap;
413
414 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL) {
415 ap->guardsize = guardsize;
416 return (0);
417 }
418 return (EINVAL);
419 }
420
421 /*
422 * UNIX98
423 * pthread_attr_getguardsize: gets the guardsize
424 */
425 int
pthread_attr_getguardsize(const pthread_attr_t * attr,size_t * guardsize)426 pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize)
427 {
428 thrattr_t *ap;
429
430 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
431 guardsize != NULL) {
432 *guardsize = ap->guardsize;
433 return (0);
434 }
435 return (EINVAL);
436 }
437
438 /*
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().
442 */
443 int
pthread_attr_setstack(pthread_attr_t * attr,void * stackaddr,size_t stacksize)444 pthread_attr_setstack(pthread_attr_t *attr,
445 void *stackaddr, size_t stacksize)
446 {
447 thrattr_t *ap;
448
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);
457 }
458 return (EINVAL);
459 }
460
461 /*
462 * pthread_attr_getstack: gets the user stack addr and stack size.
463 */
464 int
pthread_attr_getstack(const pthread_attr_t * attr,void ** stackaddr,size_t * stacksize)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
pthread_attr_get_np(pthread_t tid,pthread_attr_t * attr)499 pthread_attr_get_np(pthread_t tid, pthread_attr_t *attr)
500 {
501 int ret;
502 ulwp_t *self = curthread;
503 uberdata_t *udp = self->ul_uberdata;
504 ulwp_t *target = NULL;
505 thrattr_t *ap;
506
507 /*
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.
511 */
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);
519 }
520
521 if (attr == NULL) {
522 ret = EINVAL;
523 goto out;
524 }
525
526 if ((ap = attr->__pthread_attrp) == NULL) {
527 ret = EINVAL;
528 goto out;
529 }
530
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;
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 }
560