1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Copyright 2018, Joyent, Inc. 29 */ 30 31 #include "lint.h" 32 #include "thr_uberdata.h" 33 #include <sys/ctype.h> 34 #include <strings.h> 35 #include <sched.h> 36 37 /* 38 * Default attribute object for pthread_create() with NULL attr pointer. 39 * Note that the 'guardsize' field is initialized on the first call. 40 */ 41 const thrattr_t * 42 def_thrattr(void) 43 { 44 static thrattr_t thrattr = { 45 0, /* stksize */ 46 NULL, /* stkaddr */ 47 PTHREAD_CREATE_JOINABLE, /* detachstate */ 48 PTHREAD_CREATE_NONDAEMON_NP, /* daemonstate */ 49 PTHREAD_SCOPE_PROCESS, /* scope */ 50 0, /* prio */ 51 SCHED_OTHER, /* policy */ 52 PTHREAD_INHERIT_SCHED, /* inherit */ 53 0, /* guardsize */ 54 { 0 } /* name */ 55 }; 56 if (thrattr.guardsize == 0) 57 thrattr.guardsize = _sysconf(_SC_PAGESIZE); 58 return (&thrattr); 59 } 60 61 /* 62 * pthread_attr_init: allocates the attribute object and initializes it 63 * with the default values. 64 */ 65 #pragma weak _pthread_attr_init = pthread_attr_init 66 int 67 pthread_attr_init(pthread_attr_t *attr) 68 { 69 thrattr_t *ap; 70 71 if ((ap = lmalloc(sizeof (thrattr_t))) != NULL) { 72 *ap = *def_thrattr(); 73 attr->__pthread_attrp = ap; 74 return (0); 75 } 76 return (ENOMEM); 77 } 78 79 /* 80 * pthread_attr_destroy: frees the attribute object and invalidates it 81 * with NULL value. 82 */ 83 int 84 pthread_attr_destroy(pthread_attr_t *attr) 85 { 86 if (attr == NULL || attr->__pthread_attrp == NULL) 87 return (EINVAL); 88 lfree(attr->__pthread_attrp, sizeof (thrattr_t)); 89 attr->__pthread_attrp = NULL; 90 return (0); 91 } 92 93 /* 94 * pthread_attr_clone: make a copy of a pthread_attr_t. 95 */ 96 int 97 pthread_attr_clone(pthread_attr_t *attr, const pthread_attr_t *old_attr) 98 { 99 thrattr_t *ap; 100 const thrattr_t *old_ap = 101 old_attr ? old_attr->__pthread_attrp : def_thrattr(); 102 103 if (old_ap == NULL) 104 return (EINVAL); 105 if ((ap = lmalloc(sizeof (thrattr_t))) == NULL) 106 return (ENOMEM); 107 *ap = *old_ap; 108 attr->__pthread_attrp = ap; 109 return (0); 110 } 111 112 /* 113 * pthread_attr_equal: compare two pthread_attr_t's, return 1 if equal. 114 * A NULL pthread_attr_t pointer implies default attributes. 115 * This is a consolidation-private interface, for librt. 116 */ 117 int 118 pthread_attr_equal(const pthread_attr_t *attr1, const pthread_attr_t *attr2) 119 { 120 const thrattr_t *ap1 = attr1 ? attr1->__pthread_attrp : def_thrattr(); 121 const thrattr_t *ap2 = attr2 ? attr2->__pthread_attrp : def_thrattr(); 122 123 if (ap1 == NULL || ap2 == NULL) 124 return (0); 125 return (ap1 == ap2 || memcmp(ap1, ap2, sizeof (thrattr_t)) == 0); 126 } 127 128 /* 129 * pthread_attr_setstacksize: sets the user stack size, minimum should 130 * be PTHREAD_STACK_MIN (MINSTACK). 131 * This is equivalent to stksize argument in thr_create(). 132 */ 133 int 134 pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize) 135 { 136 thrattr_t *ap; 137 138 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL && 139 stacksize >= MINSTACK) { 140 ap->stksize = stacksize; 141 return (0); 142 } 143 return (EINVAL); 144 } 145 146 /* 147 * pthread_attr_getstacksize: gets the user stack size. 148 */ 149 #pragma weak _pthread_attr_getstacksize = pthread_attr_getstacksize 150 int 151 pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize) 152 { 153 thrattr_t *ap; 154 155 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL && 156 stacksize != NULL) { 157 *stacksize = ap->stksize; 158 return (0); 159 } 160 return (EINVAL); 161 } 162 163 /* 164 * pthread_attr_setstackaddr: sets the user stack addr. 165 * This is equivalent to stkaddr argument in thr_create(). 166 */ 167 int 168 pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr) 169 { 170 thrattr_t *ap; 171 172 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL) { 173 ap->stkaddr = stackaddr; 174 return (0); 175 } 176 return (EINVAL); 177 } 178 179 /* 180 * pthread_attr_getstackaddr: gets the user stack addr. 181 */ 182 #pragma weak _pthread_attr_getstackaddr = pthread_attr_getstackaddr 183 int 184 pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr) 185 { 186 thrattr_t *ap; 187 188 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL && 189 stackaddr != NULL) { 190 *stackaddr = ap->stkaddr; 191 return (0); 192 } 193 return (EINVAL); 194 } 195 196 /* 197 * pthread_attr_setdetachstate: sets the detach state to DETACHED or JOINABLE. 198 * PTHREAD_CREATE_DETACHED is equivalent to thr_create(THR_DETACHED). 199 */ 200 int 201 pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate) 202 { 203 thrattr_t *ap; 204 205 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL && 206 (detachstate == PTHREAD_CREATE_DETACHED || 207 detachstate == PTHREAD_CREATE_JOINABLE)) { 208 ap->detachstate = detachstate; 209 return (0); 210 } 211 return (EINVAL); 212 } 213 214 /* 215 * pthread_attr_getdetachstate: gets the detach state. 216 */ 217 #pragma weak _pthread_attr_getdetachstate = pthread_attr_getdetachstate 218 int 219 pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate) 220 { 221 thrattr_t *ap; 222 223 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL && 224 detachstate != NULL) { 225 *detachstate = ap->detachstate; 226 return (0); 227 } 228 return (EINVAL); 229 } 230 231 /* 232 * pthread_attr_setdaemonstate_np: sets the daemon state to DAEMON or NONDAEMON. 233 * PTHREAD_CREATE_DAEMON is equivalent to thr_create(THR_DAEMON). 234 * For now, this is a private interface in libc. 235 */ 236 int 237 pthread_attr_setdaemonstate_np(pthread_attr_t *attr, int daemonstate) 238 { 239 thrattr_t *ap; 240 241 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL && 242 (daemonstate == PTHREAD_CREATE_DAEMON_NP || 243 daemonstate == PTHREAD_CREATE_NONDAEMON_NP)) { 244 ap->daemonstate = daemonstate; 245 return (0); 246 } 247 return (EINVAL); 248 } 249 250 /* 251 * pthread_attr_getdaemonstate_np: gets the daemon state. 252 * For now, this is a private interface in libc, but it is exposed in the 253 * mapfile for the purposes of testing only. 254 */ 255 int 256 pthread_attr_getdaemonstate_np(const pthread_attr_t *attr, int *daemonstate) 257 { 258 thrattr_t *ap; 259 260 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL && 261 daemonstate != NULL) { 262 *daemonstate = ap->daemonstate; 263 return (0); 264 } 265 return (EINVAL); 266 } 267 268 /* 269 * pthread_attr_setscope: sets the scope to SYSTEM or PROCESS. 270 * This is equivalent to setting THR_BOUND flag in thr_create(). 271 */ 272 int 273 pthread_attr_setscope(pthread_attr_t *attr, int scope) 274 { 275 thrattr_t *ap; 276 277 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL && 278 (scope == PTHREAD_SCOPE_SYSTEM || 279 scope == PTHREAD_SCOPE_PROCESS)) { 280 ap->scope = scope; 281 return (0); 282 } 283 return (EINVAL); 284 } 285 286 /* 287 * pthread_attr_getscope: gets the scheduling scope. 288 */ 289 #pragma weak _pthread_attr_getscope = pthread_attr_getscope 290 int 291 pthread_attr_getscope(const pthread_attr_t *attr, int *scope) 292 { 293 thrattr_t *ap; 294 295 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL && 296 scope != NULL) { 297 *scope = ap->scope; 298 return (0); 299 } 300 return (EINVAL); 301 } 302 303 /* 304 * pthread_attr_setinheritsched: sets the scheduling parameters to be 305 * EXPLICIT or INHERITED from parent thread. 306 */ 307 int 308 pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit) 309 { 310 thrattr_t *ap; 311 312 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL && 313 (inherit == PTHREAD_EXPLICIT_SCHED || 314 inherit == PTHREAD_INHERIT_SCHED)) { 315 ap->inherit = inherit; 316 return (0); 317 } 318 return (EINVAL); 319 } 320 321 /* 322 * pthread_attr_getinheritsched: gets the scheduling inheritance. 323 */ 324 #pragma weak _pthread_attr_getinheritsched = pthread_attr_getinheritsched 325 int 326 pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inherit) 327 { 328 thrattr_t *ap; 329 330 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL && 331 inherit != NULL) { 332 *inherit = ap->inherit; 333 return (0); 334 } 335 return (EINVAL); 336 } 337 338 /* 339 * pthread_attr_setschedpolicy: sets the scheduling policy. 340 */ 341 int 342 pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy) 343 { 344 thrattr_t *ap; 345 346 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL && 347 policy != SCHED_SYS && get_info_by_policy(policy) != NULL) { 348 ap->policy = policy; 349 return (0); 350 } 351 return (EINVAL); 352 } 353 354 /* 355 * pthread_attr_getpolicy: gets the scheduling policy. 356 */ 357 #pragma weak _pthread_attr_getschedpolicy = pthread_attr_getschedpolicy 358 int 359 pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy) 360 { 361 thrattr_t *ap; 362 363 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL && 364 policy != NULL) { 365 *policy = ap->policy; 366 return (0); 367 } 368 return (EINVAL); 369 } 370 371 /* 372 * pthread_attr_setschedparam: sets the scheduling parameters. 373 * Currently, we support priority only. 374 */ 375 int 376 pthread_attr_setschedparam(pthread_attr_t *attr, 377 const struct sched_param *param) 378 { 379 thrattr_t *ap; 380 381 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL && 382 param != NULL) { 383 ap->prio = param->sched_priority; 384 return (0); 385 } 386 return (EINVAL); 387 } 388 389 /* 390 * pthread_attr_getschedparam: gets the scheduling parameters. 391 * Currently, only priority is defined as sched parameter. 392 */ 393 #pragma weak _pthread_attr_getschedparam = pthread_attr_getschedparam 394 int 395 pthread_attr_getschedparam(const pthread_attr_t *attr, 396 struct sched_param *param) 397 { 398 thrattr_t *ap; 399 400 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL && 401 param != NULL) { 402 param->sched_priority = ap->prio; 403 return (0); 404 } 405 return (EINVAL); 406 } 407 408 /* 409 * UNIX98 410 * pthread_attr_setguardsize: sets the guardsize 411 */ 412 int 413 pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize) 414 { 415 thrattr_t *ap; 416 417 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL) { 418 ap->guardsize = guardsize; 419 return (0); 420 } 421 return (EINVAL); 422 } 423 424 /* 425 * UNIX98 426 * pthread_attr_getguardsize: gets the guardsize 427 */ 428 int 429 pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize) 430 { 431 thrattr_t *ap; 432 433 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL && 434 guardsize != NULL) { 435 *guardsize = ap->guardsize; 436 return (0); 437 } 438 return (EINVAL); 439 } 440 441 /* 442 * pthread_attr_setstack: sets the user stack addr and stack size. 443 * This is equivalent to the stack_base and stack_size arguments 444 * to thr_create(). 445 */ 446 int 447 pthread_attr_setstack(pthread_attr_t *attr, 448 void *stackaddr, size_t stacksize) 449 { 450 thrattr_t *ap; 451 452 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL && 453 stacksize >= MINSTACK) { 454 ap->stkaddr = stackaddr; 455 ap->stksize = stacksize; 456 if (stackaddr != NULL && 457 setup_top_frame(stackaddr, stacksize, NULL) == NULL) 458 return (EACCES); 459 return (0); 460 } 461 return (EINVAL); 462 } 463 464 /* 465 * pthread_attr_getstack: gets the user stack addr and stack size. 466 */ 467 int 468 pthread_attr_getstack(const pthread_attr_t *attr, 469 void **stackaddr, size_t *stacksize) 470 { 471 thrattr_t *ap; 472 473 if (attr != NULL && (ap = attr->__pthread_attrp) != NULL && 474 stackaddr != NULL && stacksize != NULL) { 475 *stackaddr = ap->stkaddr; 476 *stacksize = ap->stksize; 477 return (0); 478 } 479 return (EINVAL); 480 } 481 482 int 483 pthread_attr_setname_np(pthread_attr_t *attr, const char *name) 484 { 485 thrattr_t *ap; 486 487 if (attr == NULL || (ap = attr->__pthread_attrp) == NULL) 488 return (EINVAL); 489 490 if (name == NULL) { 491 bzero(ap->name, sizeof (ap->name)); 492 return (0); 493 } 494 495 if (strlen(name) >= sizeof (ap->name)) 496 return (ERANGE); 497 498 /* 499 * We really want the ASCII version of isprint() here... 500 */ 501 for (size_t i = 0; name[i] != '\0'; i++) { 502 if (!ISPRINT(name[i])) 503 return (EINVAL); 504 } 505 506 /* 507 * not having garbage after the end of the string simplifies attr 508 * comparison 509 */ 510 bzero(ap->name, sizeof (ap->name)); 511 (void) strlcpy(ap->name, name, sizeof (ap->name)); 512 return (0); 513 } 514 515 int 516 pthread_attr_getname_np(pthread_attr_t *attr, char *buf, size_t len) 517 { 518 thrattr_t *ap; 519 520 if (buf == NULL || attr == NULL || 521 (ap = attr->__pthread_attrp) == NULL) 522 return (EINVAL); 523 524 if (strlcpy(buf, ap->name, len) > len) 525 return (ERANGE); 526 return (0); 527 } 528 529 /* 530 * This function is a common BSD extension to pthread which is used to obtain 531 * the attributes of a thread that might have changed after its creation, for 532 * example, it's stack address. 533 * 534 * Note, there is no setattr analogue, nor do we desire to add one at this time. 535 * Similarly there is no native threads API analogue (nor should we add one for 536 * C11). 537 * 538 * The astute reader may note that there is a GNU version of this called 539 * pthread_getattr_np(). The two functions are similar, but subtley different in 540 * a rather important way. While the pthread_attr_get_np() expects to be given 541 * a pthread_attr_t that has had pthread_attr_init() called on in, 542 * pthread_getattr_np() does not. However, on GNU systems, where the function 543 * originates, the pthread_attr_t is not opaque and thus it is entirely safe to 544 * both call pthread_attr_init() and then call pthread_getattr_np() on the same 545 * attributes object. On illumos, since the pthread_attr_t is opaque, that would 546 * be a memory leak. As such, we don't provide it. 547 */ 548 int 549 pthread_attr_get_np(pthread_t tid, pthread_attr_t *attr) 550 { 551 int ret; 552 ulwp_t *self = curthread; 553 uberdata_t *udp = self->ul_uberdata; 554 ulwp_t *target = NULL; 555 thrattr_t *ap; 556 557 /* 558 * To ensure that information about the target thread does not change or 559 * disappear while we're trying to interrogate it, we grab the uwlp 560 * lock. 561 */ 562 if (self->ul_lwpid == tid) { 563 ulwp_lock(self, udp); 564 target = self; 565 } else { 566 target = find_lwp(tid); 567 if (target == NULL) 568 return (ESRCH); 569 } 570 571 if (attr == NULL) { 572 ret = EINVAL; 573 goto out; 574 } 575 576 if ((ap = attr->__pthread_attrp) == NULL) { 577 ret = EINVAL; 578 goto out; 579 } 580 581 ap->stksize = target->ul_stksiz; 582 ap->stkaddr = target->ul_stk; 583 if (target->ul_usropts & THR_DETACHED) { 584 ap->detachstate = PTHREAD_CREATE_DETACHED; 585 } else { 586 ap->detachstate = PTHREAD_CREATE_JOINABLE; 587 } 588 589 if (target->ul_usropts & THR_DAEMON) { 590 ap->daemonstate = PTHREAD_CREATE_DAEMON_NP; 591 } else { 592 ap->daemonstate = PTHREAD_CREATE_NONDAEMON_NP; 593 } 594 595 if (target->ul_usropts & THR_BOUND) { 596 ap->scope = PTHREAD_SCOPE_SYSTEM; 597 } else { 598 ap->scope = PTHREAD_SCOPE_PROCESS; 599 } 600 ap->prio = target->ul_pri; 601 ap->policy = target->ul_policy; 602 ap->inherit = target->ul_ptinherit; 603 ap->guardsize = target->ul_guardsize; 604 (void) pthread_getname_np(tid, ap->name, sizeof (ap->name)); 605 606 ret = 0; 607 out: 608 ulwp_unlock(target, udp); 609 return (ret); 610 } 611