xref: /freebsd/lib/libthr/thread/thr_attr.c (revision c96ae1968a6ab7056427a739bce81bf07447c2d4)
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. Neither the name of the author nor the names of any co-contributors
78  *    may be used to endorse or promote products derived from this software
79  *    without specific prior written permission.
80  *
81  * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
82  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
83  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
84  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
85  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
86  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
87  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
88  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
89  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
90  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
91  * SUCH DAMAGE.
92  *
93  * $FreeBSD$
94  */
95 
96 #include "namespace.h"
97 #include <errno.h>
98 #include <pthread.h>
99 #include <stdlib.h>
100 #include <string.h>
101 #include <pthread_np.h>
102 #include "un-namespace.h"
103 
104 #include "thr_private.h"
105 
106 __weak_reference(_pthread_attr_destroy, pthread_attr_destroy);
107 
108 int
109 _pthread_attr_destroy(pthread_attr_t *attr)
110 {
111 	int	ret;
112 
113 	/* Check for invalid arguments: */
114 	if (attr == NULL || *attr == NULL)
115 		/* Invalid argument: */
116 		ret = EINVAL;
117 	else {
118 		/* Free the memory allocated to the attribute object: */
119 		free(*attr);
120 
121 		/*
122 		 * Leave the attribute pointer NULL now that the memory
123 		 * has been freed:
124 		 */
125 		*attr = NULL;
126 		ret = 0;
127 	}
128 	return(ret);
129 }
130 
131 __weak_reference(_pthread_attr_get_np, pthread_attr_get_np);
132 
133 int
134 _pthread_attr_get_np(pthread_t pid, pthread_attr_t *dst)
135 {
136 	struct pthread *curthread;
137 	struct pthread_attr attr;
138 	int	ret;
139 
140 	if (pid == NULL || dst == NULL || *dst == NULL)
141 		return (EINVAL);
142 
143 	curthread = _get_curthread();
144 	if ((ret = _thr_ref_add(curthread, pid, /*include dead*/0)) != 0)
145 		return (ret);
146 	attr = pid->attr;
147 	if (pid->tlflags & TLFLAGS_DETACHED)
148 		attr.flags |= PTHREAD_DETACHED;
149 	_thr_ref_delete(curthread, pid);
150 	memcpy(*dst, &attr, sizeof(struct pthread_attr));
151 
152 	return (0);
153 }
154 
155 __weak_reference(_pthread_attr_getdetachstate, pthread_attr_getdetachstate);
156 
157 int
158 _pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
159 {
160 	int	ret;
161 
162 	/* Check for invalid arguments: */
163 	if (attr == NULL || *attr == NULL || detachstate == NULL)
164 		ret = EINVAL;
165 	else {
166 		/* Check if the detached flag is set: */
167 		if ((*attr)->flags & PTHREAD_DETACHED)
168 			/* Return detached: */
169 			*detachstate = PTHREAD_CREATE_DETACHED;
170 		else
171 			/* Return joinable: */
172 			*detachstate = PTHREAD_CREATE_JOINABLE;
173 		ret = 0;
174 	}
175 	return(ret);
176 }
177 
178 __weak_reference(_pthread_attr_getguardsize, pthread_attr_getguardsize);
179 
180 int
181 _pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize)
182 {
183 	int	ret;
184 
185 	/* Check for invalid arguments: */
186 	if (attr == NULL || *attr == NULL || guardsize == NULL)
187 		ret = EINVAL;
188 	else {
189 		/* Return the guard size: */
190 		*guardsize = (*attr)->guardsize_attr;
191 		ret = 0;
192 	}
193 	return(ret);
194 }
195 
196 __weak_reference(_pthread_attr_getinheritsched, pthread_attr_getinheritsched);
197 
198 int
199 _pthread_attr_getinheritsched(const pthread_attr_t *attr, int *sched_inherit)
200 {
201 	int ret = 0;
202 
203 	if ((attr == NULL) || (*attr == NULL))
204 		ret = EINVAL;
205 	else
206 		*sched_inherit = (*attr)->sched_inherit;
207 
208 	return(ret);
209 }
210 
211 __weak_reference(_pthread_attr_getschedparam, pthread_attr_getschedparam);
212 
213 int
214 _pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param)
215 {
216 	int ret = 0;
217 
218 	if ((attr == NULL) || (*attr == NULL) || (param == NULL))
219 		ret = EINVAL;
220 	else
221 		param->sched_priority = (*attr)->prio;
222 
223 	return(ret);
224 }
225 
226 __weak_reference(_pthread_attr_getschedpolicy, pthread_attr_getschedpolicy);
227 
228 int
229 _pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
230 {
231 	int ret = 0;
232 
233 	if ((attr == NULL) || (*attr == NULL) || (policy == NULL))
234 		ret = EINVAL;
235 	else
236 		*policy = (*attr)->sched_policy;
237 
238 	return(ret);
239 }
240 
241 __weak_reference(_pthread_attr_getscope, pthread_attr_getscope);
242 
243 int
244 _pthread_attr_getscope(const pthread_attr_t *attr, int *contentionscope)
245 {
246 	int ret = 0;
247 
248 	if ((attr == NULL) || (*attr == NULL) || (contentionscope == NULL))
249 		/* Return an invalid argument: */
250 		ret = EINVAL;
251 
252 	else
253 		*contentionscope = (*attr)->flags & PTHREAD_SCOPE_SYSTEM ?
254 		    PTHREAD_SCOPE_SYSTEM : PTHREAD_SCOPE_PROCESS;
255 
256 	return(ret);
257 }
258 
259 __weak_reference(_pthread_attr_getstack, pthread_attr_getstack);
260 
261 int
262 _pthread_attr_getstack(const pthread_attr_t * __restrict attr,
263                         void ** __restrict stackaddr,
264                         size_t * __restrict stacksize)
265 {
266 	int     ret;
267 
268 	/* Check for invalid arguments: */
269 	if (attr == NULL || *attr == NULL || stackaddr == NULL
270 	    || stacksize == NULL )
271 		ret = EINVAL;
272 	else {
273 		/* Return the stack address and size */
274 		*stackaddr = (*attr)->stackaddr_attr;
275 		*stacksize = (*attr)->stacksize_attr;
276 		ret = 0;
277 	}
278 	return(ret);
279 }
280 
281 __weak_reference(_pthread_attr_getstackaddr, pthread_attr_getstackaddr);
282 
283 int
284 _pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr)
285 {
286 	int	ret;
287 
288 	/* Check for invalid arguments: */
289 	if (attr == NULL || *attr == NULL || stackaddr == NULL)
290 		ret = EINVAL;
291 	else {
292 		/* Return the stack address: */
293 		*stackaddr = (*attr)->stackaddr_attr;
294 		ret = 0;
295 	}
296 	return(ret);
297 }
298 
299 __weak_reference(_pthread_attr_getstacksize, pthread_attr_getstacksize);
300 
301 int
302 _pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize)
303 {
304 	int	ret;
305 
306 	/* Check for invalid arguments: */
307 	if (attr == NULL || *attr == NULL || stacksize  == NULL)
308 		ret = EINVAL;
309 	else {
310 		/* Return the stack size: */
311 		*stacksize = (*attr)->stacksize_attr;
312 		ret = 0;
313 	}
314 	return(ret);
315 }
316 
317 __weak_reference(_pthread_attr_init, pthread_attr_init);
318 
319 int
320 _pthread_attr_init(pthread_attr_t *attr)
321 {
322 	int	ret;
323 	pthread_attr_t	pattr;
324 
325 	_thr_check_init();
326 
327 	/* Allocate memory for the attribute object: */
328 	if ((pattr = (pthread_attr_t) malloc(sizeof(struct pthread_attr))) == NULL)
329 		/* Insufficient memory: */
330 		ret = ENOMEM;
331 	else {
332 		/* Initialise the attribute object with the defaults: */
333 		memcpy(pattr, &_pthread_attr_default, sizeof(struct pthread_attr));
334 
335 		/* Return a pointer to the attribute object: */
336 		*attr = pattr;
337 		ret = 0;
338 	}
339 	return(ret);
340 }
341 
342 __weak_reference(_pthread_attr_setcreatesuspend_np, pthread_attr_setcreatesuspend_np);
343 
344 int
345 _pthread_attr_setcreatesuspend_np(pthread_attr_t *attr)
346 {
347 	int	ret;
348 
349 	if (attr == NULL || *attr == NULL) {
350 		ret = EINVAL;
351 	} else {
352 		(*attr)->suspend = THR_CREATE_SUSPENDED;
353 		ret = 0;
354 	}
355 	return(ret);
356 }
357 
358 __weak_reference(_pthread_attr_setdetachstate, pthread_attr_setdetachstate);
359 
360 int
361 _pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
362 {
363 	int	ret;
364 
365 	/* Check for invalid arguments: */
366 	if (attr == NULL || *attr == NULL ||
367 	    (detachstate != PTHREAD_CREATE_DETACHED &&
368 	    detachstate != PTHREAD_CREATE_JOINABLE))
369 		ret = EINVAL;
370 	else {
371 		/* Check if detached state: */
372 		if (detachstate == PTHREAD_CREATE_DETACHED)
373 			/* Set the detached flag: */
374 			(*attr)->flags |= PTHREAD_DETACHED;
375 		else
376 			/* Reset the detached flag: */
377 			(*attr)->flags &= ~PTHREAD_DETACHED;
378 		ret = 0;
379 	}
380 	return(ret);
381 }
382 
383 __weak_reference(_pthread_attr_setguardsize, pthread_attr_setguardsize);
384 
385 int
386 _pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize)
387 {
388 	int	ret;
389 
390 	/* Check for invalid arguments. */
391 	if (attr == NULL || *attr == NULL)
392 		ret = EINVAL;
393 	else {
394 		/* Save the stack size. */
395 		(*attr)->guardsize_attr = guardsize;
396 		ret = 0;
397 	}
398 	return(ret);
399 }
400 
401 __weak_reference(_pthread_attr_setinheritsched, pthread_attr_setinheritsched);
402 
403 int
404 _pthread_attr_setinheritsched(pthread_attr_t *attr, int sched_inherit)
405 {
406 	int ret = 0;
407 
408 	if ((attr == NULL) || (*attr == NULL))
409 		ret = EINVAL;
410 	else if (sched_inherit != PTHREAD_INHERIT_SCHED &&
411 		 sched_inherit != PTHREAD_EXPLICIT_SCHED)
412 		ret = ENOTSUP;
413 	else
414 		(*attr)->sched_inherit = sched_inherit;
415 
416 	return(ret);
417 }
418 
419 __weak_reference(_pthread_attr_setschedparam, pthread_attr_setschedparam);
420 
421 int
422 _pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param)
423 {
424 	int policy;
425 
426 	if ((attr == NULL) || (*attr == NULL))
427 		return (EINVAL);
428 
429 	if (param == NULL)
430 		return (ENOTSUP);
431 
432 	policy = (*attr)->sched_policy;
433 
434 	if (policy == SCHED_FIFO || policy == SCHED_RR) {
435 		if (param->sched_priority < _thr_priorities[policy-1].pri_min ||
436 		    param->sched_priority > _thr_priorities[policy-1].pri_max)
437 		return (ENOTSUP);
438 	} else {
439 		/*
440 		 * Ignore it for SCHED_OTHER now, patches for glib ports
441 		 * are wrongly using M:N thread library's internal macro
442 		 * THR_MIN_PRIORITY and THR_MAX_PRIORITY.
443 		 */
444 	}
445 
446 	(*attr)->prio = param->sched_priority;
447 
448 	return (0);
449 }
450 
451 __weak_reference(_pthread_attr_setschedpolicy, pthread_attr_setschedpolicy);
452 
453 int
454 _pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
455 {
456 	int ret = 0;
457 
458 	if ((attr == NULL) || (*attr == NULL))
459 		ret = EINVAL;
460 	else if ((policy < SCHED_FIFO) || (policy > SCHED_RR)) {
461 		ret = ENOTSUP;
462 	} else {
463 		(*attr)->sched_policy = policy;
464 		(*attr)->prio = _thr_priorities[policy-1].pri_default;
465 	}
466 	return(ret);
467 }
468 
469 __weak_reference(_pthread_attr_setscope, pthread_attr_setscope);
470 
471 int
472 _pthread_attr_setscope(pthread_attr_t *attr, int contentionscope)
473 {
474 	int ret = 0;
475 
476 	if ((attr == NULL) || (*attr == NULL)) {
477 		/* Return an invalid argument: */
478 		ret = EINVAL;
479 	} else if ((contentionscope != PTHREAD_SCOPE_PROCESS) &&
480 	    (contentionscope != PTHREAD_SCOPE_SYSTEM)) {
481 		ret = EINVAL;
482 	} else if (contentionscope == PTHREAD_SCOPE_SYSTEM) {
483 		(*attr)->flags |= contentionscope;
484 	} else {
485 		(*attr)->flags &= ~PTHREAD_SCOPE_SYSTEM;
486 	}
487 	return (ret);
488 }
489 
490 __weak_reference(_pthread_attr_setstack, pthread_attr_setstack);
491 
492 int
493 _pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr,
494                         size_t stacksize)
495 {
496 	int     ret;
497 
498 	/* Check for invalid arguments: */
499 	if (attr == NULL || *attr == NULL || stackaddr == NULL
500 	    || stacksize < PTHREAD_STACK_MIN)
501 		ret = EINVAL;
502 	else {
503 		/* Save the stack address and stack size */
504 		(*attr)->stackaddr_attr = stackaddr;
505 		(*attr)->stacksize_attr = stacksize;
506 		ret = 0;
507 	}
508 	return(ret);
509 }
510 
511 __weak_reference(_pthread_attr_setstackaddr, pthread_attr_setstackaddr);
512 
513 int
514 _pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr)
515 {
516 	int	ret;
517 
518 	/* Check for invalid arguments: */
519 	if (attr == NULL || *attr == NULL || stackaddr == NULL)
520 		ret = EINVAL;
521 	else {
522 		/* Save the stack address: */
523 		(*attr)->stackaddr_attr = stackaddr;
524 		ret = 0;
525 	}
526 	return(ret);
527 }
528 
529 __weak_reference(_pthread_attr_setstacksize, pthread_attr_setstacksize);
530 
531 int
532 _pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
533 {
534 	int	ret;
535 
536 	/* Check for invalid arguments: */
537 	if (attr == NULL || *attr == NULL || stacksize < PTHREAD_STACK_MIN)
538 		ret = EINVAL;
539 	else {
540 		/* Save the stack size: */
541 		(*attr)->stacksize_attr = stacksize;
542 		ret = 0;
543 	}
544 	return(ret);
545 }
546