xref: /illumos-gate/usr/src/lib/libc/port/threads/pthr_attr.c (revision 8c69cc8fbe729fa7b091e901c4b50508ccc6bb33)
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 *
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);
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
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);
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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