Print this page
8158 Want named threads API
9857 proc manpages should have LIBRARY section


   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);


  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);


 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


 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 }


   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);


  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);


 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


 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 }