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 2024 Oxide Computer Company 29 */ 30 31 #include "lint.h" 32 #include "thr_uberdata.h" 33 #include <pthread.h> 34 35 /* 36 * pthread_mutexattr_init: allocates the mutex attribute object and 37 * initializes it with the default values. 38 */ 39 #pragma weak _pthread_mutexattr_init = pthread_mutexattr_init 40 int 41 pthread_mutexattr_init(pthread_mutexattr_t *attr) 42 { 43 mattr_t *ap; 44 45 if ((ap = lmalloc(sizeof (mattr_t))) == NULL) 46 return (ENOMEM); 47 ap->pshared = PTHREAD_PROCESS_PRIVATE; 48 ap->type = PTHREAD_MUTEX_DEFAULT; 49 ap->protocol = PTHREAD_PRIO_NONE; 50 ap->robustness = PTHREAD_MUTEX_STALLED; 51 attr->__pthread_mutexattrp = ap; 52 return (0); 53 } 54 55 /* 56 * pthread_mutexattr_destroy: frees the mutex attribute object and 57 * invalidates it with NULL value. 58 */ 59 int 60 pthread_mutexattr_destroy(pthread_mutexattr_t *attr) 61 { 62 if (attr == NULL || attr->__pthread_mutexattrp == NULL) 63 return (EINVAL); 64 lfree(attr->__pthread_mutexattrp, sizeof (mattr_t)); 65 attr->__pthread_mutexattrp = NULL; 66 return (0); 67 } 68 69 /* 70 * pthread_mutexattr_setpshared: sets the shared attribute 71 * to PTHREAD_PROCESS_PRIVATE or PTHREAD_PROCESS_SHARED. 72 * This is equivalent to setting the USYNC_THREAD/USYNC_PROCESS 73 * flag in mutex_init(). 74 */ 75 int 76 pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared) 77 { 78 mattr_t *ap; 79 80 if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL || 81 (pshared != PTHREAD_PROCESS_PRIVATE && 82 pshared != PTHREAD_PROCESS_SHARED)) 83 return (EINVAL); 84 ap->pshared = pshared; 85 return (0); 86 } 87 88 /* 89 * pthread_mutexattr_getpshared: gets the shared attribute. 90 */ 91 #pragma weak _pthread_mutexattr_getpshared = pthread_mutexattr_getpshared 92 int 93 pthread_mutexattr_getpshared(const pthread_mutexattr_t *attr, int *pshared) 94 { 95 mattr_t *ap; 96 97 if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL || 98 pshared == NULL) 99 return (EINVAL); 100 *pshared = ap->pshared; 101 return (0); 102 } 103 104 /* 105 * pthread_mutexattr_setprioceiling: sets the prioceiling attribute. 106 */ 107 int 108 pthread_mutexattr_setprioceiling(pthread_mutexattr_t *attr, int prioceiling) 109 { 110 const pcclass_t *pccp = get_info_by_policy(SCHED_FIFO); 111 mattr_t *ap; 112 113 if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL || 114 prioceiling < pccp->pcc_primin || prioceiling > pccp->pcc_primax) 115 return (EINVAL); 116 ap->prioceiling = prioceiling; 117 return (0); 118 } 119 120 /* 121 * pthread_mutexattr_getprioceiling: gets the prioceiling attribute. 122 */ 123 #pragma weak _pthread_mutexattr_getprioceiling = \ 124 pthread_mutexattr_getprioceiling 125 int 126 pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *attr, int *ceiling) 127 { 128 mattr_t *ap; 129 130 if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL || 131 ceiling == NULL) 132 return (EINVAL); 133 *ceiling = ap->prioceiling; 134 return (0); 135 } 136 137 /* 138 * pthread_mutexattr_setprotocol: sets the protocol attribute. 139 */ 140 int 141 pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr, int protocol) 142 { 143 mattr_t *ap; 144 145 if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL) 146 return (EINVAL); 147 if (protocol != PTHREAD_PRIO_NONE && 148 protocol != PTHREAD_PRIO_INHERIT && 149 protocol != PTHREAD_PRIO_PROTECT) 150 return (ENOTSUP); 151 ap->protocol = protocol; 152 return (0); 153 } 154 155 /* 156 * pthread_mutexattr_getprotocol: gets the protocol attribute. 157 */ 158 #pragma weak _pthread_mutexattr_getprotocol = pthread_mutexattr_getprotocol 159 int 160 pthread_mutexattr_getprotocol(const pthread_mutexattr_t *attr, int *protocol) 161 { 162 mattr_t *ap; 163 164 if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL || 165 protocol == NULL) 166 return (EINVAL); 167 *protocol = ap->protocol; 168 return (0); 169 } 170 171 /* 172 * pthread_mutexattr_setrobust: set the mutex robust attribute. 173 * pthread_mutexattr_setrobust_np: the historical name. 174 */ 175 #pragma weak pthread_mutexattr_setrobust_np = pthread_mutexattr_setrobust 176 int 177 pthread_mutexattr_setrobust(pthread_mutexattr_t *attr, int robust) 178 { 179 mattr_t *ap; 180 181 if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL || 182 (robust != PTHREAD_MUTEX_ROBUST && robust != PTHREAD_MUTEX_STALLED)) 183 return (EINVAL); 184 ap->robustness = robust; 185 return (0); 186 } 187 188 /* 189 * pthread_mutexattr_getrobust: get the mutex robust attribute. 190 * pthread_mutexattr_getrobust_np: the historical name. 191 */ 192 #pragma weak pthread_mutexattr_getrobust_np = pthread_mutexattr_getrobust 193 int 194 pthread_mutexattr_getrobust(const pthread_mutexattr_t *attr, int *robust) 195 { 196 mattr_t *ap; 197 198 if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL || 199 robust == NULL) 200 return (EINVAL); 201 *robust = ap->robustness; 202 return (0); 203 } 204 205 /* 206 * pthread_mutex_init: Initializes the mutex object. It copies the various 207 * attributes into one type argument and calls mutex_init(). Unlike other 208 * values, the types that are used in the mutex attributes are not 1:1 mapped to 209 * our underlying lock types at this time so we can properly honor the semantics 210 * of someone asking for a PTHREAD_MUTEX_NORMAL lock that must deadlock. The 211 * underlying threads implementation does not do this by default for 212 * USYNC_THREAD and so we don't do this unless explicitly asked for it. 213 */ 214 #pragma weak _pthread_mutex_init = pthread_mutex_init 215 int 216 pthread_mutex_init(pthread_mutex_t *_RESTRICT_KYWD mutex, 217 const pthread_mutexattr_t *_RESTRICT_KYWD attr) 218 { 219 mattr_t *ap; 220 int type, ret; 221 int prioceiling = 0; 222 uint16_t flags = 0; 223 224 /* 225 * All of the pshared, type, protocol, robust attributes 226 * translate to bits in the mutex_type field. 227 */ 228 if (attr != NULL) { 229 if ((ap = attr->__pthread_mutexattrp) == NULL) 230 return (EINVAL); 231 switch (ap->type) { 232 case PTHREAD_MUTEX_NORMAL: 233 type = LOCK_NORMAL; 234 flags = LOCK_DEADLOCK; 235 break; 236 case PTHREAD_MUTEX_ERRORCHECK: 237 type = LOCK_ERRORCHECK; 238 break; 239 case PTHREAD_MUTEX_RECURSIVE: 240 type = LOCK_RECURSIVE | LOCK_ERRORCHECK; 241 break; 242 default: 243 /* 244 * This covers PTHREAD_MUTEX_DEFAULT, which should be 245 * the only remaining valid value. 246 */ 247 type = LOCK_NORMAL; 248 break; 249 } 250 251 type |= ap->pshared | ap->protocol | ap->robustness; 252 if (ap->protocol == PTHREAD_PRIO_PROTECT) 253 prioceiling = ap->prioceiling; 254 } else { 255 type = PTHREAD_PROCESS_PRIVATE | LOCK_NORMAL | 256 PTHREAD_PRIO_NONE | PTHREAD_MUTEX_STALLED; 257 } 258 259 /* 260 * POSIX mutexes (this interface) make no guarantee about the state of 261 * the mutex before pthread_mutex_init(3C) is called. Sun mutexes, upon 262 * which these are built and which mutex_init(3C) below represents 263 * require that a robust mutex be initialized to all 0s _prior_ to 264 * mutex_init() being called, and that mutex_init() of an initialized 265 * mutex return EBUSY. 266 * 267 * We respect both these behaviors by zeroing the mutex here in the 268 * POSIX implementation if and only if the mutex magic is incorrect, 269 * and the mutex is robust. 270 */ 271 if (((type & PTHREAD_MUTEX_ROBUST) != 0) && 272 (((mutex_t *)mutex)->mutex_magic != MUTEX_MAGIC)) { 273 (void) memset(mutex, 0, sizeof (*mutex)); 274 } 275 276 ret = mutex_init((mutex_t *)mutex, type, &prioceiling); 277 278 /* 279 * If we have a normal mutex, we need to set that deadlock behavior is 280 * required. 281 */ 282 if (ret == 0 && flags != 0) { 283 mutex_t *mp = (mutex_t *)mutex; 284 mp->mutex_flag |= flags; 285 } 286 287 return (ret); 288 } 289 290 /* 291 * pthread_mutex_setprioceiling: sets the prioceiling. 292 * From the SUSv3 (POSIX) specification for pthread_mutex_setprioceiling(): 293 * The process of locking the mutex need not 294 * adhere to the priority protect protocol. 295 * We pass the MUTEX_NOCEIL flag to mutex_lock_internal() so that 296 * a non-realtime thread can successfully execute this operation. 297 */ 298 int 299 pthread_mutex_setprioceiling(pthread_mutex_t *mutex, int ceil, int *oceil) 300 { 301 mutex_t *mp = (mutex_t *)mutex; 302 const pcclass_t *pccp = get_info_by_policy(SCHED_FIFO); 303 int error; 304 305 if (!(mp->mutex_type & PTHREAD_PRIO_PROTECT) || 306 ceil < pccp->pcc_primin || ceil > pccp->pcc_primax) 307 return (EINVAL); 308 error = mutex_lock_internal(mp, NULL, MUTEX_LOCK | MUTEX_NOCEIL); 309 if (error == 0 || error == EOWNERDEAD || error == ELOCKUNMAPPED) { 310 if (oceil) 311 *oceil = mp->mutex_ceiling; 312 mp->mutex_ceiling = ceil; 313 error = mutex_unlock_internal(mp, 1); 314 } 315 return (error); 316 } 317 318 /* 319 * pthread_mutex_getprioceiling: gets the prioceiling. 320 */ 321 #pragma weak _pthread_mutex_getprioceiling = pthread_mutex_getprioceiling 322 int 323 pthread_mutex_getprioceiling(const pthread_mutex_t *mp, int *ceiling) 324 { 325 *ceiling = ((mutex_t *)mp)->mutex_ceiling; 326 return (0); 327 } 328 329 /* 330 * UNIX98 331 * pthread_mutexattr_settype: sets the type attribute 332 * 333 * Type attributes are kept in terms of POSIX mutex types until the mutex is 334 * initialized, after which it is translated into the corresponding underlying 335 * lock type. 336 */ 337 int 338 pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type) 339 { 340 mattr_t *ap; 341 342 if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL) 343 return (EINVAL); 344 switch (type) { 345 case PTHREAD_MUTEX_NORMAL: 346 case PTHREAD_MUTEX_ERRORCHECK: 347 case PTHREAD_MUTEX_RECURSIVE: 348 case PTHREAD_MUTEX_DEFAULT: 349 break; 350 default: 351 return (EINVAL); 352 } 353 ap->type = type; 354 return (0); 355 } 356 357 /* 358 * UNIX98 359 * pthread_mutexattr_gettype: gets the type attribute. 360 */ 361 int 362 pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *typep) 363 { 364 mattr_t *ap; 365 int type; 366 367 if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL || 368 typep == NULL) 369 return (EINVAL); 370 *typep = type; 371 return (0); 372 } 373