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 "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 <sys/sysctl.h>
103 #include "un-namespace.h"
104
105 #include "thr_private.h"
106
107 static size_t _get_kern_cpuset_size(void);
108
109 __weak_reference(_thr_attr_destroy, _pthread_attr_destroy);
110 __weak_reference(_thr_attr_destroy, pthread_attr_destroy);
111
112 int
_thr_attr_destroy(pthread_attr_t * attr)113 _thr_attr_destroy(pthread_attr_t *attr)
114 {
115
116 if (attr == NULL || *attr == NULL)
117 return (EINVAL);
118
119 free((*attr)->cpuset);
120 free(*attr);
121 *attr = NULL;
122 return (0);
123 }
124
125 __weak_reference(_thr_attr_get_np, pthread_attr_get_np);
126 __weak_reference(_thr_attr_get_np, _pthread_attr_get_np);
127
128 int
_thr_attr_get_np(pthread_t pthread,pthread_attr_t * dstattr)129 _thr_attr_get_np(pthread_t pthread, pthread_attr_t *dstattr)
130 {
131 struct pthread_attr *dst;
132 struct pthread *curthread;
133 cpuset_t *cpuset;
134 size_t kern_size;
135 int error;
136
137 if (pthread == NULL || dstattr == NULL || (dst = *dstattr) == NULL)
138 return (EINVAL);
139
140 kern_size = _get_kern_cpuset_size();
141 if (dst->cpuset == NULL) {
142 if ((cpuset = malloc(kern_size)) == NULL)
143 return (ENOMEM);
144 } else
145 cpuset = dst->cpuset;
146
147 curthread = _get_curthread();
148 /* Arg 0 is to include dead threads. */
149 if ((error = _thr_find_thread(curthread, pthread, 0)) != 0)
150 goto free_and_exit;
151
152 error = cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, TID(pthread),
153 kern_size, cpuset);
154 if (error == -1) {
155 THR_THREAD_UNLOCK(curthread, pthread);
156 error = errno;
157 goto free_and_exit;
158 }
159
160 /*
161 * From this point on, we can't fail, so we can start modifying 'dst'.
162 */
163
164 *dst = pthread->attr;
165 if ((pthread->flags & THR_FLAGS_DETACHED) != 0)
166 dst->flags |= PTHREAD_DETACHED;
167
168 THR_THREAD_UNLOCK(curthread, pthread);
169
170 dst->cpuset = cpuset;
171 dst->cpusetsize = kern_size;
172 return (0);
173
174 free_and_exit:
175 if (dst->cpuset == NULL)
176 free(cpuset);
177 return (error);
178 }
179
180 __weak_reference(_thr_attr_getdetachstate, pthread_attr_getdetachstate);
181 __weak_reference(_thr_attr_getdetachstate, _pthread_attr_getdetachstate);
182
183 int
_thr_attr_getdetachstate(const pthread_attr_t * attr,int * detachstate)184 _thr_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
185 {
186
187 if (attr == NULL || *attr == NULL || detachstate == NULL)
188 return (EINVAL);
189
190 if (((*attr)->flags & PTHREAD_DETACHED) != 0)
191 *detachstate = PTHREAD_CREATE_DETACHED;
192 else
193 *detachstate = PTHREAD_CREATE_JOINABLE;
194 return (0);
195 }
196
197 __weak_reference(_thr_attr_getguardsize, pthread_attr_getguardsize);
198 __weak_reference(_thr_attr_getguardsize, _pthread_attr_getguardsize);
199
200 int
_thr_attr_getguardsize(const pthread_attr_t * __restrict attr,size_t * __restrict guardsize)201 _thr_attr_getguardsize(const pthread_attr_t * __restrict attr,
202 size_t * __restrict guardsize)
203 {
204
205 if (attr == NULL || *attr == NULL || guardsize == NULL)
206 return (EINVAL);
207
208 *guardsize = (*attr)->guardsize_attr;
209 return (0);
210 }
211
212 __weak_reference(_thr_attr_getinheritsched, pthread_attr_getinheritsched);
213 __weak_reference(_thr_attr_getinheritsched, _pthread_attr_getinheritsched);
214
215 int
_thr_attr_getinheritsched(const pthread_attr_t * __restrict attr,int * __restrict sched_inherit)216 _thr_attr_getinheritsched(const pthread_attr_t * __restrict attr,
217 int * __restrict sched_inherit)
218 {
219
220 if (attr == NULL || *attr == NULL)
221 return (EINVAL);
222
223 *sched_inherit = (*attr)->sched_inherit;
224 return (0);
225 }
226
227 __weak_reference(_thr_attr_getschedparam, pthread_attr_getschedparam);
228 __weak_reference(_thr_attr_getschedparam, _pthread_attr_getschedparam);
229
230 int
_thr_attr_getschedparam(const pthread_attr_t * __restrict attr,struct sched_param * __restrict param)231 _thr_attr_getschedparam(const pthread_attr_t * __restrict attr,
232 struct sched_param * __restrict param)
233 {
234
235 if (attr == NULL || *attr == NULL || param == NULL)
236 return (EINVAL);
237
238 param->sched_priority = (*attr)->prio;
239 return (0);
240 }
241
242 __weak_reference(_thr_attr_getschedpolicy, pthread_attr_getschedpolicy);
243 __weak_reference(_thr_attr_getschedpolicy, _pthread_attr_getschedpolicy);
244
245 int
_thr_attr_getschedpolicy(const pthread_attr_t * __restrict attr,int * __restrict policy)246 _thr_attr_getschedpolicy(const pthread_attr_t * __restrict attr,
247 int * __restrict policy)
248 {
249
250 if (attr == NULL || *attr == NULL || policy == NULL)
251 return (EINVAL);
252
253 *policy = (*attr)->sched_policy;
254 return (0);
255 }
256
257 __weak_reference(_thr_attr_getscope, pthread_attr_getscope);
258 __weak_reference(_thr_attr_getscope, _pthread_attr_getscope);
259
260 int
_thr_attr_getscope(const pthread_attr_t * __restrict attr,int * __restrict contentionscope)261 _thr_attr_getscope(const pthread_attr_t * __restrict attr,
262 int * __restrict contentionscope)
263 {
264
265 if (attr == NULL || *attr == NULL || contentionscope == NULL)
266 return (EINVAL);
267
268 *contentionscope = ((*attr)->flags & PTHREAD_SCOPE_SYSTEM) != 0 ?
269 PTHREAD_SCOPE_SYSTEM : PTHREAD_SCOPE_PROCESS;
270 return (0);
271 }
272
273 __weak_reference(_pthread_attr_getstack, pthread_attr_getstack);
274
275 int
_pthread_attr_getstack(const pthread_attr_t * __restrict attr,void ** __restrict stackaddr,size_t * __restrict stacksize)276 _pthread_attr_getstack(const pthread_attr_t * __restrict attr,
277 void ** __restrict stackaddr, size_t * __restrict stacksize)
278 {
279
280 if (attr == NULL || *attr == NULL || stackaddr == NULL ||
281 stacksize == NULL)
282 return (EINVAL);
283
284 *stackaddr = (*attr)->stackaddr_attr;
285 *stacksize = (*attr)->stacksize_attr;
286 return (0);
287 }
288
289 __weak_reference(_thr_attr_getstackaddr, pthread_attr_getstackaddr);
290 __weak_reference(_thr_attr_getstackaddr, _pthread_attr_getstackaddr);
291
292 int
_thr_attr_getstackaddr(const pthread_attr_t * attr,void ** stackaddr)293 _thr_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr)
294 {
295
296 if (attr == NULL || *attr == NULL || stackaddr == NULL)
297 return (EINVAL);
298
299 *stackaddr = (*attr)->stackaddr_attr;
300 return (0);
301 }
302
303 __weak_reference(_thr_attr_getstacksize, pthread_attr_getstacksize);
304 __weak_reference(_thr_attr_getstacksize, _pthread_attr_getstacksize);
305
306 int
_thr_attr_getstacksize(const pthread_attr_t * __restrict attr,size_t * __restrict stacksize)307 _thr_attr_getstacksize(const pthread_attr_t * __restrict attr,
308 size_t * __restrict stacksize)
309 {
310
311 if (attr == NULL || *attr == NULL || stacksize == NULL)
312 return (EINVAL);
313
314 *stacksize = (*attr)->stacksize_attr;
315 return (0);
316 }
317
318 __weak_reference(_thr_attr_init, pthread_attr_init);
319 __weak_reference(_thr_attr_init, _pthread_attr_init);
320
321 int
_thr_attr_init(pthread_attr_t * attr)322 _thr_attr_init(pthread_attr_t *attr)
323 {
324 pthread_attr_t pattr;
325
326 _thr_check_init();
327
328 if ((pattr = malloc(sizeof(*pattr))) == NULL)
329 return (ENOMEM);
330
331 memcpy(pattr, &_pthread_attr_default, sizeof(*pattr));
332 *attr = pattr;
333 return (0);
334 }
335
336 __weak_reference(_pthread_attr_setcreatesuspend_np, \
337 pthread_attr_setcreatesuspend_np);
338
339 int
_pthread_attr_setcreatesuspend_np(pthread_attr_t * attr)340 _pthread_attr_setcreatesuspend_np(pthread_attr_t *attr)
341 {
342
343 if (attr == NULL || *attr == NULL)
344 return (EINVAL);
345
346 (*attr)->suspend = THR_CREATE_SUSPENDED;
347 return (0);
348 }
349
350 __weak_reference(_thr_attr_setdetachstate, pthread_attr_setdetachstate);
351 __weak_reference(_thr_attr_setdetachstate, _pthread_attr_setdetachstate);
352
353 int
_thr_attr_setdetachstate(pthread_attr_t * attr,int detachstate)354 _thr_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
355 {
356
357 if (attr == NULL || *attr == NULL ||
358 (detachstate != PTHREAD_CREATE_DETACHED &&
359 detachstate != PTHREAD_CREATE_JOINABLE))
360 return (EINVAL);
361
362 if (detachstate == PTHREAD_CREATE_DETACHED)
363 (*attr)->flags |= PTHREAD_DETACHED;
364 else
365 (*attr)->flags &= ~PTHREAD_DETACHED;
366 return (0);
367 }
368
369 __weak_reference(_thr_attr_setguardsize, pthread_attr_setguardsize);
370 __weak_reference(_thr_attr_setguardsize, _pthread_attr_setguardsize);
371
372 int
_thr_attr_setguardsize(pthread_attr_t * attr,size_t guardsize)373 _thr_attr_setguardsize(pthread_attr_t *attr, size_t guardsize)
374 {
375
376 if (attr == NULL || *attr == NULL)
377 return (EINVAL);
378
379 (*attr)->guardsize_attr = guardsize;
380 return (0);
381 }
382
383 __weak_reference(_thr_attr_setinheritsched, pthread_attr_setinheritsched);
384 __weak_reference(_thr_attr_setinheritsched, _pthread_attr_setinheritsched);
385
386 int
_thr_attr_setinheritsched(pthread_attr_t * attr,int sched_inherit)387 _thr_attr_setinheritsched(pthread_attr_t *attr, int sched_inherit)
388 {
389
390 if (attr == NULL || *attr == NULL ||
391 (sched_inherit != PTHREAD_INHERIT_SCHED &&
392 sched_inherit != PTHREAD_EXPLICIT_SCHED))
393 return (EINVAL);
394
395 (*attr)->sched_inherit = sched_inherit;
396 return (0);
397 }
398
399 __weak_reference(_thr_attr_setschedparam, pthread_attr_setschedparam);
400 __weak_reference(_thr_attr_setschedparam, _pthread_attr_setschedparam);
401
402 int
_thr_attr_setschedparam(pthread_attr_t * __restrict attr,const struct sched_param * __restrict param)403 _thr_attr_setschedparam(pthread_attr_t * __restrict attr,
404 const struct sched_param * __restrict param)
405 {
406 int policy;
407
408 if (attr == NULL || *attr == NULL || param == NULL)
409 return (EINVAL);
410
411 policy = (*attr)->sched_policy;
412
413 if (policy == SCHED_FIFO || policy == SCHED_RR) {
414 if (param->sched_priority < _thr_priorities[policy-1].pri_min ||
415 param->sched_priority > _thr_priorities[policy-1].pri_max)
416 return (EINVAL);
417 } else {
418 /*
419 * Ignore it for SCHED_OTHER now, patches for glib ports
420 * are wrongly using M:N thread library's internal macro
421 * THR_MIN_PRIORITY and THR_MAX_PRIORITY.
422 */
423 }
424
425 (*attr)->prio = param->sched_priority;
426
427 return (0);
428 }
429
430 __weak_reference(_thr_attr_setschedpolicy, pthread_attr_setschedpolicy);
431 __weak_reference(_thr_attr_setschedpolicy, _pthread_attr_setschedpolicy);
432
433 int
_thr_attr_setschedpolicy(pthread_attr_t * attr,int policy)434 _thr_attr_setschedpolicy(pthread_attr_t *attr, int policy)
435 {
436
437 if (attr == NULL || *attr == NULL ||
438 policy < SCHED_FIFO || policy > SCHED_RR)
439 return (EINVAL);
440
441 (*attr)->sched_policy = policy;
442 (*attr)->prio = _thr_priorities[policy-1].pri_default;
443 return (0);
444 }
445
446 __weak_reference(_thr_attr_setscope, pthread_attr_setscope);
447 __weak_reference(_thr_attr_setscope, _pthread_attr_setscope);
448
449 int
_thr_attr_setscope(pthread_attr_t * attr,int contentionscope)450 _thr_attr_setscope(pthread_attr_t *attr, int contentionscope)
451 {
452
453 if (attr == NULL || *attr == NULL ||
454 (contentionscope != PTHREAD_SCOPE_PROCESS &&
455 contentionscope != PTHREAD_SCOPE_SYSTEM))
456 return (EINVAL);
457
458 if (contentionscope == PTHREAD_SCOPE_SYSTEM)
459 (*attr)->flags |= PTHREAD_SCOPE_SYSTEM;
460 else
461 (*attr)->flags &= ~PTHREAD_SCOPE_SYSTEM;
462 return (0);
463 }
464
465 __weak_reference(_pthread_attr_setstack, pthread_attr_setstack);
466
467 int
_pthread_attr_setstack(pthread_attr_t * attr,void * stackaddr,size_t stacksize)468 _pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr,
469 size_t stacksize)
470 {
471
472 if (attr == NULL || *attr == NULL || stackaddr == NULL ||
473 stacksize < PTHREAD_STACK_MIN)
474 return (EINVAL);
475
476 (*attr)->stackaddr_attr = stackaddr;
477 (*attr)->stacksize_attr = stacksize;
478 return (0);
479 }
480
481 __weak_reference(_thr_attr_setstackaddr, pthread_attr_setstackaddr);
482 __weak_reference(_thr_attr_setstackaddr, _pthread_attr_setstackaddr);
483
484 int
_thr_attr_setstackaddr(pthread_attr_t * attr,void * stackaddr)485 _thr_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr)
486 {
487
488 if (attr == NULL || *attr == NULL || stackaddr == NULL)
489 return (EINVAL);
490
491 (*attr)->stackaddr_attr = stackaddr;
492 return (0);
493 }
494
495 __weak_reference(_thr_attr_setstacksize, pthread_attr_setstacksize);
496 __weak_reference(_thr_attr_setstacksize, _pthread_attr_setstacksize);
497
498 int
_thr_attr_setstacksize(pthread_attr_t * attr,size_t stacksize)499 _thr_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
500 {
501
502 if (attr == NULL || *attr == NULL || stacksize < PTHREAD_STACK_MIN)
503 return (EINVAL);
504
505 (*attr)->stacksize_attr = stacksize;
506 return (0);
507 }
508
509 static size_t
_get_kern_cpuset_size(void)510 _get_kern_cpuset_size(void)
511 {
512 static int kern_cpuset_size = 0;
513
514 if (kern_cpuset_size == 0) {
515 size_t len;
516
517 len = sizeof(kern_cpuset_size);
518 if (sysctlbyname("kern.sched.cpusetsizemin", &kern_cpuset_size,
519 &len, NULL, 0) != 0 &&
520 sysctlbyname("kern.sched.cpusetsize", &kern_cpuset_size,
521 &len, NULL, 0) != 0)
522 PANIC("failed to get sysctl kern.sched.cpusetsize");
523 }
524
525 return (kern_cpuset_size);
526 }
527
528 __weak_reference(_pthread_attr_setaffinity_np, pthread_attr_setaffinity_np);
529
530 int
_pthread_attr_setaffinity_np(pthread_attr_t * pattr,size_t cpusetsize,const cpuset_t * cpusetp)531 _pthread_attr_setaffinity_np(pthread_attr_t *pattr, size_t cpusetsize,
532 const cpuset_t *cpusetp)
533 {
534 pthread_attr_t attr;
535 size_t kern_size;
536
537 if (pattr == NULL || (attr = (*pattr)) == NULL)
538 return (EINVAL);
539
540 if (cpusetsize == 0 || cpusetp == NULL) {
541 if (attr->cpuset != NULL) {
542 free(attr->cpuset);
543 attr->cpuset = NULL;
544 attr->cpusetsize = 0;
545 }
546 return (0);
547 }
548
549 kern_size = _get_kern_cpuset_size();
550 /* Kernel rejects small set, we check it here too. */
551 if (cpusetsize < kern_size)
552 return (ERANGE);
553 if (cpusetsize > kern_size) {
554 /* Kernel checks invalid bits, we check it here too. */
555 size_t i;
556
557 for (i = kern_size; i < cpusetsize; ++i)
558 if (((const char *)cpusetp)[i] != 0)
559 return (EINVAL);
560 }
561 if (attr->cpuset == NULL) {
562 attr->cpuset = malloc(kern_size);
563 if (attr->cpuset == NULL)
564 return (errno);
565 attr->cpusetsize = kern_size;
566 }
567 memcpy(attr->cpuset, cpusetp, kern_size);
568 return (0);
569 }
570
571 __weak_reference(_pthread_attr_getaffinity_np, pthread_attr_getaffinity_np);
572
573 int
_pthread_attr_getaffinity_np(const pthread_attr_t * pattr,size_t cpusetsize,cpuset_t * cpusetp)574 _pthread_attr_getaffinity_np(const pthread_attr_t *pattr, size_t cpusetsize,
575 cpuset_t *cpusetp)
576 {
577 pthread_attr_t attr;
578
579 if (pattr == NULL || (attr = (*pattr)) == NULL)
580 return (EINVAL);
581
582 /* Kernel rejects small set, we check it here too. */
583 size_t kern_size = _get_kern_cpuset_size();
584 if (cpusetsize < kern_size)
585 return (ERANGE);
586 if (attr->cpuset != NULL)
587 memcpy(cpusetp, attr->cpuset, MIN(cpusetsize,
588 attr->cpusetsize));
589 else
590 memset(cpusetp, -1, kern_size);
591 if (cpusetsize > kern_size)
592 memset(((char *)cpusetp) + kern_size, 0,
593 cpusetsize - kern_size);
594 return (0);
595 }
596