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