1 /* $NetBSD: pthread_attr.c,v 1.22 2025/10/06 13:12:29 riastradh Exp $ */ 2 3 /*- 4 * Copyright (c) 2001, 2002, 2003, 2008 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Nathan J. Williams. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __RCSID("$NetBSD: pthread_attr.c,v 1.22 2025/10/06 13:12:29 riastradh Exp $"); 34 35 /* Need to use libc-private names for atomic operations. */ 36 #include "../../common/lib/libc/atomic/atomic_op_namespace.h" 37 38 #include <errno.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <unistd.h> 43 44 #ifndef __lint__ 45 #define pthread_attr_get_np _pthread_attr_get_np 46 #endif 47 48 #include "pthread.h" 49 #include "pthread_int.h" 50 51 __strong_alias(__libc_thr_attr_init, pthread_attr_init) 52 __strong_alias(__libc_thr_attr_setdetachstate, pthread_attr_setdetachstate) 53 __strong_alias(__libc_thr_attr_destroy, pthread_attr_destroy) 54 55 __weak_alias(pthread_attr_get_np, _pthread_attr_get_np) 56 57 static struct pthread_attr_private *pthread__attr_init_private( 58 pthread_attr_t *); 59 60 static struct pthread_attr_private * 61 pthread__attr_init_private(pthread_attr_t *attr) 62 { 63 struct pthread_attr_private *p; 64 65 if ((p = attr->pta_private) != NULL) 66 return p; 67 68 p = calloc(1, sizeof(*p)); 69 if (p != NULL) { 70 attr->pta_private = p; 71 p->ptap_policy = SCHED_OTHER; 72 p->ptap_stacksize = pthread__stacksize; 73 p->ptap_guardsize = pthread__guardsize; 74 } 75 return p; 76 } 77 78 79 int 80 pthread_attr_init(pthread_attr_t *attr) 81 { 82 83 attr->pta_magic = PT_ATTR_MAGIC; 84 attr->pta_flags = 0; 85 attr->pta_private = NULL; 86 87 return 0; 88 } 89 90 91 int 92 pthread_attr_destroy(pthread_attr_t *attr) 93 { 94 struct pthread_attr_private *p; 95 96 pthread__error(EINVAL, "Invalid attribute", 97 attr->pta_magic == PT_ATTR_MAGIC); 98 99 if ((p = attr->pta_private) != NULL) 100 free(p); 101 102 attr->pta_magic = PT_ATTR_DEAD; 103 104 return 0; 105 } 106 107 108 int 109 pthread_attr_get_np(pthread_t thread, pthread_attr_t *attr) 110 { 111 struct pthread_attr_private *p; 112 113 pthread__error(EINVAL, "Invalid attribute", 114 attr->pta_magic == PT_ATTR_MAGIC); 115 116 p = pthread__attr_init_private(attr); 117 if (p == NULL) 118 return ENOMEM; 119 120 attr->pta_flags = thread->pt_flags & 121 (PT_FLAG_DETACHED | PT_FLAG_SCOPE_SYSTEM | PT_FLAG_EXPLICIT_SCHED); 122 123 p->ptap_namearg = thread->pt_name; 124 p->ptap_stackaddr = thread->pt_stack.ss_sp; 125 p->ptap_stacksize = thread->pt_stack.ss_size; 126 p->ptap_guardsize = thread->pt_guardsize; 127 return pthread_getschedparam(thread, &p->ptap_policy, &p->ptap_sp); 128 } 129 130 131 int 132 pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate) 133 { 134 135 pthread__error(EINVAL, "Invalid attribute", 136 attr->pta_magic == PT_ATTR_MAGIC); 137 138 if (attr->pta_flags & PT_FLAG_DETACHED) 139 *detachstate = PTHREAD_CREATE_DETACHED; 140 else 141 *detachstate = PTHREAD_CREATE_JOINABLE; 142 143 return 0; 144 } 145 146 147 int 148 pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate) 149 { 150 151 pthread__error(EINVAL, "Invalid attribute", 152 attr->pta_magic == PT_ATTR_MAGIC); 153 154 switch (detachstate) { 155 case PTHREAD_CREATE_JOINABLE: 156 attr->pta_flags &= ~PT_FLAG_DETACHED; 157 break; 158 case PTHREAD_CREATE_DETACHED: 159 attr->pta_flags |= PT_FLAG_DETACHED; 160 break; 161 default: 162 return EINVAL; 163 } 164 165 return 0; 166 } 167 168 169 int 170 pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guard) 171 { 172 struct pthread_attr_private *p; 173 174 pthread__error(EINVAL, "Invalid attribute", 175 attr->pta_magic == PT_ATTR_MAGIC); 176 177 if ((p = attr->pta_private) == NULL) 178 *guard = pthread__guardsize; 179 else 180 *guard = p->ptap_guardsize; 181 182 return 0; 183 } 184 185 186 int 187 pthread_attr_setguardsize(pthread_attr_t *attr, size_t guard) 188 { 189 struct pthread_attr_private *p; 190 191 pthread__error(EINVAL, "Invalid attribute", 192 attr->pta_magic == PT_ATTR_MAGIC); 193 194 p = pthread__attr_init_private(attr); 195 if (p == NULL) 196 return ENOMEM; 197 198 p->ptap_guardsize = guard; 199 200 return 0; 201 } 202 203 204 int 205 pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inherit) 206 { 207 208 pthread__error(EINVAL, "Invalid attribute", 209 attr->pta_magic == PT_ATTR_MAGIC); 210 211 if (attr->pta_flags & PT_FLAG_EXPLICIT_SCHED) 212 *inherit = PTHREAD_EXPLICIT_SCHED; 213 else 214 *inherit = PTHREAD_INHERIT_SCHED; 215 216 return 0; 217 } 218 219 220 int 221 pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit) 222 { 223 224 pthread__error(EINVAL, "Invalid attribute", 225 attr->pta_magic == PT_ATTR_MAGIC); 226 227 switch (inherit) { 228 case PTHREAD_INHERIT_SCHED: 229 attr->pta_flags &= ~PT_FLAG_EXPLICIT_SCHED; 230 break; 231 case PTHREAD_EXPLICIT_SCHED: 232 attr->pta_flags |= PT_FLAG_EXPLICIT_SCHED; 233 break; 234 default: 235 return EINVAL; 236 } 237 238 return 0; 239 } 240 241 242 int 243 pthread_attr_getscope(const pthread_attr_t *attr, int *scope) 244 { 245 246 pthread__error(EINVAL, "Invalid attribute", 247 attr->pta_magic == PT_ATTR_MAGIC); 248 249 if (attr->pta_flags & PT_FLAG_SCOPE_SYSTEM) 250 *scope = PTHREAD_SCOPE_SYSTEM; 251 else 252 *scope = PTHREAD_SCOPE_PROCESS; 253 254 return 0; 255 } 256 257 258 int 259 pthread_attr_setscope(pthread_attr_t *attr, int scope) 260 { 261 262 pthread__error(EINVAL, "Invalid attribute", 263 attr->pta_magic == PT_ATTR_MAGIC); 264 265 switch (scope) { 266 case PTHREAD_SCOPE_PROCESS: 267 attr->pta_flags &= ~PT_FLAG_SCOPE_SYSTEM; 268 break; 269 case PTHREAD_SCOPE_SYSTEM: 270 attr->pta_flags |= PT_FLAG_SCOPE_SYSTEM; 271 break; 272 default: 273 return EINVAL; 274 } 275 276 return 0; 277 } 278 279 280 int 281 pthread_attr_setschedparam(pthread_attr_t *attr, 282 const struct sched_param *param) 283 { 284 struct pthread_attr_private *p; 285 int error; 286 287 pthread__error(EINVAL, "Invalid attribute", 288 attr->pta_magic == PT_ATTR_MAGIC); 289 290 if (param == NULL) 291 return EINVAL; 292 p = pthread__attr_init_private(attr); 293 if (p == NULL) 294 return ENOMEM; 295 error = pthread__checkpri(param->sched_priority); 296 if (error == 0) 297 p->ptap_sp = *param; 298 return error; 299 } 300 301 302 int 303 pthread_attr_getschedparam(const pthread_attr_t *attr, 304 struct sched_param *param) 305 { 306 struct pthread_attr_private *p; 307 308 pthread__error(EINVAL, "Invalid attribute", 309 attr->pta_magic == PT_ATTR_MAGIC); 310 311 if (param == NULL) 312 return EINVAL; 313 p = attr->pta_private; 314 if (p == NULL) 315 memset(param, 0, sizeof(*param)); 316 else 317 *param = p->ptap_sp; 318 return 0; 319 } 320 321 322 int 323 pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy) 324 { 325 struct pthread_attr_private *p; 326 327 pthread__error(EINVAL, "Invalid attribute", 328 attr->pta_magic == PT_ATTR_MAGIC); 329 330 switch (policy) { 331 case SCHED_OTHER: 332 case SCHED_FIFO: 333 case SCHED_RR: 334 p = pthread__attr_init_private(attr); 335 if (p == NULL) 336 return ENOMEM; 337 p->ptap_policy = policy; 338 return 0; 339 default: 340 return ENOTSUP; 341 } 342 } 343 344 345 int 346 pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy) 347 { 348 struct pthread_attr_private *p; 349 350 pthread__error(EINVAL, "Invalid attribute", 351 attr->pta_magic == PT_ATTR_MAGIC); 352 353 p = attr->pta_private; 354 if (p == NULL) { 355 *policy = SCHED_OTHER; 356 return 0; 357 } 358 *policy = p->ptap_policy; 359 return 0; 360 } 361 362 363 int 364 pthread_attr_getstack(const pthread_attr_t *attr, void **addr, size_t *size) 365 { 366 struct pthread_attr_private *p; 367 368 pthread__error(EINVAL, "Invalid attribute", 369 attr->pta_magic == PT_ATTR_MAGIC); 370 371 if ((p = attr->pta_private) == NULL) { 372 *addr = NULL; 373 *size = pthread__stacksize; 374 } else { 375 *addr = p->ptap_stackaddr; 376 *size = p->ptap_stacksize; 377 } 378 379 return 0; 380 } 381 382 383 int 384 pthread_attr_setstack(pthread_attr_t *attr, void *addr, size_t size) 385 { 386 struct pthread_attr_private *p; 387 388 pthread__error(EINVAL, "Invalid attribute", 389 attr->pta_magic == PT_ATTR_MAGIC); 390 391 p = pthread__attr_init_private(attr); 392 if (p == NULL) 393 return ENOMEM; 394 395 p->ptap_stackaddr = addr; 396 p->ptap_stacksize = size; 397 398 return 0; 399 } 400 401 402 int 403 pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *size) 404 { 405 struct pthread_attr_private *p; 406 407 pthread__error(EINVAL, "Invalid attribute", 408 attr->pta_magic == PT_ATTR_MAGIC); 409 410 if ((p = attr->pta_private) == NULL) 411 *size = pthread__stacksize; 412 else 413 *size = p->ptap_stacksize; 414 415 return 0; 416 } 417 418 419 int 420 pthread_attr_setstacksize(pthread_attr_t *attr, size_t size) 421 { 422 struct pthread_attr_private *p; 423 424 pthread__error(EINVAL, "Invalid attribute", 425 attr->pta_magic == PT_ATTR_MAGIC); 426 427 if (size < (size_t)sysconf(_SC_THREAD_STACK_MIN)) 428 return EINVAL; 429 430 p = pthread__attr_init_private(attr); 431 if (p == NULL) 432 return ENOMEM; 433 434 p->ptap_stacksize = size; 435 436 return 0; 437 } 438 439 440 int 441 pthread_attr_getstackaddr(const pthread_attr_t *attr, void **addr) 442 { 443 struct pthread_attr_private *p; 444 445 pthread__error(EINVAL, "Invalid attribute", 446 attr->pta_magic == PT_ATTR_MAGIC); 447 448 if ((p = attr->pta_private) == NULL) 449 *addr = NULL; 450 else 451 *addr = p->ptap_stackaddr; 452 453 return 0; 454 } 455 456 457 int 458 pthread_attr_setstackaddr(pthread_attr_t *attr, void *addr) 459 { 460 struct pthread_attr_private *p; 461 462 pthread__error(EINVAL, "Invalid attribute", 463 attr->pta_magic == PT_ATTR_MAGIC); 464 465 p = pthread__attr_init_private(attr); 466 if (p == NULL) 467 return ENOMEM; 468 469 p->ptap_stackaddr = addr; 470 471 return 0; 472 } 473 474 475 int 476 pthread_attr_getname_np(const pthread_attr_t *attr, char *name, size_t len, 477 void **argp) 478 { 479 struct pthread_attr_private *p; 480 481 pthread__error(EINVAL, "Invalid attribute", 482 attr->pta_magic == PT_ATTR_MAGIC); 483 484 if ((p = attr->pta_private) == NULL) { 485 name[0] = '\0'; 486 if (argp != NULL) 487 *argp = NULL; 488 } else { 489 strlcpy(name, p->ptap_name, len); 490 if (argp != NULL) 491 *argp = p->ptap_namearg; 492 } 493 494 return 0; 495 } 496 497 498 int 499 pthread_attr_setname_np(pthread_attr_t *attr, const char *name, void *arg) 500 { 501 struct pthread_attr_private *p; 502 int namelen; 503 504 pthread__error(EINVAL, "Invalid attribute", 505 attr->pta_magic == PT_ATTR_MAGIC); 506 507 p = pthread__attr_init_private(attr); 508 if (p == NULL) 509 return ENOMEM; 510 511 namelen = snprintf(p->ptap_name, PTHREAD_MAX_NAMELEN_NP, name, arg); 512 if (namelen >= PTHREAD_MAX_NAMELEN_NP) { 513 p->ptap_name[0] = '\0'; 514 return EINVAL; 515 } 516 p->ptap_namearg = arg; 517 518 return 0; 519 } 520 521 int 522 pthread_attr_setcreatesuspend_np(pthread_attr_t *attr) 523 { 524 525 pthread__error(EINVAL, "Invalid attribute", 526 attr->pta_magic == PT_ATTR_MAGIC); 527 528 attr->pta_flags |= PT_FLAG_SUSPENDED; 529 return 0; 530 } 531 532 int 533 pthread_getattr_np(pthread_t thread, pthread_attr_t *attr) 534 { 535 int error; 536 537 if ((error = pthread_attr_init(attr)) != 0) 538 return error; 539 if ((error = pthread_attr_get_np(thread, attr)) != 0) { 540 (void)pthread_attr_destroy(attr); 541 return error; 542 } 543 return 0; 544 } 545