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