1 /*
2  * Copyright (c) 2003 Craig Rodrigues <rodrigc@attbi.com>.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by Craig Rodrigues.
16  * 4. Neither the name of the author nor the names of any co-contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY CRAIG RODRIGUES AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  */
33 
34 /*
35  * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.com>.
36  * Copyright (C) 2001 Jason Evans <jasone@freebsd.org>.
37  * Copyright (c) 2002,2003 Alexey Zelkin <phantom@FreeBSD.org>
38  * All rights reserved.
39  *
40  * Redistribution and use in source and binary forms, with or without
41  * modification, are permitted provided that the following conditions
42  * are met:
43  * 1. Redistributions of source code must retain the above copyright
44  *    notice(s), this list of conditions and the following disclaimer
45  *    unmodified other than the allowable addition of one or more
46  *    copyright notices.
47  * 2. Redistributions in binary form must reproduce the above copyright
48  *    notice(s), this list of conditions and the following disclaimer in
49  *    the documentation and/or other materials provided with the
50  *    distribution.
51  *
52  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
53  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
55  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
56  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
57  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
58  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
59  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
60  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
61  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
62  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
63  */
64 
65 /*
66  * Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>.
67  * All rights reserved.
68  *
69  * Redistribution and use in source and binary forms, with or without
70  * modification, are permitted provided that the following conditions
71  * are met:
72  * 1. Redistributions of source code must retain the above copyright
73  *    notice, this list of conditions and the following disclaimer.
74  * 2. Redistributions in binary form must reproduce the above copyright
75  *    notice, this list of conditions and the following disclaimer in the
76  *    documentation and/or other materials provided with the distribution.
77  * 3. All advertising materials mentioning features or use of this software
78  *    must display the following acknowledgement:
79  *	This product includes software developed by John Birrell.
80  * 4. Neither the name of the author nor the names of any co-contributors
81  *    may be used to endorse or promote products derived from this software
82  *    without specific prior written permission.
83  *
84  * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
85  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
86  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
87  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
88  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
89  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
90  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
91  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
92  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
93  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
94  * SUCH DAMAGE.
95  *
96  * $DragonFly: src/lib/libthread_xu/thread/thr_attr.c,v 1.3 2005/03/29 19:26:20 joerg Exp $
97  */
98 
99 #include <machine/tls.h>
100 
101 #include <errno.h>
102 #include <pthread.h>
103 #include <stdlib.h>
104 #include <string.h>
105 #include <pthread_np.h>
106 
107 #include "thr_private.h"
108 
109 __weak_reference(_pthread_attr_destroy, pthread_attr_destroy);
110 
111 int
112 _pthread_attr_destroy(pthread_attr_t *attr)
113 {
114 	int	ret;
115 
116 	/* Check for invalid arguments: */
117 	if (attr == NULL || *attr == NULL)
118 		/* Invalid argument: */
119 		ret = EINVAL;
120 	else {
121 		/* Free the memory allocated to the attribute object: */
122 		free(*attr);
123 
124 		/*
125 		 * Leave the attribute pointer NULL now that the memory
126 		 * has been freed:
127 		 */
128 		*attr = NULL;
129 		ret = 0;
130 	}
131 	return(ret);
132 }
133 
134 __weak_reference(_pthread_attr_get_np, pthread_attr_get_np);
135 
136 int
137 _pthread_attr_get_np(pthread_t pid, pthread_attr_t *dst)
138 {
139 	struct pthread *curthread;
140 	struct pthread_attr attr;
141 	int	ret;
142 
143 	if (pid == NULL || dst == NULL || *dst == NULL)
144 		return (EINVAL);
145 
146 	curthread = tls_get_curthread();
147 	if ((ret = _thr_ref_add(curthread, pid, /*include dead*/0)) != 0)
148 		return (ret);
149 	attr = pid->attr;
150 	_thr_ref_delete(curthread, pid);
151 	memcpy(*dst, &attr, sizeof(struct pthread_attr));
152 
153 	return (0);
154 }
155 
156 __weak_reference(_pthread_attr_getdetachstate, pthread_attr_getdetachstate);
157 
158 int
159 _pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
160 {
161 	int	ret;
162 
163 	/* Check for invalid arguments: */
164 	if (attr == NULL || *attr == NULL || detachstate == NULL)
165 		ret = EINVAL;
166 	else {
167 		/* Check if the detached flag is set: */
168 		if ((*attr)->flags & PTHREAD_DETACHED)
169 			/* Return detached: */
170 			*detachstate = PTHREAD_CREATE_DETACHED;
171 		else
172 			/* Return joinable: */
173 			*detachstate = PTHREAD_CREATE_JOINABLE;
174 		ret = 0;
175 	}
176 	return(ret);
177 }
178 
179 __weak_reference(_pthread_attr_getguardsize, pthread_attr_getguardsize);
180 
181 int
182 _pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize)
183 {
184 	int	ret;
185 
186 	/* Check for invalid arguments: */
187 	if (attr == NULL || *attr == NULL || guardsize == NULL)
188 		ret = EINVAL;
189 	else {
190 		/* Return the guard size: */
191 		*guardsize = (*attr)->guardsize_attr;
192 		ret = 0;
193 	}
194 	return(ret);
195 }
196 
197 __weak_reference(_pthread_attr_getinheritsched, pthread_attr_getinheritsched);
198 
199 int
200 _pthread_attr_getinheritsched(const pthread_attr_t *attr, int *sched_inherit)
201 {
202 	int ret = 0;
203 
204 	if ((attr == NULL) || (*attr == NULL))
205 		ret = EINVAL;
206 	else
207 		*sched_inherit = (*attr)->sched_inherit;
208 
209 	return(ret);
210 }
211 
212 __weak_reference(_pthread_attr_getschedparam, pthread_attr_getschedparam);
213 
214 int
215 _pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param)
216 {
217 	int ret = 0;
218 
219 	if ((attr == NULL) || (*attr == NULL) || (param == NULL))
220 		ret = EINVAL;
221 	else
222 		param->sched_priority = (*attr)->prio;
223 
224 	return(ret);
225 }
226 
227 __weak_reference(_pthread_attr_getschedpolicy, pthread_attr_getschedpolicy);
228 
229 int
230 _pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
231 {
232 	int ret = 0;
233 
234 	if ((attr == NULL) || (*attr == NULL) || (policy == NULL))
235 		ret = EINVAL;
236 	else
237 		*policy = (*attr)->sched_policy;
238 
239 	return(ret);
240 }
241 
242 __weak_reference(_pthread_attr_getscope, pthread_attr_getscope);
243 
244 int
245 _pthread_attr_getscope(const pthread_attr_t *attr, int *contentionscope)
246 {
247 	int ret = 0;
248 
249 	if ((attr == NULL) || (*attr == NULL) || (contentionscope == NULL))
250 		/* Return an invalid argument: */
251 		ret = EINVAL;
252 
253 	else
254 		*contentionscope = (*attr)->flags & PTHREAD_SCOPE_SYSTEM ?
255 		    PTHREAD_SCOPE_SYSTEM : PTHREAD_SCOPE_PROCESS;
256 
257 	return(ret);
258 }
259 
260 __weak_reference(_pthread_attr_getstack, pthread_attr_getstack);
261 
262 int
263 _pthread_attr_getstack(const pthread_attr_t * __restrict attr,
264                         void ** __restrict stackaddr,
265                         size_t * __restrict stacksize)
266 {
267 	int     ret;
268 
269 	/* Check for invalid arguments: */
270 	if (attr == NULL || *attr == NULL || stackaddr == NULL
271 	    || stacksize == NULL )
272 		ret = EINVAL;
273 	else {
274 		/* Return the stack address and size */
275 		*stackaddr = (*attr)->stackaddr_attr;
276 		*stacksize = (*attr)->stacksize_attr;
277 		ret = 0;
278 	}
279 	return(ret);
280 }
281 
282 __weak_reference(_pthread_attr_getstackaddr, pthread_attr_getstackaddr);
283 
284 int
285 _pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr)
286 {
287 	int	ret;
288 
289 	/* Check for invalid arguments: */
290 	if (attr == NULL || *attr == NULL || stackaddr == NULL)
291 		ret = EINVAL;
292 	else {
293 		/* Return the stack address: */
294 		*stackaddr = (*attr)->stackaddr_attr;
295 		ret = 0;
296 	}
297 	return(ret);
298 }
299 
300 __weak_reference(_pthread_attr_getstacksize, pthread_attr_getstacksize);
301 
302 int
303 _pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize)
304 {
305 	int	ret;
306 
307 	/* Check for invalid arguments: */
308 	if (attr == NULL || *attr == NULL || stacksize  == NULL)
309 		ret = EINVAL;
310 	else {
311 		/* Return the stack size: */
312 		*stacksize = (*attr)->stacksize_attr;
313 		ret = 0;
314 	}
315 	return(ret);
316 }
317 
318 __weak_reference(_pthread_attr_init, pthread_attr_init);
319 
320 int
321 _pthread_attr_init(pthread_attr_t *attr)
322 {
323 	int	ret;
324 	pthread_attr_t	pattr;
325 
326 	_thr_check_init();
327 
328 	/* Allocate memory for the attribute object: */
329 	if ((pattr = (pthread_attr_t) malloc(sizeof(struct pthread_attr))) == NULL)
330 		/* Insufficient memory: */
331 		ret = ENOMEM;
332 	else {
333 		/* Initialise the attribute object with the defaults: */
334 		memcpy(pattr, &_pthread_attr_default,
335 		    sizeof(struct pthread_attr));
336 
337 		/* Return a pointer to the attribute object: */
338 		*attr = pattr;
339 		ret = 0;
340 	}
341 	return(ret);
342 }
343 
344 __weak_reference(_pthread_attr_setcreatesuspend_np, pthread_attr_setcreatesuspend_np);
345 
346 int
347 _pthread_attr_setcreatesuspend_np(pthread_attr_t *attr)
348 {
349 	int	ret;
350 
351 	if (attr == NULL || *attr == NULL) {
352 		ret = EINVAL;
353 	} else {
354 		(*attr)->suspend = THR_CREATE_SUSPENDED;
355 		ret = 0;
356 	}
357 	return(ret);
358 }
359 
360 __weak_reference(_pthread_attr_setdetachstate, pthread_attr_setdetachstate);
361 
362 int
363 _pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
364 {
365 	int	ret;
366 
367 	/* Check for invalid arguments: */
368 	if (attr == NULL || *attr == NULL ||
369 	    (detachstate != PTHREAD_CREATE_DETACHED &&
370 	    detachstate != PTHREAD_CREATE_JOINABLE))
371 		ret = EINVAL;
372 	else {
373 		/* Check if detached state: */
374 		if (detachstate == PTHREAD_CREATE_DETACHED)
375 			/* Set the detached flag: */
376 			(*attr)->flags |= PTHREAD_DETACHED;
377 		else
378 			/* Reset the detached flag: */
379 			(*attr)->flags &= ~PTHREAD_DETACHED;
380 		ret = 0;
381 	}
382 	return(ret);
383 }
384 
385 __weak_reference(_pthread_attr_setguardsize, pthread_attr_setguardsize);
386 
387 int
388 _pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize)
389 {
390 	int	ret;
391 
392 	/* Check for invalid arguments. */
393 	if (attr == NULL || *attr == NULL)
394 		ret = EINVAL;
395 	else {
396 		/* Save the stack size. */
397 		(*attr)->guardsize_attr = guardsize;
398 		ret = 0;
399 	}
400 	return(ret);
401 }
402 
403 __weak_reference(_pthread_attr_setinheritsched, pthread_attr_setinheritsched);
404 
405 int
406 _pthread_attr_setinheritsched(pthread_attr_t *attr, int sched_inherit)
407 {
408 	int ret = 0;
409 
410 	if ((attr == NULL) || (*attr == NULL))
411 		ret = EINVAL;
412 	else if (sched_inherit != PTHREAD_INHERIT_SCHED &&
413 		 sched_inherit != PTHREAD_EXPLICIT_SCHED)
414 		ret = ENOTSUP;
415 	else
416 		(*attr)->sched_inherit = sched_inherit;
417 
418 	return(ret);
419 }
420 
421 __weak_reference(_pthread_attr_setschedparam, pthread_attr_setschedparam);
422 
423 int
424 _pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param)
425 {
426 	int ret = 0;
427 
428 	if ((attr == NULL) || (*attr == NULL))
429 		ret = EINVAL;
430 	else if (param == NULL) {
431 		ret = ENOTSUP;
432 	} else if ((param->sched_priority < THR_MIN_PRIORITY) ||
433 	    (param->sched_priority > THR_MAX_PRIORITY)) {
434 		/* Return an unsupported value error. */
435 		ret = ENOTSUP;
436 	} else
437 		(*attr)->prio = param->sched_priority;
438 
439 	return(ret);
440 }
441 
442 __weak_reference(_pthread_attr_setschedpolicy, pthread_attr_setschedpolicy);
443 
444 int
445 _pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
446 {
447 	int ret = 0;
448 
449 	if ((attr == NULL) || (*attr == NULL))
450 		ret = EINVAL;
451 	else if ((policy < SCHED_FIFO) || (policy > SCHED_RR)) {
452 		ret = ENOTSUP;
453 	} else
454 		(*attr)->sched_policy = policy;
455 
456 	return(ret);
457 }
458 
459 __weak_reference(_pthread_attr_setscope, pthread_attr_setscope);
460 
461 int
462 _pthread_attr_setscope(pthread_attr_t *attr, int contentionscope)
463 {
464 	int ret = 0;
465 
466 	if ((attr == NULL) || (*attr == NULL)) {
467 		/* Return an invalid argument: */
468 		ret = EINVAL;
469 	} else if ((contentionscope != PTHREAD_SCOPE_PROCESS) &&
470 	    (contentionscope != PTHREAD_SCOPE_SYSTEM)) {
471 		ret = EINVAL;
472 	} else if (contentionscope == PTHREAD_SCOPE_SYSTEM) {
473 		(*attr)->flags |= contentionscope;
474 	} else {
475 		(*attr)->flags &= ~PTHREAD_SCOPE_SYSTEM;
476 	}
477 	return (ret);
478 }
479 
480 __weak_reference(_pthread_attr_setstack, pthread_attr_setstack);
481 
482 int
483 _pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr,
484                         size_t stacksize)
485 {
486 	int     ret;
487 
488 	/* Check for invalid arguments: */
489 	if (attr == NULL || *attr == NULL || stackaddr == NULL
490 	    || stacksize < PTHREAD_STACK_MIN)
491 		ret = EINVAL;
492 	else {
493 		/* Save the stack address and stack size */
494 		(*attr)->stackaddr_attr = stackaddr;
495 		(*attr)->stacksize_attr = stacksize;
496 		ret = 0;
497 	}
498 	return(ret);
499 }
500 
501 __weak_reference(_pthread_attr_setstackaddr, pthread_attr_setstackaddr);
502 
503 int
504 _pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr)
505 {
506 	int	ret;
507 
508 	/* Check for invalid arguments: */
509 	if (attr == NULL || *attr == NULL || stackaddr == NULL)
510 		ret = EINVAL;
511 	else {
512 		/* Save the stack address: */
513 		(*attr)->stackaddr_attr = stackaddr;
514 		ret = 0;
515 	}
516 	return(ret);
517 }
518 
519 __weak_reference(_pthread_attr_setstacksize, pthread_attr_setstacksize);
520 
521 int
522 _pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
523 {
524 	int	ret;
525 
526 	/* Check for invalid arguments: */
527 	if (attr == NULL || *attr == NULL || stacksize < PTHREAD_STACK_MIN)
528 		ret = EINVAL;
529 	else {
530 		/* Save the stack size: */
531 		(*attr)->stacksize_attr = stacksize;
532 		ret = 0;
533 	}
534 	return(ret);
535 }
536