1/*	$NetBSD: pthread_attr.c,v 1.21 2022/04/10 10:38:33 riastradh 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.21 2022/04/10 10:38:33 riastradh Exp $");
34
35/* Need to use libc-private names for atomic operations. */
36#include "../../common/lib/libc/atomic/atomic_op_namespace.h"
37
38#include <errno.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42#include <unistd.h>
43
44#ifndef __lint__
45#define pthread_attr_get_np _pthread_attr_get_np
46#endif
47
48#include "pthread.h"
49#include "pthread_int.h"
50
51__weak_alias(pthread_attr_get_np, _pthread_attr_get_np)
52
53static struct pthread_attr_private *pthread__attr_init_private(
54    pthread_attr_t *);
55
56static struct pthread_attr_private *
57pthread__attr_init_private(pthread_attr_t *attr)
58{
59	struct pthread_attr_private *p;
60
61	if ((p = attr->pta_private) != NULL)
62		return p;
63
64	p = calloc(1, sizeof(*p));
65	if (p != NULL) {
66		attr->pta_private = p;
67		p->ptap_policy = SCHED_OTHER;
68		p->ptap_stacksize = pthread__stacksize;
69		p->ptap_guardsize = pthread__guardsize;
70	}
71	return p;
72}
73
74
75int
76pthread_attr_init(pthread_attr_t *attr)
77{
78
79	attr->pta_magic = PT_ATTR_MAGIC;
80	attr->pta_flags = 0;
81	attr->pta_private = NULL;
82
83	return 0;
84}
85
86
87int
88pthread_attr_destroy(pthread_attr_t *attr)
89{
90	struct pthread_attr_private *p;
91
92	pthread__error(EINVAL, "Invalid attribute",
93	    attr->pta_magic == PT_ATTR_MAGIC);
94
95	if ((p = attr->pta_private) != NULL)
96		free(p);
97
98	attr->pta_magic = PT_ATTR_DEAD;
99
100	return 0;
101}
102
103
104int
105pthread_attr_get_np(pthread_t thread, pthread_attr_t *attr)
106{
107	struct pthread_attr_private *p;
108
109	pthread__error(EINVAL, "Invalid attribute",
110	    attr->pta_magic == PT_ATTR_MAGIC);
111
112	p = pthread__attr_init_private(attr);
113	if (p == NULL)
114		return ENOMEM;
115
116	attr->pta_flags = thread->pt_flags &
117	    (PT_FLAG_DETACHED | PT_FLAG_SCOPE_SYSTEM | PT_FLAG_EXPLICIT_SCHED);
118
119	p->ptap_namearg = thread->pt_name;
120	p->ptap_stackaddr = thread->pt_stack.ss_sp;
121	p->ptap_stacksize = thread->pt_stack.ss_size;
122	p->ptap_guardsize = thread->pt_guardsize;
123	return pthread_getschedparam(thread, &p->ptap_policy, &p->ptap_sp);
124}
125
126
127int
128pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
129{
130
131	pthread__error(EINVAL, "Invalid attribute",
132	    attr->pta_magic == PT_ATTR_MAGIC);
133
134	if (attr->pta_flags & PT_FLAG_DETACHED)
135		*detachstate = PTHREAD_CREATE_DETACHED;
136	else
137		*detachstate = PTHREAD_CREATE_JOINABLE;
138
139	return 0;
140}
141
142
143int
144pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
145{
146
147	pthread__error(EINVAL, "Invalid attribute",
148	    attr->pta_magic == PT_ATTR_MAGIC);
149
150	switch (detachstate) {
151	case PTHREAD_CREATE_JOINABLE:
152		attr->pta_flags &= ~PT_FLAG_DETACHED;
153		break;
154	case PTHREAD_CREATE_DETACHED:
155		attr->pta_flags |= PT_FLAG_DETACHED;
156		break;
157	default:
158		return EINVAL;
159	}
160
161	return 0;
162}
163
164
165int
166pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guard)
167{
168	struct pthread_attr_private *p;
169
170	pthread__error(EINVAL, "Invalid attribute",
171	    attr->pta_magic == PT_ATTR_MAGIC);
172
173	if ((p = attr->pta_private) == NULL)
174		*guard = pthread__guardsize;
175	else
176		*guard = p->ptap_guardsize;
177
178	return 0;
179}
180
181
182int
183pthread_attr_setguardsize(pthread_attr_t *attr, size_t guard)
184{
185	struct pthread_attr_private *p;
186
187	pthread__error(EINVAL, "Invalid attribute",
188	    attr->pta_magic == PT_ATTR_MAGIC);
189
190	p = pthread__attr_init_private(attr);
191	if (p == NULL)
192		return ENOMEM;
193
194	p->ptap_guardsize = guard;
195
196	return 0;
197}
198
199
200int
201pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inherit)
202{
203
204	pthread__error(EINVAL, "Invalid attribute",
205	    attr->pta_magic == PT_ATTR_MAGIC);
206
207	if (attr->pta_flags & PT_FLAG_EXPLICIT_SCHED)
208		*inherit = PTHREAD_EXPLICIT_SCHED;
209	else
210		*inherit = PTHREAD_INHERIT_SCHED;
211
212	return 0;
213}
214
215
216int
217pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit)
218{
219
220	pthread__error(EINVAL, "Invalid attribute",
221	    attr->pta_magic == PT_ATTR_MAGIC);
222
223	switch (inherit) {
224	case PTHREAD_INHERIT_SCHED:
225		attr->pta_flags &= ~PT_FLAG_EXPLICIT_SCHED;
226		break;
227	case PTHREAD_EXPLICIT_SCHED:
228		attr->pta_flags |= PT_FLAG_EXPLICIT_SCHED;
229		break;
230	default:
231		return EINVAL;
232	}
233
234	return 0;
235}
236
237
238int
239pthread_attr_getscope(const pthread_attr_t *attr, int *scope)
240{
241
242	pthread__error(EINVAL, "Invalid attribute",
243	    attr->pta_magic == PT_ATTR_MAGIC);
244
245	if (attr->pta_flags & PT_FLAG_SCOPE_SYSTEM)
246		*scope = PTHREAD_SCOPE_SYSTEM;
247	else
248		*scope = PTHREAD_SCOPE_PROCESS;
249
250	return 0;
251}
252
253
254int
255pthread_attr_setscope(pthread_attr_t *attr, int scope)
256{
257
258	pthread__error(EINVAL, "Invalid attribute",
259	    attr->pta_magic == PT_ATTR_MAGIC);
260
261	switch (scope) {
262	case PTHREAD_SCOPE_PROCESS:
263		attr->pta_flags &= ~PT_FLAG_SCOPE_SYSTEM;
264		break;
265	case PTHREAD_SCOPE_SYSTEM:
266		attr->pta_flags |= PT_FLAG_SCOPE_SYSTEM;
267		break;
268	default:
269		return EINVAL;
270	}
271
272	return 0;
273}
274
275
276int
277pthread_attr_setschedparam(pthread_attr_t *attr,
278			   const struct sched_param *param)
279{
280	struct pthread_attr_private *p;
281	int error;
282
283	pthread__error(EINVAL, "Invalid attribute",
284	    attr->pta_magic == PT_ATTR_MAGIC);
285
286	if (param == NULL)
287		return EINVAL;
288	p = pthread__attr_init_private(attr);
289	if (p == NULL)
290		return ENOMEM;
291	error = pthread__checkpri(param->sched_priority);
292	if (error == 0)
293		p->ptap_sp = *param;
294	return error;
295}
296
297
298int
299pthread_attr_getschedparam(const pthread_attr_t *attr,
300			   struct sched_param *param)
301{
302	struct pthread_attr_private *p;
303
304	pthread__error(EINVAL, "Invalid attribute",
305	    attr->pta_magic == PT_ATTR_MAGIC);
306
307	if (param == NULL)
308		return EINVAL;
309	p = attr->pta_private;
310	if (p == NULL)
311		memset(param, 0, sizeof(*param));
312	else
313		*param = p->ptap_sp;
314	return 0;
315}
316
317
318int
319pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
320{
321	struct pthread_attr_private *p;
322
323	pthread__error(EINVAL, "Invalid attribute",
324	    attr->pta_magic == PT_ATTR_MAGIC);
325
326	switch (policy) {
327	case SCHED_OTHER:
328	case SCHED_FIFO:
329	case SCHED_RR:
330		p = pthread__attr_init_private(attr);
331		if (p == NULL)
332			return ENOMEM;
333		p->ptap_policy = policy;
334		return 0;
335	default:
336		return ENOTSUP;
337	}
338}
339
340
341int
342pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
343{
344	struct pthread_attr_private *p;
345
346	pthread__error(EINVAL, "Invalid attribute",
347	    attr->pta_magic == PT_ATTR_MAGIC);
348
349	p = attr->pta_private;
350	if (p == NULL) {
351		*policy = SCHED_OTHER;
352		return 0;
353	}
354	*policy = p->ptap_policy;
355	return 0;
356}
357
358
359int
360pthread_attr_getstack(const pthread_attr_t *attr, void **addr, size_t *size)
361{
362	struct pthread_attr_private *p;
363
364	pthread__error(EINVAL, "Invalid attribute",
365	    attr->pta_magic == PT_ATTR_MAGIC);
366
367	if ((p = attr->pta_private) == NULL) {
368		*addr = NULL;
369		*size = pthread__stacksize;
370	} else {
371		*addr = p->ptap_stackaddr;
372		*size = p->ptap_stacksize;
373	}
374
375	return 0;
376}
377
378
379int
380pthread_attr_setstack(pthread_attr_t *attr, void *addr, size_t size)
381{
382	struct pthread_attr_private *p;
383
384	pthread__error(EINVAL, "Invalid attribute",
385	    attr->pta_magic == PT_ATTR_MAGIC);
386
387	p = pthread__attr_init_private(attr);
388	if (p == NULL)
389		return ENOMEM;
390
391	p->ptap_stackaddr = addr;
392	p->ptap_stacksize = size;
393
394	return 0;
395}
396
397
398int
399pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *size)
400{
401	struct pthread_attr_private *p;
402
403	pthread__error(EINVAL, "Invalid attribute",
404	    attr->pta_magic == PT_ATTR_MAGIC);
405
406	if ((p = attr->pta_private) == NULL)
407		*size = pthread__stacksize;
408	else
409		*size = p->ptap_stacksize;
410
411	return 0;
412}
413
414
415int
416pthread_attr_setstacksize(pthread_attr_t *attr, size_t size)
417{
418	struct pthread_attr_private *p;
419
420	pthread__error(EINVAL, "Invalid attribute",
421	    attr->pta_magic == PT_ATTR_MAGIC);
422
423	if (size < (size_t)sysconf(_SC_THREAD_STACK_MIN))
424		return EINVAL;
425
426	p = pthread__attr_init_private(attr);
427	if (p == NULL)
428		return ENOMEM;
429
430	p->ptap_stacksize = size;
431
432	return 0;
433}
434
435
436int
437pthread_attr_getstackaddr(const pthread_attr_t *attr, void **addr)
438{
439	struct pthread_attr_private *p;
440
441	pthread__error(EINVAL, "Invalid attribute",
442	    attr->pta_magic == PT_ATTR_MAGIC);
443
444	if ((p = attr->pta_private) == NULL)
445		*addr = NULL;
446	else
447		*addr = p->ptap_stackaddr;
448
449	return 0;
450}
451
452
453int
454pthread_attr_setstackaddr(pthread_attr_t *attr, void *addr)
455{
456	struct pthread_attr_private *p;
457
458	pthread__error(EINVAL, "Invalid attribute",
459	    attr->pta_magic == PT_ATTR_MAGIC);
460
461	p = pthread__attr_init_private(attr);
462	if (p == NULL)
463		return ENOMEM;
464
465	p->ptap_stackaddr = addr;
466
467	return 0;
468}
469
470
471int
472pthread_attr_getname_np(const pthread_attr_t *attr, char *name, size_t len,
473    void **argp)
474{
475	struct pthread_attr_private *p;
476
477	pthread__error(EINVAL, "Invalid attribute",
478	    attr->pta_magic == PT_ATTR_MAGIC);
479
480	if ((p = attr->pta_private) == NULL) {
481		name[0] = '\0';
482		if (argp != NULL)
483			*argp = NULL;
484	} else {
485		strlcpy(name, p->ptap_name, len);
486		if (argp != NULL)
487			*argp = p->ptap_namearg;
488	}
489
490	return 0;
491}
492
493
494int
495pthread_attr_setname_np(pthread_attr_t *attr, const char *name, void *arg)
496{
497	struct pthread_attr_private *p;
498	int namelen;
499
500	pthread__error(EINVAL, "Invalid attribute",
501	    attr->pta_magic == PT_ATTR_MAGIC);
502
503	p = pthread__attr_init_private(attr);
504	if (p == NULL)
505		return ENOMEM;
506
507	namelen = snprintf(p->ptap_name, PTHREAD_MAX_NAMELEN_NP, name, arg);
508	if (namelen >= PTHREAD_MAX_NAMELEN_NP) {
509		p->ptap_name[0] = '\0';
510		return EINVAL;
511	}
512	p->ptap_namearg = arg;
513
514	return 0;
515}
516
517int
518pthread_attr_setcreatesuspend_np(pthread_attr_t *attr)
519{
520
521	pthread__error(EINVAL, "Invalid attribute",
522	    attr->pta_magic == PT_ATTR_MAGIC);
523
524	attr->pta_flags |= PT_FLAG_SUSPENDED;
525	return 0;
526}
527
528int
529pthread_getattr_np(pthread_t thread, pthread_attr_t *attr)
530{
531	int error;
532
533	if ((error = pthread_attr_init(attr)) != 0)
534		return error;
535	if ((error = pthread_attr_get_np(thread, attr)) != 0) {
536		(void)pthread_attr_destroy(attr);
537		return error;
538	}
539	return 0;
540}
541