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 53static struct pthread_attr_private *pthread__attr_init_private( 54 pthread_attr_t *); 55 56static struct pthread_attr_private * 57pthread__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 75int 76pthread_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 87int 88pthread_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 104int 105pthread_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 127int 128pthread_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 143int 144pthread_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 165int 166pthread_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 182int 183pthread_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 200int 201pthread_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 216int 217pthread_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 238int 239pthread_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 254int 255pthread_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 276int 277pthread_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 298int 299pthread_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 318int 319pthread_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 341int 342pthread_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 359int 360pthread_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 379int 380pthread_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 398int 399pthread_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 415int 416pthread_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 436int 437pthread_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 453int 454pthread_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 471int 472pthread_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 494int 495pthread_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 517int 518pthread_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 528int 529pthread_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