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