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 }