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