xref: /netbsd-src/lib/libpthread/pthread_attr.c (revision ed75d7a867996c84cfa88e3b8906816277e957f7)
1 /*	$NetBSD: pthread_attr.c,v 1.19 2020/01/29 13:47:31 kamil Exp $	*/
2 
3 /*-
4  * Copyright (c) 2001, 2002, 2003, 2008 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Nathan J. Williams.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 __RCSID("$NetBSD: pthread_attr.c,v 1.19 2020/01/29 13:47:31 kamil Exp $");
34 
35 #include <errno.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40 
41 #ifndef __lint__
42 #define pthread_attr_get_np _pthread_attr_get_np
43 #endif
44 
45 #include "pthread.h"
46 #include "pthread_int.h"
47 
48 __weak_alias(pthread_attr_get_np, _pthread_attr_get_np)
49 
50 static struct pthread_attr_private *pthread__attr_init_private(
51     pthread_attr_t *);
52 
53 static struct pthread_attr_private *
54 pthread__attr_init_private(pthread_attr_t *attr)
55 {
56 	struct pthread_attr_private *p;
57 
58 	if ((p = attr->pta_private) != NULL)
59 		return p;
60 
61 	p = calloc(1, sizeof(*p));
62 	if (p != NULL) {
63 		attr->pta_private = p;
64 		p->ptap_policy = SCHED_OTHER;
65 		p->ptap_stacksize = pthread__stacksize;
66 		p->ptap_guardsize = pthread__guardsize;
67 	}
68 	return p;
69 }
70 
71 
72 int
73 pthread_attr_init(pthread_attr_t *attr)
74 {
75 
76 	attr->pta_magic = PT_ATTR_MAGIC;
77 	attr->pta_flags = 0;
78 	attr->pta_private = NULL;
79 
80 	return 0;
81 }
82 
83 
84 int
85 pthread_attr_destroy(pthread_attr_t *attr)
86 {
87 	struct pthread_attr_private *p;
88 
89 	pthread__error(EINVAL, "Invalid attribute",
90 	    attr->pta_magic == PT_ATTR_MAGIC);
91 
92 	if ((p = attr->pta_private) != NULL)
93 		free(p);
94 
95 	attr->pta_magic = PT_ATTR_DEAD;
96 
97 	return 0;
98 }
99 
100 
101 int
102 pthread_attr_get_np(pthread_t thread, pthread_attr_t *attr)
103 {
104 	struct pthread_attr_private *p;
105 
106 	pthread__error(EINVAL, "Invalid attribute",
107 	    attr->pta_magic == PT_ATTR_MAGIC);
108 
109 	p = pthread__attr_init_private(attr);
110 	if (p == NULL)
111 		return ENOMEM;
112 
113 	attr->pta_flags = thread->pt_flags &
114 	    (PT_FLAG_DETACHED | PT_FLAG_SCOPE_SYSTEM | PT_FLAG_EXPLICIT_SCHED);
115 
116 	p->ptap_namearg = thread->pt_name;
117 	p->ptap_stackaddr = thread->pt_stack.ss_sp;
118 	p->ptap_stacksize = thread->pt_stack.ss_size;
119 	p->ptap_guardsize = thread->pt_guardsize;
120 	return pthread_getschedparam(thread, &p->ptap_policy, &p->ptap_sp);
121 }
122 
123 
124 int
125 pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
126 {
127 
128 	pthread__error(EINVAL, "Invalid attribute",
129 	    attr->pta_magic == PT_ATTR_MAGIC);
130 
131 	if (attr->pta_flags & PT_FLAG_DETACHED)
132 		*detachstate = PTHREAD_CREATE_DETACHED;
133 	else
134 		*detachstate = PTHREAD_CREATE_JOINABLE;
135 
136 	return 0;
137 }
138 
139 
140 int
141 pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
142 {
143 
144 	pthread__error(EINVAL, "Invalid attribute",
145 	    attr->pta_magic == PT_ATTR_MAGIC);
146 
147 	switch (detachstate) {
148 	case PTHREAD_CREATE_JOINABLE:
149 		attr->pta_flags &= ~PT_FLAG_DETACHED;
150 		break;
151 	case PTHREAD_CREATE_DETACHED:
152 		attr->pta_flags |= PT_FLAG_DETACHED;
153 		break;
154 	default:
155 		return EINVAL;
156 	}
157 
158 	return 0;
159 }
160 
161 
162 int
163 pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guard)
164 {
165 	struct pthread_attr_private *p;
166 
167 	pthread__error(EINVAL, "Invalid attribute",
168 	    attr->pta_magic == PT_ATTR_MAGIC);
169 
170 	if ((p = attr->pta_private) == NULL)
171 		*guard = pthread__guardsize;
172 	else
173 		*guard = p->ptap_guardsize;
174 
175 	return 0;
176 }
177 
178 
179 int
180 pthread_attr_setguardsize(pthread_attr_t *attr, size_t guard)
181 {
182 	struct pthread_attr_private *p;
183 
184 	pthread__error(EINVAL, "Invalid attribute",
185 	    attr->pta_magic == PT_ATTR_MAGIC);
186 
187 	p = pthread__attr_init_private(attr);
188 	if (p == NULL)
189 		return ENOMEM;
190 
191 	p->ptap_guardsize = guard;
192 
193 	return 0;
194 }
195 
196 
197 int
198 pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inherit)
199 {
200 
201 	pthread__error(EINVAL, "Invalid attribute",
202 	    attr->pta_magic == PT_ATTR_MAGIC);
203 
204 	if (attr->pta_flags & PT_FLAG_EXPLICIT_SCHED)
205 		*inherit = PTHREAD_EXPLICIT_SCHED;
206 	else
207 		*inherit = PTHREAD_INHERIT_SCHED;
208 
209 	return 0;
210 }
211 
212 
213 int
214 pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit)
215 {
216 
217 	pthread__error(EINVAL, "Invalid attribute",
218 	    attr->pta_magic == PT_ATTR_MAGIC);
219 
220 	switch (inherit) {
221 	case PTHREAD_INHERIT_SCHED:
222 		attr->pta_flags &= ~PT_FLAG_EXPLICIT_SCHED;
223 		break;
224 	case PTHREAD_EXPLICIT_SCHED:
225 		attr->pta_flags |= PT_FLAG_EXPLICIT_SCHED;
226 		break;
227 	default:
228 		return EINVAL;
229 	}
230 
231 	return 0;
232 }
233 
234 
235 int
236 pthread_attr_getscope(const pthread_attr_t *attr, int *scope)
237 {
238 
239 	pthread__error(EINVAL, "Invalid attribute",
240 	    attr->pta_magic == PT_ATTR_MAGIC);
241 
242 	if (attr->pta_flags & PT_FLAG_SCOPE_SYSTEM)
243 		*scope = PTHREAD_SCOPE_SYSTEM;
244 	else
245 		*scope = PTHREAD_SCOPE_PROCESS;
246 
247 	return 0;
248 }
249 
250 
251 int
252 pthread_attr_setscope(pthread_attr_t *attr, int scope)
253 {
254 
255 	pthread__error(EINVAL, "Invalid attribute",
256 	    attr->pta_magic == PT_ATTR_MAGIC);
257 
258 	switch (scope) {
259 	case PTHREAD_SCOPE_PROCESS:
260 		attr->pta_flags &= ~PT_FLAG_SCOPE_SYSTEM;
261 		break;
262 	case PTHREAD_SCOPE_SYSTEM:
263 		attr->pta_flags |= PT_FLAG_SCOPE_SYSTEM;
264 		break;
265 	default:
266 		return EINVAL;
267 	}
268 
269 	return 0;
270 }
271 
272 
273 int
274 pthread_attr_setschedparam(pthread_attr_t *attr,
275 			   const struct sched_param *param)
276 {
277 	struct pthread_attr_private *p;
278 	int error;
279 
280 	pthread__error(EINVAL, "Invalid attribute",
281 	    attr->pta_magic == PT_ATTR_MAGIC);
282 
283 	if (param == NULL)
284 		return EINVAL;
285 	p = pthread__attr_init_private(attr);
286 	if (p == NULL)
287 		return ENOMEM;
288 	error = pthread__checkpri(param->sched_priority);
289 	if (error == 0)
290 		p->ptap_sp = *param;
291 	return error;
292 }
293 
294 
295 int
296 pthread_attr_getschedparam(const pthread_attr_t *attr,
297 			   struct sched_param *param)
298 {
299 	struct pthread_attr_private *p;
300 
301 	pthread__error(EINVAL, "Invalid attribute",
302 	    attr->pta_magic == PT_ATTR_MAGIC);
303 
304 	if (param == NULL)
305 		return EINVAL;
306 	p = attr->pta_private;
307 	if (p == NULL)
308 		memset(param, 0, sizeof(*param));
309 	else
310 		*param = p->ptap_sp;
311 	return 0;
312 }
313 
314 
315 int
316 pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
317 {
318 	struct pthread_attr_private *p;
319 
320 	pthread__error(EINVAL, "Invalid attribute",
321 	    attr->pta_magic == PT_ATTR_MAGIC);
322 
323 	switch (policy) {
324 	case SCHED_OTHER:
325 	case SCHED_FIFO:
326 	case SCHED_RR:
327 		p = pthread__attr_init_private(attr);
328 		if (p == NULL)
329 			return ENOMEM;
330 		p->ptap_policy = policy;
331 		return 0;
332 	default:
333 		return ENOTSUP;
334 	}
335 }
336 
337 
338 int
339 pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
340 {
341 	struct pthread_attr_private *p;
342 
343 	pthread__error(EINVAL, "Invalid attribute",
344 	    attr->pta_magic == PT_ATTR_MAGIC);
345 
346 	p = attr->pta_private;
347 	if (p == NULL) {
348 		*policy = SCHED_OTHER;
349 		return 0;
350 	}
351 	*policy = p->ptap_policy;
352 	return 0;
353 }
354 
355 
356 int
357 pthread_attr_getstack(const pthread_attr_t *attr, void **addr, size_t *size)
358 {
359 	struct pthread_attr_private *p;
360 
361 	pthread__error(EINVAL, "Invalid attribute",
362 	    attr->pta_magic == PT_ATTR_MAGIC);
363 
364 	if ((p = attr->pta_private) == NULL) {
365 		*addr = NULL;
366 		*size = pthread__stacksize;
367 	} else {
368 		*addr = p->ptap_stackaddr;
369 		*size = p->ptap_stacksize;
370 	}
371 
372 	return 0;
373 }
374 
375 
376 int
377 pthread_attr_setstack(pthread_attr_t *attr, void *addr, size_t size)
378 {
379 	struct pthread_attr_private *p;
380 
381 	pthread__error(EINVAL, "Invalid attribute",
382 	    attr->pta_magic == PT_ATTR_MAGIC);
383 
384 	p = pthread__attr_init_private(attr);
385 	if (p == NULL)
386 		return ENOMEM;
387 
388 	p->ptap_stackaddr = addr;
389 	p->ptap_stacksize = size;
390 
391 	return 0;
392 }
393 
394 
395 int
396 pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *size)
397 {
398 	struct pthread_attr_private *p;
399 
400 	pthread__error(EINVAL, "Invalid attribute",
401 	    attr->pta_magic == PT_ATTR_MAGIC);
402 
403 	if ((p = attr->pta_private) == NULL)
404 		*size = pthread__stacksize;
405 	else
406 		*size = p->ptap_stacksize;
407 
408 	return 0;
409 }
410 
411 
412 int
413 pthread_attr_setstacksize(pthread_attr_t *attr, size_t size)
414 {
415 	struct pthread_attr_private *p;
416 
417 	pthread__error(EINVAL, "Invalid attribute",
418 	    attr->pta_magic == PT_ATTR_MAGIC);
419 
420 	if (size < (size_t)sysconf(_SC_THREAD_STACK_MIN))
421 		return EINVAL;
422 
423 	p = pthread__attr_init_private(attr);
424 	if (p == NULL)
425 		return ENOMEM;
426 
427 	p->ptap_stacksize = size;
428 
429 	return 0;
430 }
431 
432 
433 int
434 pthread_attr_getstackaddr(const pthread_attr_t *attr, void **addr)
435 {
436 	struct pthread_attr_private *p;
437 
438 	pthread__error(EINVAL, "Invalid attribute",
439 	    attr->pta_magic == PT_ATTR_MAGIC);
440 
441 	if ((p = attr->pta_private) == NULL)
442 		*addr = NULL;
443 	else
444 		*addr = p->ptap_stackaddr;
445 
446 	return 0;
447 }
448 
449 
450 int
451 pthread_attr_setstackaddr(pthread_attr_t *attr, void *addr)
452 {
453 	struct pthread_attr_private *p;
454 
455 	pthread__error(EINVAL, "Invalid attribute",
456 	    attr->pta_magic == PT_ATTR_MAGIC);
457 
458 	p = pthread__attr_init_private(attr);
459 	if (p == NULL)
460 		return ENOMEM;
461 
462 	p->ptap_stackaddr = addr;
463 
464 	return 0;
465 }
466 
467 
468 int
469 pthread_attr_getname_np(const pthread_attr_t *attr, char *name, size_t len,
470     void **argp)
471 {
472 	struct pthread_attr_private *p;
473 
474 	pthread__error(EINVAL, "Invalid attribute",
475 	    attr->pta_magic == PT_ATTR_MAGIC);
476 
477 	if ((p = attr->pta_private) == NULL) {
478 		name[0] = '\0';
479 		if (argp != NULL)
480 			*argp = NULL;
481 	} else {
482 		strlcpy(name, p->ptap_name, len);
483 		if (argp != NULL)
484 			*argp = p->ptap_namearg;
485 	}
486 
487 	return 0;
488 }
489 
490 
491 int
492 pthread_attr_setname_np(pthread_attr_t *attr, const char *name, void *arg)
493 {
494 	struct pthread_attr_private *p;
495 	int namelen;
496 
497 	pthread__error(EINVAL, "Invalid attribute",
498 	    attr->pta_magic == PT_ATTR_MAGIC);
499 
500 	p = pthread__attr_init_private(attr);
501 	if (p == NULL)
502 		return ENOMEM;
503 
504 	namelen = snprintf(p->ptap_name, PTHREAD_MAX_NAMELEN_NP, name, arg);
505 	if (namelen >= PTHREAD_MAX_NAMELEN_NP) {
506 		p->ptap_name[0] = '\0';
507 		return EINVAL;
508 	}
509 	p->ptap_namearg = arg;
510 
511 	return 0;
512 }
513 
514 int
515 pthread_attr_setcreatesuspend_np(pthread_attr_t *attr)
516 {
517 
518 	pthread__error(EINVAL, "Invalid attribute",
519 	    attr->pta_magic == PT_ATTR_MAGIC);
520 
521 	attr->pta_flags |= PT_FLAG_SUSPENDED;
522 	return 0;
523 }
524 
525 int
526 pthread_getattr_np(pthread_t thread, pthread_attr_t *attr)
527 {
528 	int error;
529 
530 	if ((error = pthread_attr_init(attr)) != 0)
531 		return error;
532 	if ((error = pthread_attr_get_np(thread, attr)) != 0) {
533 		(void)pthread_attr_destroy(attr);
534 		return error;
535 	}
536 	return 0;
537 }
538