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