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