1/* 2 * Copyright (c) 2003 Craig Rodrigues <rodrigc@attbi.com>. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Craig Rodrigues. 16 * 4. Neither the name of the author nor the names of any co-contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY CRAIG RODRIGUES AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 */ 33 34/* 35 * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.com>. 36 * Copyright (C) 2001 Jason Evans <jasone@freebsd.org>. 37 * Copyright (c) 2002,2003 Alexey Zelkin <phantom@FreeBSD.org> 38 * All rights reserved. 39 * 40 * Redistribution and use in source and binary forms, with or without 41 * modification, are permitted provided that the following conditions 42 * are met: 43 * 1. Redistributions of source code must retain the above copyright 44 * notice(s), this list of conditions and the following disclaimer 45 * unmodified other than the allowable addition of one or more 46 * copyright notices. 47 * 2. Redistributions in binary form must reproduce the above copyright 48 * notice(s), this list of conditions and the following disclaimer in 49 * the documentation and/or other materials provided with the 50 * distribution. 51 * 52 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY 53 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 55 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE 56 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 57 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 58 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 59 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 60 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 61 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 62 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 63 */ 64 65/* 66 * Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>. 67 * All rights reserved. 68 * 69 * Redistribution and use in source and binary forms, with or without 70 * modification, are permitted provided that the following conditions 71 * are met: 72 * 1. Redistributions of source code must retain the above copyright 73 * notice, this list of conditions and the following disclaimer. 74 * 2. Redistributions in binary form must reproduce the above copyright 75 * notice, this list of conditions and the following disclaimer in the 76 * documentation and/or other materials provided with the distribution. 77 * 3. Neither the name of the author nor the names of any co-contributors 78 * may be used to endorse or promote products derived from this software 79 * without specific prior written permission. 80 * 81 * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND 82 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 83 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 84 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 85 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 86 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 87 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 88 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 89 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 90 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 91 * SUCH DAMAGE. 92 */ 93 94#include <sys/cdefs.h> 95__FBSDID("$FreeBSD: stable/11/lib/libthr/thread/thr_attr.c 338707 2018-09-17 02:51:08Z pfg $"); 96 97#include "namespace.h" 98#include <errno.h> 99#include <pthread.h> 100#include <stdlib.h> 101#include <string.h> 102#include <pthread_np.h> 103#include <sys/sysctl.h> 104#include "un-namespace.h" 105 106#include "thr_private.h" 107 108static size_t _get_kern_cpuset_size(void); 109 110__weak_reference(_pthread_attr_destroy, pthread_attr_destroy); 111 112int 113_pthread_attr_destroy(pthread_attr_t *attr) 114{ 115 int ret; 116 117 /* Check for invalid arguments: */ 118 if (attr == NULL || *attr == NULL) 119 /* Invalid argument: */ 120 ret = EINVAL; 121 else { 122 if ((*attr)->cpuset != NULL) 123 free((*attr)->cpuset); 124 /* Free the memory allocated to the attribute object: */ 125 free(*attr); 126 127 /* 128 * Leave the attribute pointer NULL now that the memory 129 * has been freed: 130 */ 131 *attr = NULL; 132 ret = 0; 133 } 134 return(ret); 135} 136 137__weak_reference(_pthread_attr_get_np, pthread_attr_get_np); 138 139int 140_pthread_attr_get_np(pthread_t pthread, pthread_attr_t *dstattr) 141{ 142 struct pthread *curthread; 143 struct pthread_attr attr, *dst; 144 int ret; 145 size_t kern_size; 146 147 if (pthread == NULL || dstattr == NULL || (dst = *dstattr) == NULL) 148 return (EINVAL); 149 kern_size = _get_kern_cpuset_size(); 150 if (dst->cpuset == NULL) { 151 dst->cpuset = calloc(1, kern_size); 152 dst->cpusetsize = kern_size; 153 } 154 curthread = _get_curthread(); 155 if ((ret = _thr_find_thread(curthread, pthread, /*include dead*/0)) != 0) 156 return (ret); 157 attr = pthread->attr; 158 if (pthread->flags & THR_FLAGS_DETACHED) 159 attr.flags |= PTHREAD_DETACHED; 160 ret = cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, TID(pthread), 161 dst->cpusetsize, dst->cpuset); 162 if (ret == -1) 163 ret = errno; 164 THR_THREAD_UNLOCK(curthread, pthread); 165 if (ret == 0) { 166 memcpy(&dst->pthread_attr_start_copy, 167 &attr.pthread_attr_start_copy, 168 offsetof(struct pthread_attr, pthread_attr_end_copy) - 169 offsetof(struct pthread_attr, pthread_attr_start_copy)); 170 } 171 return (ret); 172} 173 174__weak_reference(_pthread_attr_getdetachstate, pthread_attr_getdetachstate); 175 176int 177_pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate) 178{ 179 int ret; 180 181 /* Check for invalid arguments: */ 182 if (attr == NULL || *attr == NULL || detachstate == NULL) 183 ret = EINVAL; 184 else { 185 /* Check if the detached flag is set: */ 186 if ((*attr)->flags & PTHREAD_DETACHED) 187 /* Return detached: */ 188 *detachstate = PTHREAD_CREATE_DETACHED; 189 else 190 /* Return joinable: */ 191 *detachstate = PTHREAD_CREATE_JOINABLE; 192 ret = 0; 193 } 194 return(ret); 195} 196 197__weak_reference(_pthread_attr_getguardsize, pthread_attr_getguardsize); 198 199int 200_pthread_attr_getguardsize(const pthread_attr_t * __restrict attr, 201 size_t * __restrict guardsize) 202{ 203 int ret; 204 205 /* Check for invalid arguments: */ 206 if (attr == NULL || *attr == NULL || guardsize == NULL) 207 ret = EINVAL; 208 else { 209 /* Return the guard size: */ 210 *guardsize = (*attr)->guardsize_attr; 211 ret = 0; 212 } 213 return(ret); 214} 215 216__weak_reference(_pthread_attr_getinheritsched, pthread_attr_getinheritsched); 217 218int 219_pthread_attr_getinheritsched(const pthread_attr_t * __restrict attr, 220 int * __restrict sched_inherit) 221{ 222 int ret = 0; 223 224 if ((attr == NULL) || (*attr == NULL)) 225 ret = EINVAL; 226 else 227 *sched_inherit = (*attr)->sched_inherit; 228 229 return(ret); 230} 231 232__weak_reference(_pthread_attr_getschedparam, pthread_attr_getschedparam); 233 234int 235_pthread_attr_getschedparam(const pthread_attr_t * __restrict attr, 236 struct sched_param * __restrict param) 237{ 238 int ret = 0; 239 240 if ((attr == NULL) || (*attr == NULL) || (param == NULL)) 241 ret = EINVAL; 242 else 243 param->sched_priority = (*attr)->prio; 244 245 return(ret); 246} 247 248__weak_reference(_pthread_attr_getschedpolicy, pthread_attr_getschedpolicy); 249 250int 251_pthread_attr_getschedpolicy(const pthread_attr_t * __restrict attr, 252 int * __restrict policy) 253{ 254 int ret = 0; 255 256 if ((attr == NULL) || (*attr == NULL) || (policy == NULL)) 257 ret = EINVAL; 258 else 259 *policy = (*attr)->sched_policy; 260 261 return(ret); 262} 263 264__weak_reference(_pthread_attr_getscope, pthread_attr_getscope); 265 266int 267_pthread_attr_getscope(const pthread_attr_t * __restrict attr, 268 int * __restrict contentionscope) 269{ 270 int ret = 0; 271 272 if ((attr == NULL) || (*attr == NULL) || (contentionscope == NULL)) 273 /* Return an invalid argument: */ 274 ret = EINVAL; 275 276 else 277 *contentionscope = (*attr)->flags & PTHREAD_SCOPE_SYSTEM ? 278 PTHREAD_SCOPE_SYSTEM : PTHREAD_SCOPE_PROCESS; 279 280 return(ret); 281} 282 283__weak_reference(_pthread_attr_getstack, pthread_attr_getstack); 284 285int 286_pthread_attr_getstack(const pthread_attr_t * __restrict attr, 287 void ** __restrict stackaddr, 288 size_t * __restrict stacksize) 289{ 290 int ret; 291 292 /* Check for invalid arguments: */ 293 if (attr == NULL || *attr == NULL || stackaddr == NULL 294 || stacksize == NULL ) 295 ret = EINVAL; 296 else { 297 /* Return the stack address and size */ 298 *stackaddr = (*attr)->stackaddr_attr; 299 *stacksize = (*attr)->stacksize_attr; 300 ret = 0; 301 } 302 return(ret); 303} 304 305__weak_reference(_pthread_attr_getstackaddr, pthread_attr_getstackaddr); 306 307int 308_pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr) 309{ 310 int ret; 311 312 /* Check for invalid arguments: */ 313 if (attr == NULL || *attr == NULL || stackaddr == NULL) 314 ret = EINVAL; 315 else { 316 /* Return the stack address: */ 317 *stackaddr = (*attr)->stackaddr_attr; 318 ret = 0; 319 } 320 return(ret); 321} 322 323__weak_reference(_pthread_attr_getstacksize, pthread_attr_getstacksize); 324 325int 326_pthread_attr_getstacksize(const pthread_attr_t * __restrict attr, 327 size_t * __restrict stacksize) 328{ 329 int ret; 330 331 /* Check for invalid arguments: */ 332 if (attr == NULL || *attr == NULL || stacksize == NULL) 333 ret = EINVAL; 334 else { 335 /* Return the stack size: */ 336 *stacksize = (*attr)->stacksize_attr; 337 ret = 0; 338 } 339 return(ret); 340} 341 342__weak_reference(_pthread_attr_init, pthread_attr_init); 343 344int 345_pthread_attr_init(pthread_attr_t *attr) 346{ 347 int ret; 348 pthread_attr_t pattr; 349 350 _thr_check_init(); 351 352 /* Allocate memory for the attribute object: */ 353 if ((pattr = (pthread_attr_t) malloc(sizeof(struct pthread_attr))) == NULL) 354 /* Insufficient memory: */ 355 ret = ENOMEM; 356 else { 357 /* Initialise the attribute object with the defaults: */ 358 memcpy(pattr, &_pthread_attr_default, sizeof(struct pthread_attr)); 359 360 /* Return a pointer to the attribute object: */ 361 *attr = pattr; 362 ret = 0; 363 } 364 return(ret); 365} 366 367__weak_reference(_pthread_attr_setcreatesuspend_np, pthread_attr_setcreatesuspend_np); 368 369int 370_pthread_attr_setcreatesuspend_np(pthread_attr_t *attr) 371{ 372 int ret; 373 374 if (attr == NULL || *attr == NULL) { 375 ret = EINVAL; 376 } else { 377 (*attr)->suspend = THR_CREATE_SUSPENDED; 378 ret = 0; 379 } 380 return(ret); 381} 382 383__weak_reference(_pthread_attr_setdetachstate, pthread_attr_setdetachstate); 384 385int 386_pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate) 387{ 388 int ret; 389 390 /* Check for invalid arguments: */ 391 if (attr == NULL || *attr == NULL || 392 (detachstate != PTHREAD_CREATE_DETACHED && 393 detachstate != PTHREAD_CREATE_JOINABLE)) 394 ret = EINVAL; 395 else { 396 /* Check if detached state: */ 397 if (detachstate == PTHREAD_CREATE_DETACHED) 398 /* Set the detached flag: */ 399 (*attr)->flags |= PTHREAD_DETACHED; 400 else 401 /* Reset the detached flag: */ 402 (*attr)->flags &= ~PTHREAD_DETACHED; 403 ret = 0; 404 } 405 return(ret); 406} 407 408__weak_reference(_pthread_attr_setguardsize, pthread_attr_setguardsize); 409 410int 411_pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize) 412{ 413 int ret; 414 415 /* Check for invalid arguments. */ 416 if (attr == NULL || *attr == NULL) 417 ret = EINVAL; 418 else { 419 /* Save the stack size. */ 420 (*attr)->guardsize_attr = guardsize; 421 ret = 0; 422 } 423 return(ret); 424} 425 426__weak_reference(_pthread_attr_setinheritsched, pthread_attr_setinheritsched); 427 428int 429_pthread_attr_setinheritsched(pthread_attr_t *attr, int sched_inherit) 430{ 431 int ret = 0; 432 433 if ((attr == NULL) || (*attr == NULL)) 434 ret = EINVAL; 435 else if (sched_inherit != PTHREAD_INHERIT_SCHED && 436 sched_inherit != PTHREAD_EXPLICIT_SCHED) 437 ret = ENOTSUP; 438 else 439 (*attr)->sched_inherit = sched_inherit; 440 441 return(ret); 442} 443 444__weak_reference(_pthread_attr_setschedparam, pthread_attr_setschedparam); 445 446int 447_pthread_attr_setschedparam(pthread_attr_t * __restrict attr, 448 const struct sched_param * __restrict param) 449{ 450 int policy; 451 452 if ((attr == NULL) || (*attr == NULL)) 453 return (EINVAL); 454 455 if (param == NULL) 456 return (ENOTSUP); 457 458 policy = (*attr)->sched_policy; 459 460 if (policy == SCHED_FIFO || policy == SCHED_RR) { 461 if (param->sched_priority < _thr_priorities[policy-1].pri_min || 462 param->sched_priority > _thr_priorities[policy-1].pri_max) 463 return (ENOTSUP); 464 } else { 465 /* 466 * Ignore it for SCHED_OTHER now, patches for glib ports 467 * are wrongly using M:N thread library's internal macro 468 * THR_MIN_PRIORITY and THR_MAX_PRIORITY. 469 */ 470 } 471 472 (*attr)->prio = param->sched_priority; 473 474 return (0); 475} 476 477__weak_reference(_pthread_attr_setschedpolicy, pthread_attr_setschedpolicy); 478 479int 480_pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy) 481{ 482 int ret = 0; 483 484 if ((attr == NULL) || (*attr == NULL)) 485 ret = EINVAL; 486 else if ((policy < SCHED_FIFO) || (policy > SCHED_RR)) { 487 ret = ENOTSUP; 488 } else { 489 (*attr)->sched_policy = policy; 490 (*attr)->prio = _thr_priorities[policy-1].pri_default; 491 } 492 return(ret); 493} 494 495__weak_reference(_pthread_attr_setscope, pthread_attr_setscope); 496 497int 498_pthread_attr_setscope(pthread_attr_t *attr, int contentionscope) 499{ 500 int ret = 0; 501 502 if ((attr == NULL) || (*attr == NULL)) { 503 /* Return an invalid argument: */ 504 ret = EINVAL; 505 } else if ((contentionscope != PTHREAD_SCOPE_PROCESS) && 506 (contentionscope != PTHREAD_SCOPE_SYSTEM)) { 507 ret = EINVAL; 508 } else if (contentionscope == PTHREAD_SCOPE_SYSTEM) { 509 (*attr)->flags |= contentionscope; 510 } else { 511 (*attr)->flags &= ~PTHREAD_SCOPE_SYSTEM; 512 } 513 return (ret); 514} 515 516__weak_reference(_pthread_attr_setstack, pthread_attr_setstack); 517 518int 519_pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, 520 size_t stacksize) 521{ 522 int ret; 523 524 /* Check for invalid arguments: */ 525 if (attr == NULL || *attr == NULL || stackaddr == NULL 526 || stacksize < PTHREAD_STACK_MIN) 527 ret = EINVAL; 528 else { 529 /* Save the stack address and stack size */ 530 (*attr)->stackaddr_attr = stackaddr; 531 (*attr)->stacksize_attr = stacksize; 532 ret = 0; 533 } 534 return(ret); 535} 536 537__weak_reference(_pthread_attr_setstackaddr, pthread_attr_setstackaddr); 538 539int 540_pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr) 541{ 542 int ret; 543 544 /* Check for invalid arguments: */ 545 if (attr == NULL || *attr == NULL || stackaddr == NULL) 546 ret = EINVAL; 547 else { 548 /* Save the stack address: */ 549 (*attr)->stackaddr_attr = stackaddr; 550 ret = 0; 551 } 552 return(ret); 553} 554 555__weak_reference(_pthread_attr_setstacksize, pthread_attr_setstacksize); 556 557int 558_pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize) 559{ 560 int ret; 561 562 /* Check for invalid arguments: */ 563 if (attr == NULL || *attr == NULL || stacksize < PTHREAD_STACK_MIN) 564 ret = EINVAL; 565 else { 566 /* Save the stack size: */ 567 (*attr)->stacksize_attr = stacksize; 568 ret = 0; 569 } 570 return(ret); 571} 572 573static size_t 574_get_kern_cpuset_size(void) 575{ 576 static int kern_cpuset_size = 0; 577 578 if (kern_cpuset_size == 0) { 579 size_t len; 580 581 len = sizeof(kern_cpuset_size); 582 if (sysctlbyname("kern.sched.cpusetsize", &kern_cpuset_size, 583 &len, NULL, 0)) 584 PANIC("failed to get sysctl kern.sched.cpusetsize"); 585 } 586 587 return (kern_cpuset_size); 588} 589 590__weak_reference(_pthread_attr_setaffinity_np, pthread_attr_setaffinity_np); 591int 592_pthread_attr_setaffinity_np(pthread_attr_t *pattr, size_t cpusetsize, 593 const cpuset_t *cpusetp) 594{ 595 pthread_attr_t attr; 596 int ret; 597 598 if (pattr == NULL || (attr = (*pattr)) == NULL) 599 ret = EINVAL; 600 else { 601 if (cpusetsize == 0 || cpusetp == NULL) { 602 if (attr->cpuset != NULL) { 603 free(attr->cpuset); 604 attr->cpuset = NULL; 605 attr->cpusetsize = 0; 606 } 607 return (0); 608 } 609 size_t kern_size = _get_kern_cpuset_size(); 610 /* Kernel rejects small set, we check it here too. */ 611 if (cpusetsize < kern_size) 612 return (ERANGE); 613 if (cpusetsize > kern_size) { 614 /* Kernel checks invalid bits, we check it here too. */ 615 size_t i; 616 for (i = kern_size; i < cpusetsize; ++i) { 617 if (((const char *)cpusetp)[i]) 618 return (EINVAL); 619 } 620 } 621 if (attr->cpuset == NULL) { 622 attr->cpuset = calloc(1, kern_size); 623 if (attr->cpuset == NULL) 624 return (errno); 625 attr->cpusetsize = kern_size; 626 } 627 memcpy(attr->cpuset, cpusetp, kern_size); 628 ret = 0; 629 } 630 return (ret); 631} 632 633__weak_reference(_pthread_attr_getaffinity_np, pthread_attr_getaffinity_np); 634int 635_pthread_attr_getaffinity_np(const pthread_attr_t *pattr, size_t cpusetsize, 636 cpuset_t *cpusetp) 637{ 638 pthread_attr_t attr; 639 int ret = 0; 640 641 if (pattr == NULL || (attr = (*pattr)) == NULL) 642 ret = EINVAL; 643 else { 644 /* Kernel rejects small set, we check it here too. */ 645 size_t kern_size = _get_kern_cpuset_size(); 646 if (cpusetsize < kern_size) 647 return (ERANGE); 648 if (attr->cpuset != NULL) 649 memcpy(cpusetp, attr->cpuset, MIN(cpusetsize, 650 attr->cpusetsize)); 651 else 652 memset(cpusetp, -1, kern_size); 653 if (cpusetsize > kern_size) 654 memset(((char *)cpusetp) + kern_size, 0, 655 cpusetsize - kern_size); 656 } 657 return (ret); 658} 659