xref: /illumos-gate/usr/src/lib/libc/port/threads/pthr_attr.c (revision 922d2c76afbee21520ffa2088c4e60dcb80d3945)
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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include "lint.h"
30 #include "thr_uberdata.h"
31 #include <sched.h>
32 
33 /*
34  * Default attribute object for pthread_create() with NULL attr pointer.
35  * Note that the 'guardsize' field is initialized on the first call.
36  */
37 const thrattr_t *
38 def_thrattr(void)
39 {
40 	static thrattr_t thrattr = {
41 		0,				/* stksize */
42 		NULL,				/* stkaddr */
43 		PTHREAD_CREATE_JOINABLE,	/* detachstate */
44 		PTHREAD_CREATE_NONDAEMON_NP,	/* daemonstate */
45 		PTHREAD_SCOPE_PROCESS,		/* scope */
46 		0,				/* prio */
47 		SCHED_OTHER,			/* policy */
48 		PTHREAD_INHERIT_SCHED,		/* inherit */
49 		0				/* guardsize */
50 	};
51 	if (thrattr.guardsize == 0)
52 		thrattr.guardsize = _sysconf(_SC_PAGESIZE);
53 	return (&thrattr);
54 }
55 
56 /*
57  * pthread_attr_init: allocates the attribute object and initializes it
58  * with the default values.
59  */
60 #pragma weak _pthread_attr_init = pthread_attr_init
61 int
62 pthread_attr_init(pthread_attr_t *attr)
63 {
64 	thrattr_t *ap;
65 
66 	if ((ap = lmalloc(sizeof (thrattr_t))) != NULL) {
67 		*ap = *def_thrattr();
68 		attr->__pthread_attrp = ap;
69 		return (0);
70 	}
71 	return (ENOMEM);
72 }
73 
74 /*
75  * pthread_attr_destroy: frees the attribute object and invalidates it
76  * with NULL value.
77  */
78 int
79 pthread_attr_destroy(pthread_attr_t *attr)
80 {
81 	if (attr == NULL || attr->__pthread_attrp == NULL)
82 		return (EINVAL);
83 	lfree(attr->__pthread_attrp, sizeof (thrattr_t));
84 	attr->__pthread_attrp = NULL;
85 	return (0);
86 }
87 
88 /*
89  * pthread_attr_clone: make a copy of a pthread_attr_t.
90  */
91 int
92 pthread_attr_clone(pthread_attr_t *attr, const pthread_attr_t *old_attr)
93 {
94 	thrattr_t *ap;
95 	const thrattr_t *old_ap =
96 	    old_attr? old_attr->__pthread_attrp : def_thrattr();
97 
98 	if (old_ap == NULL)
99 		return (EINVAL);
100 	if ((ap = lmalloc(sizeof (thrattr_t))) == NULL)
101 		return (ENOMEM);
102 	*ap = *old_ap;
103 	attr->__pthread_attrp = ap;
104 	return (0);
105 }
106 
107 /*
108  * pthread_attr_equal: compare two pthread_attr_t's, return 1 if equal.
109  * A NULL pthread_attr_t pointer implies default attributes.
110  * This is a consolidation-private interface, for librt.
111  */
112 int
113 pthread_attr_equal(const pthread_attr_t *attr1, const pthread_attr_t *attr2)
114 {
115 	const thrattr_t *ap1 = attr1? attr1->__pthread_attrp : def_thrattr();
116 	const thrattr_t *ap2 = attr2? attr2->__pthread_attrp : def_thrattr();
117 
118 	if (ap1 == NULL || ap2 == NULL)
119 		return (0);
120 	return (ap1 == ap2 || memcmp(ap1, ap2, sizeof (thrattr_t)) == 0);
121 }
122 
123 /*
124  * pthread_attr_setstacksize: sets the user stack size, minimum should
125  * be PTHREAD_STACK_MIN (MINSTACK).
126  * This is equivalent to stksize argument in thr_create().
127  */
128 int
129 pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
130 {
131 	thrattr_t *ap;
132 
133 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
134 	    stacksize >= MINSTACK) {
135 		ap->stksize = stacksize;
136 		return (0);
137 	}
138 	return (EINVAL);
139 }
140 
141 /*
142  * pthread_attr_getstacksize: gets the user stack size.
143  */
144 #pragma weak _pthread_attr_getstacksize = pthread_attr_getstacksize
145 int
146 pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize)
147 {
148 	thrattr_t *ap;
149 
150 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
151 	    stacksize != NULL) {
152 		*stacksize = ap->stksize;
153 		return (0);
154 	}
155 	return (EINVAL);
156 }
157 
158 /*
159  * pthread_attr_setstackaddr: sets the user stack addr.
160  * This is equivalent to stkaddr argument in thr_create().
161  */
162 int
163 pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr)
164 {
165 	thrattr_t *ap;
166 
167 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL) {
168 		ap->stkaddr = stackaddr;
169 		return (0);
170 	}
171 	return (EINVAL);
172 }
173 
174 /*
175  * pthread_attr_getstackaddr: gets the user stack addr.
176  */
177 #pragma weak _pthread_attr_getstackaddr = pthread_attr_getstackaddr
178 int
179 pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr)
180 {
181 	thrattr_t *ap;
182 
183 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
184 	    stackaddr != NULL) {
185 		*stackaddr = ap->stkaddr;
186 		return (0);
187 	}
188 	return (EINVAL);
189 }
190 
191 /*
192  * pthread_attr_setdetachstate: sets the detach state to DETACHED or JOINABLE.
193  * PTHREAD_CREATE_DETACHED is equivalent to thr_create(THR_DETACHED).
194  */
195 int
196 pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
197 {
198 	thrattr_t *ap;
199 
200 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
201 	    (detachstate == PTHREAD_CREATE_DETACHED ||
202 	    detachstate == PTHREAD_CREATE_JOINABLE)) {
203 		ap->detachstate = detachstate;
204 		return (0);
205 	}
206 	return (EINVAL);
207 }
208 
209 /*
210  * pthread_attr_getdetachstate: gets the detach state.
211  */
212 #pragma weak _pthread_attr_getdetachstate = pthread_attr_getdetachstate
213 int
214 pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
215 {
216 	thrattr_t *ap;
217 
218 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
219 	    detachstate != NULL) {
220 		*detachstate = ap->detachstate;
221 		return (0);
222 	}
223 	return (EINVAL);
224 }
225 
226 /*
227  * pthread_attr_setdaemonstate_np: sets the daemon state to DAEMON or NONDAEMON.
228  * PTHREAD_CREATE_DAEMON is equivalent to thr_create(THR_DAEMON).
229  * For now, this is a private interface in libc.
230  */
231 int
232 pthread_attr_setdaemonstate_np(pthread_attr_t *attr, int daemonstate)
233 {
234 	thrattr_t *ap;
235 
236 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
237 	    (daemonstate == PTHREAD_CREATE_DAEMON_NP ||
238 	    daemonstate == PTHREAD_CREATE_NONDAEMON_NP)) {
239 		ap->daemonstate = daemonstate;
240 		return (0);
241 	}
242 	return (EINVAL);
243 }
244 
245 /*
246  * pthread_attr_getdaemonstate_np: gets the daemon state.
247  * For now, this is a private interface in libc.
248  */
249 int
250 pthread_attr_getdaemonstate_np(const pthread_attr_t *attr, int *daemonstate)
251 {
252 	thrattr_t *ap;
253 
254 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
255 	    daemonstate != NULL) {
256 		*daemonstate = ap->daemonstate;
257 		return (0);
258 	}
259 	return (EINVAL);
260 }
261 
262 /*
263  * pthread_attr_setscope: sets the scope to SYSTEM or PROCESS.
264  * This is equivalent to setting THR_BOUND flag in thr_create().
265  */
266 int
267 pthread_attr_setscope(pthread_attr_t *attr, int scope)
268 {
269 	thrattr_t *ap;
270 
271 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
272 	    (scope == PTHREAD_SCOPE_SYSTEM ||
273 	    scope == PTHREAD_SCOPE_PROCESS)) {
274 		ap->scope = scope;
275 		return (0);
276 	}
277 	return (EINVAL);
278 }
279 
280 /*
281  * pthread_attr_getscope: gets the scheduling scope.
282  */
283 #pragma weak _pthread_attr_getscope = pthread_attr_getscope
284 int
285 pthread_attr_getscope(const pthread_attr_t *attr, int *scope)
286 {
287 	thrattr_t *ap;
288 
289 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
290 	    scope != NULL) {
291 		*scope = ap->scope;
292 		return (0);
293 	}
294 	return (EINVAL);
295 }
296 
297 /*
298  * pthread_attr_setinheritsched: sets the scheduling parameters to be
299  * EXPLICIT or INHERITED from parent thread.
300  */
301 int
302 pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit)
303 {
304 	thrattr_t *ap;
305 
306 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
307 	    (inherit == PTHREAD_EXPLICIT_SCHED ||
308 	    inherit == PTHREAD_INHERIT_SCHED)) {
309 		ap->inherit = inherit;
310 		return (0);
311 	}
312 	return (EINVAL);
313 }
314 
315 /*
316  * pthread_attr_getinheritsched: gets the scheduling inheritance.
317  */
318 #pragma weak _pthread_attr_getinheritsched = pthread_attr_getinheritsched
319 int
320 pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inherit)
321 {
322 	thrattr_t *ap;
323 
324 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
325 	    inherit != NULL) {
326 		*inherit = ap->inherit;
327 		return (0);
328 	}
329 	return (EINVAL);
330 }
331 
332 /*
333  * pthread_attr_setschedpolicy: sets the scheduling policy.
334  */
335 int
336 pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
337 {
338 	thrattr_t *ap;
339 
340 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
341 	    policy != SCHED_SYS && get_info_by_policy(policy) != NULL) {
342 		ap->policy = policy;
343 		return (0);
344 	}
345 	return (EINVAL);
346 }
347 
348 /*
349  * pthread_attr_getpolicy: gets the scheduling policy.
350  */
351 #pragma weak _pthread_attr_getschedpolicy = pthread_attr_getschedpolicy
352 int
353 pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
354 {
355 	thrattr_t *ap;
356 
357 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
358 	    policy != NULL) {
359 		*policy = ap->policy;
360 		return (0);
361 	}
362 	return (EINVAL);
363 }
364 
365 /*
366  * pthread_attr_setschedparam: sets the scheduling parameters.
367  * Currently, we support priority only.
368  */
369 int
370 pthread_attr_setschedparam(pthread_attr_t *attr,
371 	const struct sched_param *param)
372 {
373 	thrattr_t *ap;
374 
375 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
376 	    param != NULL) {
377 		ap->prio = param->sched_priority;
378 		return (0);
379 	}
380 	return (EINVAL);
381 }
382 
383 /*
384  * pthread_attr_getschedparam: gets the scheduling parameters.
385  * Currently, only priority is defined as sched parameter.
386  */
387 #pragma weak _pthread_attr_getschedparam = pthread_attr_getschedparam
388 int
389 pthread_attr_getschedparam(const pthread_attr_t *attr,
390 					struct sched_param *param)
391 {
392 	thrattr_t *ap;
393 
394 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
395 	    param != NULL) {
396 		param->sched_priority = ap->prio;
397 		return (0);
398 	}
399 	return (EINVAL);
400 }
401 
402 /*
403  * UNIX98
404  * pthread_attr_setguardsize: sets the guardsize
405  */
406 int
407 pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize)
408 {
409 	thrattr_t *ap;
410 
411 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL) {
412 		ap->guardsize = guardsize;
413 		return (0);
414 	}
415 	return (EINVAL);
416 }
417 
418 /*
419  * UNIX98
420  * pthread_attr_getguardsize: gets the guardsize
421  */
422 int
423 pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize)
424 {
425 	thrattr_t *ap;
426 
427 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
428 	    guardsize != NULL) {
429 		*guardsize = ap->guardsize;
430 		return (0);
431 	}
432 	return (EINVAL);
433 }
434 
435 /*
436  * pthread_attr_setstack: sets the user stack addr and stack size.
437  * This is equivalent to the stack_base and stack_size arguments
438  * to thr_create().
439  */
440 int
441 pthread_attr_setstack(pthread_attr_t *attr,
442 	void *stackaddr, size_t stacksize)
443 {
444 	thrattr_t *ap;
445 
446 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
447 	    stacksize >= MINSTACK) {
448 		ap->stkaddr = stackaddr;
449 		ap->stksize = stacksize;
450 		return (0);
451 	}
452 	return (EINVAL);
453 }
454 
455 /*
456  * pthread_attr_getstack: gets the user stack addr and stack size.
457  */
458 int
459 pthread_attr_getstack(const pthread_attr_t *attr,
460 	void **stackaddr, size_t *stacksize)
461 {
462 	thrattr_t *ap;
463 
464 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
465 	    stackaddr != NULL && stacksize != NULL) {
466 		*stackaddr = ap->stkaddr;
467 		*stacksize = ap->stksize;
468 		return (0);
469 	}
470 	return (EINVAL);
471 }
472