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