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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include "lint.h" 30 #include "thr_uberdata.h" 31 32 /* 33 * pthread_once related data 34 * This structure is exported as pthread_once_t in pthread.h. 35 * We export only the size of this structure. so check 36 * pthread_once_t in pthread.h before making a change here. 37 */ 38 typedef struct __once { 39 mutex_t mlock; 40 union { 41 uint32_t pad32_flag[2]; 42 uint64_t pad64_flag; 43 } oflag; 44 } __once_t; 45 46 #define once_flag oflag.pad32_flag[1] 47 48 /* 49 * Default attribute object for pthread_create() with NULL attr pointer. 50 * Note that the 'guardsize' field is initialized on the first call 51 * to pthread_create() with a NULL attr pointer. 52 */ 53 static thrattr_t _defattr = 54 {0, NULL, PTHREAD_CREATE_JOINABLE, PTHREAD_SCOPE_PROCESS, 55 0, SCHED_OTHER, PTHREAD_EXPLICIT_SCHED, 0}; 56 57 /* 58 * pthread_create: creates a thread in the current process. 59 * calls common _thrp_create() after copying the attributes. 60 */ 61 #pragma weak pthread_create = _pthread_create 62 int 63 _pthread_create(pthread_t *thread, const pthread_attr_t *attr, 64 void * (*start_routine)(void *), void *arg) 65 { 66 ulwp_t *self = curthread; 67 uberdata_t *udp = self->ul_uberdata; 68 long flag; 69 thrattr_t *ap; 70 pthread_t tid; 71 int policy; 72 pri_t priority; 73 int error; 74 int mapped = 0; 75 int mappedpri; 76 int rt = 0; 77 78 if (attr == NULL) { 79 ap = &_defattr; 80 if (ap->guardsize == 0) { 81 if (_lpagesize == 0) 82 _lpagesize = _sysconf(_SC_PAGESIZE); 83 ap->guardsize = _lpagesize; 84 } 85 } else if ((ap = attr->__pthread_attrp) == NULL) { 86 return (EINVAL); 87 } 88 89 if (ap->inherit == PTHREAD_INHERIT_SCHED) { 90 policy = self->ul_policy; 91 priority = self->ul_pri; 92 mapped = self->ul_pri_mapped; 93 mappedpri = self->ul_mappedpri; 94 } else { 95 policy = ap->policy; 96 priority = ap->prio; 97 if (policy == SCHED_OTHER) { 98 if (priority < THREAD_MIN_PRIORITY || 99 priority > THREAD_MAX_PRIORITY) { 100 if (_validate_rt_prio(policy, priority)) 101 return (EINVAL); 102 mapped = 1; 103 mappedpri = priority; 104 priority = _map_rtpri_to_gp(priority); 105 ASSERT(priority >= THREAD_MIN_PRIORITY && 106 priority <= THREAD_MAX_PRIORITY); 107 } 108 } else if (policy == SCHED_FIFO || policy == SCHED_RR) { 109 if (_validate_rt_prio(policy, priority)) 110 return (EINVAL); 111 if (_private_geteuid() == 0) 112 rt = 1; 113 } else { 114 return (EINVAL); 115 } 116 } 117 118 flag = ap->scope | ap->detachstate | THR_SUSPENDED; 119 error = _thrp_create(ap->stkaddr, ap->stksize, start_routine, arg, 120 flag, &tid, priority, policy, ap->guardsize); 121 if (error == 0) { 122 if (mapped) { 123 ulwp_t *ulwp = find_lwp(tid); 124 ulwp->ul_pri_mapped = 1; 125 ulwp->ul_mappedpri = mappedpri; 126 ulwp_unlock(ulwp, udp); 127 } 128 if (rt && _thrp_setlwpprio(tid, policy, priority)) 129 thr_panic("_thrp_setlwpprio() failed"); 130 if (thread) 131 *thread = tid; 132 (void) _thr_continue(tid); 133 } 134 135 /* posix version expects EAGAIN for lack of memory */ 136 if (error == ENOMEM) 137 error = EAGAIN; 138 return (error); 139 } 140 141 /* 142 * pthread_once: calls given function only once. 143 * it synchronizes via mutex in pthread_once_t structure 144 */ 145 #pragma weak pthread_once = _pthread_once 146 int 147 _pthread_once(pthread_once_t *once_control, void (*init_routine)(void)) 148 { 149 __once_t *once = (__once_t *)once_control; 150 151 if (once == NULL || init_routine == NULL) 152 return (EINVAL); 153 154 if (once->once_flag == PTHREAD_ONCE_NOTDONE) { 155 (void) _private_mutex_lock(&once->mlock); 156 if (once->once_flag == PTHREAD_ONCE_NOTDONE) { 157 pthread_cleanup_push(_private_mutex_unlock, 158 &once->mlock); 159 (*init_routine)(); 160 pthread_cleanup_pop(0); 161 once->once_flag = PTHREAD_ONCE_DONE; 162 } 163 (void) _private_mutex_unlock(&once->mlock); 164 } 165 166 return (0); 167 } 168 169 /* 170 * pthread_equal: equates two thread ids. 171 */ 172 #pragma weak pthread_equal = _pthread_equal 173 int 174 _pthread_equal(pthread_t t1, pthread_t t2) 175 { 176 return (t1 == t2); 177 } 178 179 /* 180 * pthread_getschedparam: gets the sched parameters in a struct. 181 */ 182 #pragma weak pthread_getschedparam = _pthread_getschedparam 183 int 184 _pthread_getschedparam(pthread_t tid, int *policy, struct sched_param *param) 185 { 186 uberdata_t *udp = curthread->ul_uberdata; 187 ulwp_t *ulwp; 188 int error = 0; 189 190 if (param == NULL || policy == NULL) 191 error = EINVAL; 192 else if ((ulwp = find_lwp(tid)) == NULL) 193 error = ESRCH; 194 else { 195 if (ulwp->ul_pri_mapped) 196 param->sched_priority = ulwp->ul_mappedpri; 197 else 198 param->sched_priority = ulwp->ul_pri; 199 *policy = ulwp->ul_policy; 200 ulwp_unlock(ulwp, udp); 201 } 202 203 return (error); 204 } 205 206 /* 207 * Besides the obvious arguments, the inheritflag needs to be explained: 208 * If set to PRIO_SET or PRIO_SET_PRIO, it does the normal, expected work 209 * of setting thread's assigned scheduling parameters and policy. 210 * If set to PRIO_INHERIT, it sets the thread's effective priority values 211 * (t_epri, t_empappedpri), and does not update the assigned priority values 212 * (t_pri, t_mappedpri). If set to PRIO_DISINHERIT, it clears the thread's 213 * effective priority values, and reverts the thread, if necessary, back 214 * to the assigned priority values. 215 */ 216 int 217 _thread_setschedparam_main(pthread_t tid, int policy, 218 const struct sched_param *param, int inheritflag) 219 { 220 uberdata_t *udp = curthread->ul_uberdata; 221 ulwp_t *ulwp; 222 int error = 0; 223 int prio; 224 int opolicy; 225 int mappedprio; 226 int mapped = 0; 227 pri_t *mappedprip; 228 229 if (param == NULL) 230 return (EINVAL); 231 if ((ulwp = find_lwp(tid)) == NULL) 232 return (ESRCH); 233 prio = param->sched_priority; 234 opolicy = ulwp->ul_policy; 235 if (inheritflag == PRIO_SET_PRIO) { /* don't change policy */ 236 policy = opolicy; 237 inheritflag = PRIO_SET; 238 } 239 ASSERT(inheritflag == PRIO_SET || opolicy == policy); 240 if (inheritflag == PRIO_DISINHERIT) { 241 ulwp->ul_emappedpri = 0; 242 ulwp->ul_epri = 0; 243 prio = ulwp->ul_pri; /* ignore prio in sched_param */ 244 } 245 if (policy == SCHED_OTHER) { 246 /* 247 * Set thread's policy to OTHER 248 */ 249 if (prio < THREAD_MIN_PRIORITY || prio > THREAD_MAX_PRIORITY) { 250 if (_validate_rt_prio(policy, prio)) { 251 error = EINVAL; 252 goto out; 253 } 254 mapped = 1; 255 mappedprio = prio; 256 prio = _map_rtpri_to_gp(prio); 257 ASSERT(prio >= THREAD_MIN_PRIORITY && 258 prio <= THREAD_MAX_PRIORITY); 259 } 260 /* 261 * Thread changing from FIFO/RR to OTHER 262 */ 263 if (opolicy == SCHED_FIFO || opolicy == SCHED_RR) { 264 if ((error = _thrp_setlwpprio(tid, policy, prio)) != 0) 265 goto out; 266 } 267 if (inheritflag != PRIO_DISINHERIT) { 268 if (inheritflag == PRIO_INHERIT) 269 mappedprip = &ulwp->ul_emappedpri; 270 else 271 mappedprip = &ulwp->ul_mappedpri; 272 if (mapped) { 273 ulwp->ul_pri_mapped = 1; 274 *mappedprip = mappedprio; 275 } else { 276 ulwp->ul_pri_mapped = 0; 277 *mappedprip = 0; 278 } 279 } 280 ulwp->ul_policy = policy; 281 if (inheritflag == PRIO_INHERIT) 282 ulwp->ul_epri = prio; 283 else 284 ulwp->ul_pri = prio; 285 } else if (policy == SCHED_FIFO || policy == SCHED_RR) { 286 if (_validate_rt_prio(policy, prio)) 287 error = EINVAL; 288 else { 289 if (_private_geteuid() == 0 && 290 _thrp_setlwpprio(tid, policy, prio)) 291 thr_panic("_thrp_setlwpprio failed"); 292 ulwp->ul_policy = policy; 293 if (inheritflag == PRIO_INHERIT) 294 ulwp->ul_epri = prio; 295 else 296 ulwp->ul_pri = prio; 297 } 298 } else { 299 error = EINVAL; 300 } 301 302 out: 303 ulwp_unlock(ulwp, udp); 304 return (error); 305 } 306 307 /* 308 * pthread_setschedparam: sets the sched parameters for a thread. 309 */ 310 #pragma weak pthread_setschedparam = _pthread_setschedparam 311 int 312 _pthread_setschedparam(pthread_t tid, 313 int policy, const struct sched_param *param) 314 { 315 return (_thread_setschedparam_main(tid, policy, param, PRIO_SET)); 316 } 317