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 2006 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_EXPLICIT_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 #pragma weak pthread_attr_destroy = _pthread_attr_destroy
79 int
80 _pthread_attr_destroy(pthread_attr_t *attr)
81 {
82 	if (attr == NULL || attr->__pthread_attrp == NULL)
83 		return (EINVAL);
84 	lfree(attr->__pthread_attrp, sizeof (thrattr_t));
85 	attr->__pthread_attrp = NULL;
86 	return (0);
87 }
88 
89 /*
90  * _pthread_attr_clone: make a copy of a pthread_attr_t.
91  */
92 int
93 _pthread_attr_clone(pthread_attr_t *attr, const pthread_attr_t *old_attr)
94 {
95 	thrattr_t *ap;
96 	const thrattr_t *old_ap =
97 		old_attr? old_attr->__pthread_attrp : def_thrattr();
98 
99 	if (old_ap == NULL)
100 		return (EINVAL);
101 	if ((ap = lmalloc(sizeof (thrattr_t))) == NULL)
102 		return (ENOMEM);
103 	*ap = *old_ap;
104 	attr->__pthread_attrp = ap;
105 	return (0);
106 }
107 
108 /*
109  * _pthread_attr_equal: compare two pthread_attr_t's, return 1 if equal.
110  * A NULL pthread_attr_t pointer implies default attributes.
111  * This is a consolidation-private interface, for librt.
112  */
113 int
114 _pthread_attr_equal(const pthread_attr_t *attr1, const pthread_attr_t *attr2)
115 {
116 	const thrattr_t *ap1 = attr1? attr1->__pthread_attrp : def_thrattr();
117 	const thrattr_t *ap2 = attr2? attr2->__pthread_attrp : def_thrattr();
118 
119 	if (ap1 == NULL || ap2 == NULL)
120 		return (0);
121 	return (ap1 == ap2 || _memcmp(ap1, ap2, sizeof (thrattr_t)) == 0);
122 }
123 
124 /*
125  * pthread_attr_setstacksize: sets the user stack size, minimum should
126  * be PTHREAD_STACK_MIN (MINSTACK).
127  * This is equivalent to stksize argument in thr_create().
128  */
129 #pragma weak pthread_attr_setstacksize = _pthread_attr_setstacksize
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 #pragma weak pthread_attr_setstackaddr = _pthread_attr_setstackaddr
165 int
166 _pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr)
167 {
168 	thrattr_t *ap;
169 
170 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL) {
171 		ap->stkaddr = stackaddr;
172 		return (0);
173 	}
174 	return (EINVAL);
175 }
176 
177 /*
178  * pthread_attr_getstackaddr: gets the user stack addr.
179  */
180 #pragma weak pthread_attr_getstackaddr = _pthread_attr_getstackaddr
181 int
182 _pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr)
183 {
184 	thrattr_t *ap;
185 
186 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
187 	    stackaddr != NULL) {
188 		*stackaddr = ap->stkaddr;
189 		return (0);
190 	}
191 	return (EINVAL);
192 }
193 
194 /*
195  * pthread_attr_setdetachstate: sets the detach state to DETACHED or JOINABLE.
196  * PTHREAD_CREATE_DETACHED is equivalent to thr_create(THR_DETACHED).
197  */
198 #pragma weak pthread_attr_setdetachstate = _pthread_attr_setdetachstate
199 int
200 _pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
201 {
202 	thrattr_t *ap;
203 
204 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
205 	    (detachstate == PTHREAD_CREATE_DETACHED ||
206 	    detachstate == PTHREAD_CREATE_JOINABLE)) {
207 		ap->detachstate = detachstate;
208 		return (0);
209 	}
210 	return (EINVAL);
211 }
212 
213 /*
214  * pthread_attr_getdetachstate: gets the detach state.
215  */
216 #pragma weak pthread_attr_getdetachstate = _pthread_attr_getdetachstate
217 int
218 _pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
219 {
220 	thrattr_t *ap;
221 
222 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
223 	    detachstate != NULL) {
224 		*detachstate = ap->detachstate;
225 		return (0);
226 	}
227 	return (EINVAL);
228 }
229 
230 /*
231  * pthread_attr_setdaemonstate_np: sets the daemon state to DAEMON or NONDAEMON.
232  * PTHREAD_CREATE_DAEMON is equivalent to thr_create(THR_DAEMON).
233  * For now, this is a private interface in libc.
234  */
235 int
236 _pthread_attr_setdaemonstate_np(pthread_attr_t *attr, int daemonstate)
237 {
238 	thrattr_t *ap;
239 
240 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
241 	    (daemonstate == PTHREAD_CREATE_DAEMON_NP ||
242 	    daemonstate == PTHREAD_CREATE_NONDAEMON_NP)) {
243 		ap->daemonstate = daemonstate;
244 		return (0);
245 	}
246 	return (EINVAL);
247 }
248 
249 /*
250  * pthread_attr_getdaemonstate_np: gets the daemon state.
251  * For now, this is a private interface in libc.
252  */
253 int
254 _pthread_attr_getdaemonstate_np(const pthread_attr_t *attr, int *daemonstate)
255 {
256 	thrattr_t *ap;
257 
258 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
259 	    daemonstate != NULL) {
260 		*daemonstate = ap->daemonstate;
261 		return (0);
262 	}
263 	return (EINVAL);
264 }
265 
266 /*
267  * pthread_attr_setscope: sets the scope to SYSTEM or PROCESS.
268  * This is equivalent to setting THR_BOUND flag in thr_create().
269  */
270 #pragma weak pthread_attr_setscope = _pthread_attr_setscope
271 int
272 _pthread_attr_setscope(pthread_attr_t *attr, int scope)
273 {
274 	thrattr_t *ap;
275 
276 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
277 	    (scope == PTHREAD_SCOPE_SYSTEM ||
278 	    scope == PTHREAD_SCOPE_PROCESS)) {
279 		ap->scope = scope;
280 		return (0);
281 	}
282 	return (EINVAL);
283 }
284 
285 /*
286  * pthread_attr_getscope: gets the scheduling scope.
287  */
288 #pragma weak pthread_attr_getscope = _pthread_attr_getscope
289 int
290 _pthread_attr_getscope(const pthread_attr_t *attr, int *scope)
291 {
292 	thrattr_t *ap;
293 
294 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
295 	    scope != NULL) {
296 		*scope = ap->scope;
297 		return (0);
298 	}
299 	return (EINVAL);
300 }
301 
302 /*
303  * pthread_attr_setinheritsched: sets the scheduling parameters to be
304  * EXPLICIT or INHERITED from parent thread.
305  */
306 #pragma weak pthread_attr_setinheritsched = _pthread_attr_setinheritsched
307 int
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
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 to SCHED_RR,
340  * SCHED_FIFO or SCHED_OTHER.
341  */
342 #pragma weak pthread_attr_setschedpolicy = _pthread_attr_setschedpolicy
343 int
344 _pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
345 {
346 	thrattr_t *ap;
347 
348 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
349 	    (policy == SCHED_OTHER ||
350 	    policy == SCHED_FIFO ||
351 	    policy == SCHED_RR)) {
352 		ap->policy = policy;
353 		return (0);
354 	}
355 	return (EINVAL);
356 }
357 
358 /*
359  * pthread_attr_getpolicy: gets the scheduling policy.
360  */
361 #pragma weak pthread_attr_getschedpolicy = _pthread_attr_getschedpolicy
362 int
363 _pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
364 {
365 	thrattr_t *ap;
366 
367 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
368 	    policy != NULL) {
369 		*policy = ap->policy;
370 		return (0);
371 	}
372 	return (EINVAL);
373 }
374 
375 /*
376  * pthread_attr_setschedparam: sets the scheduling parameters.
377  * Currently, we support priority only.
378  */
379 #pragma weak pthread_attr_setschedparam = _pthread_attr_setschedparam
380 int
381 _pthread_attr_setschedparam(pthread_attr_t *attr,
382 	const struct sched_param *param)
383 {
384 	thrattr_t *ap;
385 	int	policy;
386 	int	pri;
387 
388 	if (attr == NULL || (ap = attr->__pthread_attrp) == NULL)
389 		return (EINVAL);
390 
391 	policy = ap->policy;
392 	pri = param->sched_priority;
393 	if (policy == SCHED_OTHER) {
394 		if ((pri < THREAD_MIN_PRIORITY || pri > THREAD_MAX_PRIORITY) &&
395 		    _validate_rt_prio(policy, pri))
396 			return (EINVAL);
397 	} else if (_validate_rt_prio(policy, pri)) {
398 		return (EINVAL);
399 	}
400 	ap->prio = pri;
401 	return (0);
402 }
403 
404 /*
405  * pthread_attr_getschedparam: gets the scheduling parameters.
406  * Currently, only priority is defined as sched parameter.
407  */
408 #pragma weak pthread_attr_getschedparam = _pthread_attr_getschedparam
409 int
410 _pthread_attr_getschedparam(const pthread_attr_t *attr,
411 					struct sched_param *param)
412 {
413 	thrattr_t *ap;
414 
415 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
416 	    param != NULL) {
417 		param->sched_priority = ap->prio;
418 		return (0);
419 	}
420 	return (EINVAL);
421 }
422 
423 /*
424  * UNIX98
425  * pthread_attr_setguardsize: sets the guardsize
426  */
427 #pragma weak pthread_attr_setguardsize = _pthread_attr_setguardsize
428 int
429 _pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize)
430 {
431 	thrattr_t *ap;
432 
433 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL) {
434 		ap->guardsize = guardsize;
435 		return (0);
436 	}
437 	return (EINVAL);
438 }
439 
440 /*
441  * UNIX98
442  * pthread_attr_getguardsize: gets the guardsize
443  */
444 #pragma weak pthread_attr_getguardsize = _pthread_attr_getguardsize
445 int
446 _pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize)
447 {
448 	thrattr_t *ap;
449 
450 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
451 	    guardsize != NULL) {
452 		*guardsize = ap->guardsize;
453 		return (0);
454 	}
455 	return (EINVAL);
456 }
457 
458 /*
459  * pthread_attr_setstack: sets the user stack addr and stack size.
460  * This is equivalent to the stack_base and stack_size arguments
461  * to thr_create().
462  */
463 #pragma weak pthread_attr_setstack = _pthread_attr_setstack
464 int
465 _pthread_attr_setstack(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 	    stacksize >= MINSTACK) {
472 		ap->stkaddr = stackaddr;
473 		ap->stksize = stacksize;
474 		return (0);
475 	}
476 	return (EINVAL);
477 }
478 
479 /*
480  * pthread_attr_getstack: gets the user stack addr and stack size.
481  */
482 #pragma weak pthread_attr_getstack = _pthread_attr_getstack
483 int
484 _pthread_attr_getstack(const pthread_attr_t *attr,
485 	void **stackaddr, size_t *stacksize)
486 {
487 	thrattr_t *ap;
488 
489 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
490 	    stackaddr != NULL && stacksize != NULL) {
491 		*stackaddr = ap->stkaddr;
492 		*stacksize = ap->stksize;
493 		return (0);
494 	}
495 	return (EINVAL);
496 }
497