1 /* $NetBSD: pthread_attr.c,v 1.21 2022/04/10 10:38:33 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.21 2022/04/10 10:38:33 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 __weak_alias(pthread_attr_get_np, _pthread_attr_get_np) 52 53 static struct pthread_attr_private *pthread__attr_init_private( 54 pthread_attr_t *); 55 56 static struct pthread_attr_private * 57 pthread__attr_init_private(pthread_attr_t *attr) 58 { 59 struct pthread_attr_private *p; 60 61 if ((p = attr->pta_private) != NULL) 62 return p; 63 64 p = calloc(1, sizeof(*p)); 65 if (p != NULL) { 66 attr->pta_private = p; 67 p->ptap_policy = SCHED_OTHER; 68 p->ptap_stacksize = pthread__stacksize; 69 p->ptap_guardsize = pthread__guardsize; 70 } 71 return p; 72 } 73 74 75 int 76 pthread_attr_init(pthread_attr_t *attr) 77 { 78 79 attr->pta_magic = PT_ATTR_MAGIC; 80 attr->pta_flags = 0; 81 attr->pta_private = NULL; 82 83 return 0; 84 } 85 86 87 int 88 pthread_attr_destroy(pthread_attr_t *attr) 89 { 90 struct pthread_attr_private *p; 91 92 pthread__error(EINVAL, "Invalid attribute", 93 attr->pta_magic == PT_ATTR_MAGIC); 94 95 if ((p = attr->pta_private) != NULL) 96 free(p); 97 98 attr->pta_magic = PT_ATTR_DEAD; 99 100 return 0; 101 } 102 103 104 int 105 pthread_attr_get_np(pthread_t thread, pthread_attr_t *attr) 106 { 107 struct pthread_attr_private *p; 108 109 pthread__error(EINVAL, "Invalid attribute", 110 attr->pta_magic == PT_ATTR_MAGIC); 111 112 p = pthread__attr_init_private(attr); 113 if (p == NULL) 114 return ENOMEM; 115 116 attr->pta_flags = thread->pt_flags & 117 (PT_FLAG_DETACHED | PT_FLAG_SCOPE_SYSTEM | PT_FLAG_EXPLICIT_SCHED); 118 119 p->ptap_namearg = thread->pt_name; 120 p->ptap_stackaddr = thread->pt_stack.ss_sp; 121 p->ptap_stacksize = thread->pt_stack.ss_size; 122 p->ptap_guardsize = thread->pt_guardsize; 123 return pthread_getschedparam(thread, &p->ptap_policy, &p->ptap_sp); 124 } 125 126 127 int 128 pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate) 129 { 130 131 pthread__error(EINVAL, "Invalid attribute", 132 attr->pta_magic == PT_ATTR_MAGIC); 133 134 if (attr->pta_flags & PT_FLAG_DETACHED) 135 *detachstate = PTHREAD_CREATE_DETACHED; 136 else 137 *detachstate = PTHREAD_CREATE_JOINABLE; 138 139 return 0; 140 } 141 142 143 int 144 pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate) 145 { 146 147 pthread__error(EINVAL, "Invalid attribute", 148 attr->pta_magic == PT_ATTR_MAGIC); 149 150 switch (detachstate) { 151 case PTHREAD_CREATE_JOINABLE: 152 attr->pta_flags &= ~PT_FLAG_DETACHED; 153 break; 154 case PTHREAD_CREATE_DETACHED: 155 attr->pta_flags |= PT_FLAG_DETACHED; 156 break; 157 default: 158 return EINVAL; 159 } 160 161 return 0; 162 } 163 164 165 int 166 pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guard) 167 { 168 struct pthread_attr_private *p; 169 170 pthread__error(EINVAL, "Invalid attribute", 171 attr->pta_magic == PT_ATTR_MAGIC); 172 173 if ((p = attr->pta_private) == NULL) 174 *guard = pthread__guardsize; 175 else 176 *guard = p->ptap_guardsize; 177 178 return 0; 179 } 180 181 182 int 183 pthread_attr_setguardsize(pthread_attr_t *attr, size_t guard) 184 { 185 struct pthread_attr_private *p; 186 187 pthread__error(EINVAL, "Invalid attribute", 188 attr->pta_magic == PT_ATTR_MAGIC); 189 190 p = pthread__attr_init_private(attr); 191 if (p == NULL) 192 return ENOMEM; 193 194 p->ptap_guardsize = guard; 195 196 return 0; 197 } 198 199 200 int 201 pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inherit) 202 { 203 204 pthread__error(EINVAL, "Invalid attribute", 205 attr->pta_magic == PT_ATTR_MAGIC); 206 207 if (attr->pta_flags & PT_FLAG_EXPLICIT_SCHED) 208 *inherit = PTHREAD_EXPLICIT_SCHED; 209 else 210 *inherit = PTHREAD_INHERIT_SCHED; 211 212 return 0; 213 } 214 215 216 int 217 pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit) 218 { 219 220 pthread__error(EINVAL, "Invalid attribute", 221 attr->pta_magic == PT_ATTR_MAGIC); 222 223 switch (inherit) { 224 case PTHREAD_INHERIT_SCHED: 225 attr->pta_flags &= ~PT_FLAG_EXPLICIT_SCHED; 226 break; 227 case PTHREAD_EXPLICIT_SCHED: 228 attr->pta_flags |= PT_FLAG_EXPLICIT_SCHED; 229 break; 230 default: 231 return EINVAL; 232 } 233 234 return 0; 235 } 236 237 238 int 239 pthread_attr_getscope(const pthread_attr_t *attr, int *scope) 240 { 241 242 pthread__error(EINVAL, "Invalid attribute", 243 attr->pta_magic == PT_ATTR_MAGIC); 244 245 if (attr->pta_flags & PT_FLAG_SCOPE_SYSTEM) 246 *scope = PTHREAD_SCOPE_SYSTEM; 247 else 248 *scope = PTHREAD_SCOPE_PROCESS; 249 250 return 0; 251 } 252 253 254 int 255 pthread_attr_setscope(pthread_attr_t *attr, int scope) 256 { 257 258 pthread__error(EINVAL, "Invalid attribute", 259 attr->pta_magic == PT_ATTR_MAGIC); 260 261 switch (scope) { 262 case PTHREAD_SCOPE_PROCESS: 263 attr->pta_flags &= ~PT_FLAG_SCOPE_SYSTEM; 264 break; 265 case PTHREAD_SCOPE_SYSTEM: 266 attr->pta_flags |= PT_FLAG_SCOPE_SYSTEM; 267 break; 268 default: 269 return EINVAL; 270 } 271 272 return 0; 273 } 274 275 276 int 277 pthread_attr_setschedparam(pthread_attr_t *attr, 278 const struct sched_param *param) 279 { 280 struct pthread_attr_private *p; 281 int error; 282 283 pthread__error(EINVAL, "Invalid attribute", 284 attr->pta_magic == PT_ATTR_MAGIC); 285 286 if (param == NULL) 287 return EINVAL; 288 p = pthread__attr_init_private(attr); 289 if (p == NULL) 290 return ENOMEM; 291 error = pthread__checkpri(param->sched_priority); 292 if (error == 0) 293 p->ptap_sp = *param; 294 return error; 295 } 296 297 298 int 299 pthread_attr_getschedparam(const pthread_attr_t *attr, 300 struct sched_param *param) 301 { 302 struct pthread_attr_private *p; 303 304 pthread__error(EINVAL, "Invalid attribute", 305 attr->pta_magic == PT_ATTR_MAGIC); 306 307 if (param == NULL) 308 return EINVAL; 309 p = attr->pta_private; 310 if (p == NULL) 311 memset(param, 0, sizeof(*param)); 312 else 313 *param = p->ptap_sp; 314 return 0; 315 } 316 317 318 int 319 pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy) 320 { 321 struct pthread_attr_private *p; 322 323 pthread__error(EINVAL, "Invalid attribute", 324 attr->pta_magic == PT_ATTR_MAGIC); 325 326 switch (policy) { 327 case SCHED_OTHER: 328 case SCHED_FIFO: 329 case SCHED_RR: 330 p = pthread__attr_init_private(attr); 331 if (p == NULL) 332 return ENOMEM; 333 p->ptap_policy = policy; 334 return 0; 335 default: 336 return ENOTSUP; 337 } 338 } 339 340 341 int 342 pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy) 343 { 344 struct pthread_attr_private *p; 345 346 pthread__error(EINVAL, "Invalid attribute", 347 attr->pta_magic == PT_ATTR_MAGIC); 348 349 p = attr->pta_private; 350 if (p == NULL) { 351 *policy = SCHED_OTHER; 352 return 0; 353 } 354 *policy = p->ptap_policy; 355 return 0; 356 } 357 358 359 int 360 pthread_attr_getstack(const pthread_attr_t *attr, void **addr, size_t *size) 361 { 362 struct pthread_attr_private *p; 363 364 pthread__error(EINVAL, "Invalid attribute", 365 attr->pta_magic == PT_ATTR_MAGIC); 366 367 if ((p = attr->pta_private) == NULL) { 368 *addr = NULL; 369 *size = pthread__stacksize; 370 } else { 371 *addr = p->ptap_stackaddr; 372 *size = p->ptap_stacksize; 373 } 374 375 return 0; 376 } 377 378 379 int 380 pthread_attr_setstack(pthread_attr_t *attr, void *addr, size_t size) 381 { 382 struct pthread_attr_private *p; 383 384 pthread__error(EINVAL, "Invalid attribute", 385 attr->pta_magic == PT_ATTR_MAGIC); 386 387 p = pthread__attr_init_private(attr); 388 if (p == NULL) 389 return ENOMEM; 390 391 p->ptap_stackaddr = addr; 392 p->ptap_stacksize = size; 393 394 return 0; 395 } 396 397 398 int 399 pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *size) 400 { 401 struct pthread_attr_private *p; 402 403 pthread__error(EINVAL, "Invalid attribute", 404 attr->pta_magic == PT_ATTR_MAGIC); 405 406 if ((p = attr->pta_private) == NULL) 407 *size = pthread__stacksize; 408 else 409 *size = p->ptap_stacksize; 410 411 return 0; 412 } 413 414 415 int 416 pthread_attr_setstacksize(pthread_attr_t *attr, size_t size) 417 { 418 struct pthread_attr_private *p; 419 420 pthread__error(EINVAL, "Invalid attribute", 421 attr->pta_magic == PT_ATTR_MAGIC); 422 423 if (size < (size_t)sysconf(_SC_THREAD_STACK_MIN)) 424 return EINVAL; 425 426 p = pthread__attr_init_private(attr); 427 if (p == NULL) 428 return ENOMEM; 429 430 p->ptap_stacksize = size; 431 432 return 0; 433 } 434 435 436 int 437 pthread_attr_getstackaddr(const pthread_attr_t *attr, void **addr) 438 { 439 struct pthread_attr_private *p; 440 441 pthread__error(EINVAL, "Invalid attribute", 442 attr->pta_magic == PT_ATTR_MAGIC); 443 444 if ((p = attr->pta_private) == NULL) 445 *addr = NULL; 446 else 447 *addr = p->ptap_stackaddr; 448 449 return 0; 450 } 451 452 453 int 454 pthread_attr_setstackaddr(pthread_attr_t *attr, void *addr) 455 { 456 struct pthread_attr_private *p; 457 458 pthread__error(EINVAL, "Invalid attribute", 459 attr->pta_magic == PT_ATTR_MAGIC); 460 461 p = pthread__attr_init_private(attr); 462 if (p == NULL) 463 return ENOMEM; 464 465 p->ptap_stackaddr = addr; 466 467 return 0; 468 } 469 470 471 int 472 pthread_attr_getname_np(const pthread_attr_t *attr, char *name, size_t len, 473 void **argp) 474 { 475 struct pthread_attr_private *p; 476 477 pthread__error(EINVAL, "Invalid attribute", 478 attr->pta_magic == PT_ATTR_MAGIC); 479 480 if ((p = attr->pta_private) == NULL) { 481 name[0] = '\0'; 482 if (argp != NULL) 483 *argp = NULL; 484 } else { 485 strlcpy(name, p->ptap_name, len); 486 if (argp != NULL) 487 *argp = p->ptap_namearg; 488 } 489 490 return 0; 491 } 492 493 494 int 495 pthread_attr_setname_np(pthread_attr_t *attr, const char *name, void *arg) 496 { 497 struct pthread_attr_private *p; 498 int namelen; 499 500 pthread__error(EINVAL, "Invalid attribute", 501 attr->pta_magic == PT_ATTR_MAGIC); 502 503 p = pthread__attr_init_private(attr); 504 if (p == NULL) 505 return ENOMEM; 506 507 namelen = snprintf(p->ptap_name, PTHREAD_MAX_NAMELEN_NP, name, arg); 508 if (namelen >= PTHREAD_MAX_NAMELEN_NP) { 509 p->ptap_name[0] = '\0'; 510 return EINVAL; 511 } 512 p->ptap_namearg = arg; 513 514 return 0; 515 } 516 517 int 518 pthread_attr_setcreatesuspend_np(pthread_attr_t *attr) 519 { 520 521 pthread__error(EINVAL, "Invalid attribute", 522 attr->pta_magic == PT_ATTR_MAGIC); 523 524 attr->pta_flags |= PT_FLAG_SUSPENDED; 525 return 0; 526 } 527 528 int 529 pthread_getattr_np(pthread_t thread, pthread_attr_t *attr) 530 { 531 int error; 532 533 if ((error = pthread_attr_init(attr)) != 0) 534 return error; 535 if ((error = pthread_attr_get_np(thread, attr)) != 0) { 536 (void)pthread_attr_destroy(attr); 537 return error; 538 } 539 return 0; 540 } 541