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