xref: /dragonfly/lib/libthread_xu/thread/thr_attr.c (revision 55f11bd6ffa4307e05441ec9f250376390316222)
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 <sys/types.h>
36 #include <sys/sysctl.h>
37 #include <machine/tls.h>
38 #include <errno.h>
39 #include <pthread.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <pthread_np.h>
43 #include "un-namespace.h"
44 
45 #include "thr_private.h"
46 
47 int
_pthread_attr_destroy(pthread_attr_t * attr)48 _pthread_attr_destroy(pthread_attr_t *attr)
49 {
50           int       ret;
51 
52           /* Check for invalid arguments: */
53           if (attr == NULL || *attr == NULL) {
54                     /* Invalid argument: */
55                     ret = EINVAL;
56           } else {
57                     /* Free the memory allocated to the attribute object: */
58                     __free(*attr);
59 
60                     /*
61                      * Leave the attribute pointer NULL now that the memory
62                      * has been freed:
63                      */
64                     *attr = NULL;
65                     ret = 0;
66           }
67           return(ret);
68 }
69 
70 __strong_reference(_pthread_attr_destroy, pthread_attr_destroy);
71 
72 int
_pthread_attr_get_np(pthread_t pid,pthread_attr_t * dst)73 _pthread_attr_get_np(pthread_t pid, pthread_attr_t *dst)
74 {
75           pthread_t curthread;
76           struct __pthread_attr_s attr;
77           int       ret;
78 
79           if (pid == NULL || dst == NULL || *dst == NULL)
80                     return (EINVAL);
81 
82           curthread = tls_get_curthread();
83           if ((ret = _thr_ref_add(curthread, pid, /*include dead*/0)) != 0)
84                     return (ret);
85           attr = pid->attr;
86           if (pid->tlflags & TLFLAGS_DETACHED)
87                     attr.flags |= PTHREAD_DETACHED;
88           _thr_ref_delete(curthread, pid);
89           memcpy(*dst, &attr, sizeof(struct __pthread_attr_s));
90 
91           return (0);
92 }
93 
94 __strong_reference(_pthread_attr_get_np, pthread_attr_get_np);
95 
96 int
_pthread_attr_getaffinity_np(const pthread_attr_t * attr,size_t cpusetsize,cpu_set_t * mask)97 _pthread_attr_getaffinity_np(const pthread_attr_t *attr, size_t cpusetsize,
98     cpu_set_t *mask)
99 {
100           const cpu_set_t *ret;
101           cpu_set_t mask1;
102 
103           if (attr == NULL || *attr == NULL || mask == NULL)
104                     return (EINVAL);
105 
106           if (((*attr)->flags & THR_CPUMASK) == 0) {
107                     size_t len;
108 
109                     len = sizeof(mask1);
110                     if (sysctlbyname("machdep.smp_active", &mask1, &len,
111                         NULL, 0) < 0)
112                               return (errno);
113                     ret = &mask1;
114           } else {
115                     ret = &(*attr)->cpumask;
116           }
117 
118           if (cpusetsize > sizeof(*ret)) {
119                     memset(mask, 0, cpusetsize);
120                     memcpy(mask, ret, sizeof(*ret));
121           } else {
122                     memcpy(mask, ret, cpusetsize);
123           }
124           return (0);
125 }
126 
127 __strong_reference(_pthread_attr_getaffinity_np, pthread_attr_getaffinity_np);
128 
129 int
_pthread_attr_getdetachstate(const pthread_attr_t * attr,int * detachstate)130 _pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
131 {
132           int       ret;
133 
134           /* Check for invalid arguments: */
135           if (attr == NULL || *attr == NULL || detachstate == NULL)
136                     ret = EINVAL;
137           else {
138                     /* Check if the detached flag is set: */
139                     if ((*attr)->flags & PTHREAD_DETACHED)
140                               /* Return detached: */
141                               *detachstate = PTHREAD_CREATE_DETACHED;
142                     else
143                               /* Return joinable: */
144                               *detachstate = PTHREAD_CREATE_JOINABLE;
145                     ret = 0;
146           }
147           return(ret);
148 }
149 
150 __strong_reference(_pthread_attr_getdetachstate, pthread_attr_getdetachstate);
151 
152 int
_pthread_attr_getguardsize(const pthread_attr_t * __restrict attr,size_t * __restrict guardsize)153 _pthread_attr_getguardsize(const pthread_attr_t * __restrict attr,
154     size_t * __restrict guardsize)
155 {
156           int       ret;
157 
158           /* Check for invalid arguments: */
159           if (attr == NULL || *attr == NULL || guardsize == NULL)
160                     ret = EINVAL;
161           else {
162                     /* Return the guard size: */
163                     *guardsize = (*attr)->guardsize_attr;
164                     ret = 0;
165           }
166           return(ret);
167 }
168 
169 __strong_reference(_pthread_attr_getguardsize, pthread_attr_getguardsize);
170 
171 int
_pthread_attr_getinheritsched(const pthread_attr_t * __restrict attr,int * __restrict sched_inherit)172 _pthread_attr_getinheritsched(const pthread_attr_t * __restrict attr,
173     int * __restrict sched_inherit)
174 {
175           int ret = 0;
176 
177           if ((attr == NULL) || (*attr == NULL))
178                     ret = EINVAL;
179           else
180                     *sched_inherit = (*attr)->sched_inherit;
181 
182           return(ret);
183 }
184 
185 __strong_reference(_pthread_attr_getinheritsched, pthread_attr_getinheritsched);
186 
187 int
_pthread_attr_getschedparam(const pthread_attr_t * __restrict attr,struct sched_param * __restrict param)188 _pthread_attr_getschedparam(const pthread_attr_t * __restrict attr,
189     struct sched_param * __restrict param)
190 {
191           int ret = 0;
192 
193           if ((attr == NULL) || (*attr == NULL) || (param == NULL))
194                     ret = EINVAL;
195           else
196                     param->sched_priority = (*attr)->prio;
197 
198           return(ret);
199 }
200 
201 __strong_reference(_pthread_attr_getschedparam, pthread_attr_getschedparam);
202 
203 int
_pthread_attr_getschedpolicy(const pthread_attr_t * __restrict attr,int * __restrict policy)204 _pthread_attr_getschedpolicy(const pthread_attr_t * __restrict attr,
205     int * __restrict policy)
206 {
207           int ret = 0;
208 
209           if ((attr == NULL) || (*attr == NULL) || (policy == NULL))
210                     ret = EINVAL;
211           else
212                     *policy = (*attr)->sched_policy;
213 
214           return(ret);
215 }
216 
217 __strong_reference(_pthread_attr_getschedpolicy, pthread_attr_getschedpolicy);
218 
219 int
_pthread_attr_getscope(const pthread_attr_t * __restrict attr,int * __restrict contentionscope)220 _pthread_attr_getscope(const pthread_attr_t * __restrict attr,
221     int * __restrict contentionscope)
222 {
223           int ret = 0;
224 
225           if ((attr == NULL) || (*attr == NULL) || (contentionscope == NULL))
226                     /* Return an invalid argument: */
227                     ret = EINVAL;
228 
229           else
230                     *contentionscope = ((*attr)->flags & PTHREAD_SCOPE_SYSTEM) ?
231                         PTHREAD_SCOPE_SYSTEM : PTHREAD_SCOPE_PROCESS;
232 
233           return(ret);
234 }
235 
236 __strong_reference(_pthread_attr_getscope, pthread_attr_getscope);
237 
238 int
_pthread_attr_getstack(const pthread_attr_t * __restrict attr,void ** __restrict stackaddr,size_t * __restrict stacksize)239 _pthread_attr_getstack(const pthread_attr_t * __restrict attr,
240                            void ** __restrict stackaddr,
241                            size_t * __restrict stacksize)
242 {
243           int     ret;
244 
245           /* Check for invalid arguments: */
246           if (attr == NULL || *attr == NULL || stackaddr == NULL
247               || stacksize == NULL )
248                     ret = EINVAL;
249           else {
250                     /* Return the stack address and size */
251                     *stackaddr = (*attr)->stackaddr_attr;
252                     *stacksize = (*attr)->stacksize_attr;
253                     ret = 0;
254           }
255           return(ret);
256 }
257 
258 __strong_reference(_pthread_attr_getstack, pthread_attr_getstack);
259 
260 int
_pthread_attr_getstackaddr(const pthread_attr_t * attr,void ** stackaddr)261 _pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr)
262 {
263           int       ret;
264 
265           /* Check for invalid arguments: */
266           if (attr == NULL || *attr == NULL || stackaddr == NULL)
267                     ret = EINVAL;
268           else {
269                     /* Return the stack address: */
270                     *stackaddr = (*attr)->stackaddr_attr;
271                     ret = 0;
272           }
273           return(ret);
274 }
275 
276 __strong_reference(_pthread_attr_getstackaddr, pthread_attr_getstackaddr);
277 
278 int
_pthread_attr_getstacksize(const pthread_attr_t * __restrict attr,size_t * __restrict stacksize)279 _pthread_attr_getstacksize(const pthread_attr_t * __restrict attr,
280     size_t * __restrict stacksize)
281 {
282           int       ret;
283 
284           /* Check for invalid arguments: */
285           if (attr == NULL || *attr == NULL || stacksize  == NULL)
286                     ret = EINVAL;
287           else {
288                     /* Return the stack size: */
289                     *stacksize = (*attr)->stacksize_attr;
290                     ret = 0;
291           }
292           return(ret);
293 }
294 
295 __strong_reference(_pthread_attr_getstacksize, pthread_attr_getstacksize);
296 
297 int
_pthread_attr_init(pthread_attr_t * attr)298 _pthread_attr_init(pthread_attr_t *attr)
299 {
300           int       ret;
301           pthread_attr_t      pattr;
302 
303           /* Allocate memory for the attribute object: */
304           pattr = __malloc(sizeof(struct __pthread_attr_s));
305           if (pattr == NULL) {
306                     /* Insufficient memory: */
307                     ret = ENOMEM;
308           } else {
309                     /* Initialise the attribute object with the defaults: */
310                     memcpy(pattr, &_pthread_attr_default,
311                         sizeof(struct __pthread_attr_s));
312 
313                     /* Return a pointer to the attribute object: */
314                     *attr = pattr;
315                     ret = 0;
316           }
317           return(ret);
318 }
319 
320 __strong_reference(_pthread_attr_init, pthread_attr_init);
321 
322 int
_pthread_attr_setaffinity_np(pthread_attr_t * attr,size_t cpusetsize,const cpu_set_t * mask)323 _pthread_attr_setaffinity_np(pthread_attr_t *attr, size_t cpusetsize,
324     const cpu_set_t *mask)
325 {
326           cpu_set_t active, mask1;
327           size_t len, cplen = cpusetsize;
328 
329           if (attr == NULL || *attr == NULL || mask == NULL)
330                     return (EINVAL);
331 
332           if (cplen > sizeof(mask1))
333                     cplen = sizeof(mask1);
334           CPU_ZERO(&mask1);
335           memcpy(&mask1, mask, cplen);
336 
337           len = sizeof(active);
338           if (sysctlbyname("machdep.smp_active", &active, &len, NULL, 0) < 0)
339                     return (errno);
340 
341           CPUMASK_ANDMASK(mask1, active);
342           if (CPUMASK_TESTZERO(mask1))
343                     return (EPERM);
344 
345           (*attr)->cpumask = mask1;
346           (*attr)->flags |= THR_CPUMASK;
347           return (0);
348 }
349 
350 __strong_reference(_pthread_attr_setaffinity_np, pthread_attr_setaffinity_np);
351 
352 int
_pthread_attr_setcreatesuspend_np(pthread_attr_t * attr)353 _pthread_attr_setcreatesuspend_np(pthread_attr_t *attr)
354 {
355           int       ret;
356 
357           if (attr == NULL || *attr == NULL) {
358                     ret = EINVAL;
359           } else {
360                     (*attr)->suspend = THR_CREATE_SUSPENDED;
361                     ret = 0;
362           }
363           return(ret);
364 }
365 
366 __strong_reference(_pthread_attr_setcreatesuspend_np, pthread_attr_setcreatesuspend_np);
367 
368 int
_pthread_attr_setdetachstate(pthread_attr_t * attr,int detachstate)369 _pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
370 {
371           int       ret;
372 
373           /* Check for invalid arguments: */
374           if (attr == NULL || *attr == NULL ||
375               (detachstate != PTHREAD_CREATE_DETACHED &&
376               detachstate != PTHREAD_CREATE_JOINABLE))
377                     ret = EINVAL;
378           else {
379                     /* Check if detached state: */
380                     if (detachstate == PTHREAD_CREATE_DETACHED)
381                               /* Set the detached flag: */
382                               (*attr)->flags |= PTHREAD_DETACHED;
383                     else
384                               /* Reset the detached flag: */
385                               (*attr)->flags &= ~PTHREAD_DETACHED;
386                     ret = 0;
387           }
388           return(ret);
389 }
390 
391 __strong_reference(_pthread_attr_setdetachstate, pthread_attr_setdetachstate);
392 
393 int
_pthread_attr_setguardsize(pthread_attr_t * attr,size_t guardsize)394 _pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize)
395 {
396           int       ret;
397 
398           /* Check for invalid arguments. */
399           if (attr == NULL || *attr == NULL)
400                     ret = EINVAL;
401           else {
402                     /* Save the stack size. */
403                     (*attr)->guardsize_attr = guardsize;
404                     ret = 0;
405           }
406           return(ret);
407 }
408 
409 __strong_reference(_pthread_attr_setguardsize, pthread_attr_setguardsize);
410 
411 int
_pthread_attr_setinheritsched(pthread_attr_t * attr,int sched_inherit)412 _pthread_attr_setinheritsched(pthread_attr_t *attr, int sched_inherit)
413 {
414           int ret = 0;
415 
416           if ((attr == NULL) || (*attr == NULL))
417                     ret = EINVAL;
418           else if (sched_inherit != PTHREAD_INHERIT_SCHED &&
419                      sched_inherit != PTHREAD_EXPLICIT_SCHED)
420                     ret = EINVAL;
421           else
422                     (*attr)->sched_inherit = sched_inherit;
423 
424           return(ret);
425 }
426 
427 __strong_reference(_pthread_attr_setinheritsched, pthread_attr_setinheritsched);
428 
429 int
_pthread_attr_setschedparam(pthread_attr_t * __restrict attr,const struct sched_param * __restrict param)430 _pthread_attr_setschedparam(pthread_attr_t * __restrict attr,
431     const struct sched_param * __restrict param)
432 {
433           int policy;
434 
435           if ((attr == NULL) || (*attr == NULL))
436                     return (EINVAL);
437 
438           if (param == NULL)
439                     return (ENOTSUP);
440 
441           policy = (*attr)->sched_policy;
442 
443           {
444                     int minv = sched_get_priority_min(policy);
445                     int maxv = sched_get_priority_max(policy);
446                     if (minv == -1 || maxv == -1 ||
447                         param->sched_priority < minv ||
448                         param->sched_priority > maxv) {
449                               return (ENOTSUP);
450                     }
451           }
452 
453           (*attr)->prio = param->sched_priority;
454 
455           return (0);
456 }
457 
458 __strong_reference(_pthread_attr_setschedparam, pthread_attr_setschedparam);
459 
460 int
_pthread_attr_setschedpolicy(pthread_attr_t * attr,int pol)461 _pthread_attr_setschedpolicy(pthread_attr_t *attr, int pol)
462 {
463           int ret = 0;
464 
465           if ((attr == NULL) || (*attr == NULL))
466                     ret = EINVAL;
467           else if (pol != SCHED_FIFO && pol != SCHED_OTHER && pol != SCHED_RR)
468                     ret = EINVAL;
469           else
470                     (*attr)->sched_policy = pol;
471 
472           return(ret);
473 }
474 
475 __strong_reference(_pthread_attr_setschedpolicy, pthread_attr_setschedpolicy);
476 
477 int
_pthread_attr_setscope(pthread_attr_t * attr,int contentionscope)478 _pthread_attr_setscope(pthread_attr_t *attr, int contentionscope)
479 {
480           int ret = 0;
481 
482           if ((attr == NULL) || (*attr == NULL)) {
483                     /* Return an invalid argument: */
484                     ret = EINVAL;
485           } else if ((contentionscope != PTHREAD_SCOPE_PROCESS) &&
486               (contentionscope != PTHREAD_SCOPE_SYSTEM)) {
487                     ret = EINVAL;
488           } else if (contentionscope == PTHREAD_SCOPE_SYSTEM) {
489                     (*attr)->flags |= contentionscope;
490           } else {
491                     (*attr)->flags &= ~PTHREAD_SCOPE_SYSTEM;
492           }
493           return (ret);
494 }
495 
496 __strong_reference(_pthread_attr_setscope, pthread_attr_setscope);
497 
498 int
_pthread_attr_setstack(pthread_attr_t * attr,void * stackaddr,size_t stacksize)499 _pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr,
500                            size_t stacksize)
501 {
502           int     ret;
503 
504           /* Check for invalid arguments: */
505           if (attr == NULL || *attr == NULL || stackaddr == NULL
506               || stacksize < PTHREAD_STACK_MIN)
507                     ret = EINVAL;
508           else {
509                     /* Save the stack address and stack size */
510                     (*attr)->stackaddr_attr = stackaddr;
511                     (*attr)->stacksize_attr = stacksize;
512                     ret = 0;
513           }
514           return(ret);
515 }
516 
517 __strong_reference(_pthread_attr_setstack, pthread_attr_setstack);
518 
519 int
_pthread_attr_setstackaddr(pthread_attr_t * attr,void * stackaddr)520 _pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr)
521 {
522           int       ret;
523 
524           /* Check for invalid arguments: */
525           if (attr == NULL || *attr == NULL || stackaddr == NULL)
526                     ret = EINVAL;
527           else {
528                     /* Save the stack address: */
529                     (*attr)->stackaddr_attr = stackaddr;
530                     ret = 0;
531           }
532           return(ret);
533 }
534 
535 __strong_reference(_pthread_attr_setstackaddr, pthread_attr_setstackaddr);
536 
537 int
_pthread_attr_setstacksize(pthread_attr_t * attr,size_t stacksize)538 _pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
539 {
540           int       ret;
541 
542           /* Check for invalid arguments: */
543           if (attr == NULL || *attr == NULL || stacksize < PTHREAD_STACK_MIN)
544                     ret = EINVAL;
545           else {
546                     /* Save the stack size: */
547                     (*attr)->stacksize_attr = stacksize;
548                     ret = 0;
549           }
550           return(ret);
551 }
552 
553 __strong_reference(_pthread_attr_setstacksize, pthread_attr_setstacksize);
554 
555 int
_pthread_getattr_np(pthread_t thread,pthread_attr_t * attr)556 _pthread_getattr_np(pthread_t thread, pthread_attr_t *attr)
557 {
558           int ret;
559 
560           if ((ret = pthread_attr_init(attr)) != 0)
561                     return ret;
562         if ((ret = pthread_attr_get_np(thread, attr)) != 0) {
563                     pthread_attr_destroy(attr);
564                     return ret;
565           }
566           return 0;
567 }
568 __strong_reference(_pthread_getattr_np, pthread_getattr_np);
569