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