Home | History | Annotate | Download | only in threads
      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 #include "lint.h"
     28 #include "thr_uberdata.h"
     29 #include <sched.h>
     30 
     31 /*
     32  * Default attribute object for pthread_create() with NULL attr pointer.
     33  * Note that the 'guardsize' field is initialized on the first call.
     34  */
     35 const thrattr_t *
     36 def_thrattr(void)
     37 {
     38 	static thrattr_t thrattr = {
     39 		0,				/* stksize */
     40 		NULL,				/* stkaddr */
     41 		PTHREAD_CREATE_JOINABLE,	/* detachstate */
     42 		PTHREAD_CREATE_NONDAEMON_NP,	/* daemonstate */
     43 		PTHREAD_SCOPE_PROCESS,		/* scope */
     44 		0,				/* prio */
     45 		SCHED_OTHER,			/* policy */
     46 		PTHREAD_INHERIT_SCHED,		/* inherit */
     47 		0				/* guardsize */
     48 	};
     49 	if (thrattr.guardsize == 0)
     50 		thrattr.guardsize = _sysconf(_SC_PAGESIZE);
     51 	return (&thrattr);
     52 }
     53 
     54 /*
     55  * pthread_attr_init: allocates the attribute object and initializes it
     56  * with the default values.
     57  */
     58 #pragma weak _pthread_attr_init = pthread_attr_init
     59 int
     60 pthread_attr_init(pthread_attr_t *attr)
     61 {
     62 	thrattr_t *ap;
     63 
     64 	if ((ap = lmalloc(sizeof (thrattr_t))) != NULL) {
     65 		*ap = *def_thrattr();
     66 		attr->__pthread_attrp = ap;
     67 		return (0);
     68 	}
     69 	return (ENOMEM);
     70 }
     71 
     72 /*
     73  * pthread_attr_destroy: frees the attribute object and invalidates it
     74  * with NULL value.
     75  */
     76 int
     77 pthread_attr_destroy(pthread_attr_t *attr)
     78 {
     79 	if (attr == NULL || attr->__pthread_attrp == NULL)
     80 		return (EINVAL);
     81 	lfree(attr->__pthread_attrp, sizeof (thrattr_t));
     82 	attr->__pthread_attrp = NULL;
     83 	return (0);
     84 }
     85 
     86 /*
     87  * pthread_attr_clone: make a copy of a pthread_attr_t.
     88  */
     89 int
     90 pthread_attr_clone(pthread_attr_t *attr, const pthread_attr_t *old_attr)
     91 {
     92 	thrattr_t *ap;
     93 	const thrattr_t *old_ap =
     94 	    old_attr? old_attr->__pthread_attrp : def_thrattr();
     95 
     96 	if (old_ap == NULL)
     97 		return (EINVAL);
     98 	if ((ap = lmalloc(sizeof (thrattr_t))) == NULL)
     99 		return (ENOMEM);
    100 	*ap = *old_ap;
    101 	attr->__pthread_attrp = ap;
    102 	return (0);
    103 }
    104 
    105 /*
    106  * pthread_attr_equal: compare two pthread_attr_t's, return 1 if equal.
    107  * A NULL pthread_attr_t pointer implies default attributes.
    108  * This is a consolidation-private interface, for librt.
    109  */
    110 int
    111 pthread_attr_equal(const pthread_attr_t *attr1, const pthread_attr_t *attr2)
    112 {
    113 	const thrattr_t *ap1 = attr1? attr1->__pthread_attrp : def_thrattr();
    114 	const thrattr_t *ap2 = attr2? attr2->__pthread_attrp : def_thrattr();
    115 
    116 	if (ap1 == NULL || ap2 == NULL)
    117 		return (0);
    118 	return (ap1 == ap2 || memcmp(ap1, ap2, sizeof (thrattr_t)) == 0);
    119 }
    120 
    121 /*
    122  * pthread_attr_setstacksize: sets the user stack size, minimum should
    123  * be PTHREAD_STACK_MIN (MINSTACK).
    124  * This is equivalent to stksize argument in thr_create().
    125  */
    126 int
    127 pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
    128 {
    129 	thrattr_t *ap;
    130 
    131 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
    132 	    stacksize >= MINSTACK) {
    133 		ap->stksize = stacksize;
    134 		return (0);
    135 	}
    136 	return (EINVAL);
    137 }
    138 
    139 /*
    140  * pthread_attr_getstacksize: gets the user stack size.
    141  */
    142 #pragma weak _pthread_attr_getstacksize = pthread_attr_getstacksize
    143 int
    144 pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize)
    145 {
    146 	thrattr_t *ap;
    147 
    148 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
    149 	    stacksize != NULL) {
    150 		*stacksize = ap->stksize;
    151 		return (0);
    152 	}
    153 	return (EINVAL);
    154 }
    155 
    156 /*
    157  * pthread_attr_setstackaddr: sets the user stack addr.
    158  * This is equivalent to stkaddr argument in thr_create().
    159  */
    160 int
    161 pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr)
    162 {
    163 	thrattr_t *ap;
    164 
    165 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL) {
    166 		ap->stkaddr = stackaddr;
    167 		return (0);
    168 	}
    169 	return (EINVAL);
    170 }
    171 
    172 /*
    173  * pthread_attr_getstackaddr: gets the user stack addr.
    174  */
    175 #pragma weak _pthread_attr_getstackaddr = pthread_attr_getstackaddr
    176 int
    177 pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr)
    178 {
    179 	thrattr_t *ap;
    180 
    181 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
    182 	    stackaddr != NULL) {
    183 		*stackaddr = ap->stkaddr;
    184 		return (0);
    185 	}
    186 	return (EINVAL);
    187 }
    188 
    189 /*
    190  * pthread_attr_setdetachstate: sets the detach state to DETACHED or JOINABLE.
    191  * PTHREAD_CREATE_DETACHED is equivalent to thr_create(THR_DETACHED).
    192  */
    193 int
    194 pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
    195 {
    196 	thrattr_t *ap;
    197 
    198 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
    199 	    (detachstate == PTHREAD_CREATE_DETACHED ||
    200 	    detachstate == PTHREAD_CREATE_JOINABLE)) {
    201 		ap->detachstate = detachstate;
    202 		return (0);
    203 	}
    204 	return (EINVAL);
    205 }
    206 
    207 /*
    208  * pthread_attr_getdetachstate: gets the detach state.
    209  */
    210 #pragma weak _pthread_attr_getdetachstate = pthread_attr_getdetachstate
    211 int
    212 pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
    213 {
    214 	thrattr_t *ap;
    215 
    216 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
    217 	    detachstate != NULL) {
    218 		*detachstate = ap->detachstate;
    219 		return (0);
    220 	}
    221 	return (EINVAL);
    222 }
    223 
    224 /*
    225  * pthread_attr_setdaemonstate_np: sets the daemon state to DAEMON or NONDAEMON.
    226  * PTHREAD_CREATE_DAEMON is equivalent to thr_create(THR_DAEMON).
    227  * For now, this is a private interface in libc.
    228  */
    229 int
    230 pthread_attr_setdaemonstate_np(pthread_attr_t *attr, int daemonstate)
    231 {
    232 	thrattr_t *ap;
    233 
    234 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
    235 	    (daemonstate == PTHREAD_CREATE_DAEMON_NP ||
    236 	    daemonstate == PTHREAD_CREATE_NONDAEMON_NP)) {
    237 		ap->daemonstate = daemonstate;
    238 		return (0);
    239 	}
    240 	return (EINVAL);
    241 }
    242 
    243 /*
    244  * pthread_attr_getdaemonstate_np: gets the daemon state.
    245  * For now, this is a private interface in libc.
    246  */
    247 int
    248 pthread_attr_getdaemonstate_np(const pthread_attr_t *attr, int *daemonstate)
    249 {
    250 	thrattr_t *ap;
    251 
    252 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
    253 	    daemonstate != NULL) {
    254 		*daemonstate = ap->daemonstate;
    255 		return (0);
    256 	}
    257 	return (EINVAL);
    258 }
    259 
    260 /*
    261  * pthread_attr_setscope: sets the scope to SYSTEM or PROCESS.
    262  * This is equivalent to setting THR_BOUND flag in thr_create().
    263  */
    264 int
    265 pthread_attr_setscope(pthread_attr_t *attr, int scope)
    266 {
    267 	thrattr_t *ap;
    268 
    269 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
    270 	    (scope == PTHREAD_SCOPE_SYSTEM ||
    271 	    scope == PTHREAD_SCOPE_PROCESS)) {
    272 		ap->scope = scope;
    273 		return (0);
    274 	}
    275 	return (EINVAL);
    276 }
    277 
    278 /*
    279  * pthread_attr_getscope: gets the scheduling scope.
    280  */
    281 #pragma weak _pthread_attr_getscope = pthread_attr_getscope
    282 int
    283 pthread_attr_getscope(const pthread_attr_t *attr, int *scope)
    284 {
    285 	thrattr_t *ap;
    286 
    287 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
    288 	    scope != NULL) {
    289 		*scope = ap->scope;
    290 		return (0);
    291 	}
    292 	return (EINVAL);
    293 }
    294 
    295 /*
    296  * pthread_attr_setinheritsched: sets the scheduling parameters to be
    297  * EXPLICIT or INHERITED from parent thread.
    298  */
    299 int
    300 pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit)
    301 {
    302 	thrattr_t *ap;
    303 
    304 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
    305 	    (inherit == PTHREAD_EXPLICIT_SCHED ||
    306 	    inherit == PTHREAD_INHERIT_SCHED)) {
    307 		ap->inherit = inherit;
    308 		return (0);
    309 	}
    310 	return (EINVAL);
    311 }
    312 
    313 /*
    314  * pthread_attr_getinheritsched: gets the scheduling inheritance.
    315  */
    316 #pragma weak _pthread_attr_getinheritsched = pthread_attr_getinheritsched
    317 int
    318 pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inherit)
    319 {
    320 	thrattr_t *ap;
    321 
    322 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
    323 	    inherit != NULL) {
    324 		*inherit = ap->inherit;
    325 		return (0);
    326 	}
    327 	return (EINVAL);
    328 }
    329 
    330 /*
    331  * pthread_attr_setschedpolicy: sets the scheduling policy.
    332  */
    333 int
    334 pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
    335 {
    336 	thrattr_t *ap;
    337 
    338 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
    339 	    policy != SCHED_SYS && get_info_by_policy(policy) != NULL) {
    340 		ap->policy = policy;
    341 		return (0);
    342 	}
    343 	return (EINVAL);
    344 }
    345 
    346 /*
    347  * pthread_attr_getpolicy: gets the scheduling policy.
    348  */
    349 #pragma weak _pthread_attr_getschedpolicy = pthread_attr_getschedpolicy
    350 int
    351 pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
    352 {
    353 	thrattr_t *ap;
    354 
    355 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
    356 	    policy != NULL) {
    357 		*policy = ap->policy;
    358 		return (0);
    359 	}
    360 	return (EINVAL);
    361 }
    362 
    363 /*
    364  * pthread_attr_setschedparam: sets the scheduling parameters.
    365  * Currently, we support priority only.
    366  */
    367 int
    368 pthread_attr_setschedparam(pthread_attr_t *attr,
    369 	const struct sched_param *param)
    370 {
    371 	thrattr_t *ap;
    372 
    373 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
    374 	    param != NULL) {
    375 		ap->prio = param->sched_priority;
    376 		return (0);
    377 	}
    378 	return (EINVAL);
    379 }
    380 
    381 /*
    382  * pthread_attr_getschedparam: gets the scheduling parameters.
    383  * Currently, only priority is defined as sched parameter.
    384  */
    385 #pragma weak _pthread_attr_getschedparam = pthread_attr_getschedparam
    386 int
    387 pthread_attr_getschedparam(const pthread_attr_t *attr,
    388 					struct sched_param *param)
    389 {
    390 	thrattr_t *ap;
    391 
    392 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
    393 	    param != NULL) {
    394 		param->sched_priority = ap->prio;
    395 		return (0);
    396 	}
    397 	return (EINVAL);
    398 }
    399 
    400 /*
    401  * UNIX98
    402  * pthread_attr_setguardsize: sets the guardsize
    403  */
    404 int
    405 pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize)
    406 {
    407 	thrattr_t *ap;
    408 
    409 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL) {
    410 		ap->guardsize = guardsize;
    411 		return (0);
    412 	}
    413 	return (EINVAL);
    414 }
    415 
    416 /*
    417  * UNIX98
    418  * pthread_attr_getguardsize: gets the guardsize
    419  */
    420 int
    421 pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize)
    422 {
    423 	thrattr_t *ap;
    424 
    425 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
    426 	    guardsize != NULL) {
    427 		*guardsize = ap->guardsize;
    428 		return (0);
    429 	}
    430 	return (EINVAL);
    431 }
    432 
    433 /*
    434  * pthread_attr_setstack: sets the user stack addr and stack size.
    435  * This is equivalent to the stack_base and stack_size arguments
    436  * to thr_create().
    437  */
    438 int
    439 pthread_attr_setstack(pthread_attr_t *attr,
    440 	void *stackaddr, size_t stacksize)
    441 {
    442 	thrattr_t *ap;
    443 
    444 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
    445 	    stacksize >= MINSTACK) {
    446 		ap->stkaddr = stackaddr;
    447 		ap->stksize = stacksize;
    448 		if (stackaddr != NULL &&
    449 		    setup_top_frame(stackaddr, stacksize, NULL) == NULL)
    450 			return (EACCES);
    451 		return (0);
    452 	}
    453 	return (EINVAL);
    454 }
    455 
    456 /*
    457  * pthread_attr_getstack: gets the user stack addr and stack size.
    458  */
    459 int
    460 pthread_attr_getstack(const pthread_attr_t *attr,
    461 	void **stackaddr, size_t *stacksize)
    462 {
    463 	thrattr_t *ap;
    464 
    465 	if (attr != NULL && (ap = attr->__pthread_attrp) != NULL &&
    466 	    stackaddr != NULL && stacksize != NULL) {
    467 		*stackaddr = ap->stkaddr;
    468 		*stacksize = ap->stksize;
    469 		return (0);
    470 	}
    471 	return (EINVAL);
    472 }
    473