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