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