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 <pthread.h>
  30 
  31 /*
  32  * pthread_mutexattr_init: allocates the mutex attribute object and
  33  * initializes it with the default values.
  34  */
  35 #pragma weak _pthread_mutexattr_init = pthread_mutexattr_init
  36 int
  37 pthread_mutexattr_init(pthread_mutexattr_t *attr)
  38 {
  39         mattr_t *ap;
  40 
  41         if ((ap = lmalloc(sizeof (mattr_t))) == NULL)
  42                 return (ENOMEM);
  43         ap->pshared = PTHREAD_PROCESS_PRIVATE;
  44         ap->type = PTHREAD_MUTEX_DEFAULT;
  45         ap->protocol = PTHREAD_PRIO_NONE;
  46         ap->robustness = PTHREAD_MUTEX_STALLED;
  47         attr->__pthread_mutexattrp = ap;
  48         return (0);
  49 }
  50 
  51 /*
  52  * pthread_mutexattr_destroy: frees the mutex attribute object and
  53  * invalidates it with NULL value.
  54  */
  55 int
  56 pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
  57 {
  58         if (attr == NULL || attr->__pthread_mutexattrp == NULL)
  59                 return (EINVAL);
  60         lfree(attr->__pthread_mutexattrp, sizeof (mattr_t));
  61         attr->__pthread_mutexattrp = NULL;
  62         return (0);
  63 }
  64 
  65 /*
  66  * pthread_mutexattr_setpshared: sets the shared attribute
  67  * to PTHREAD_PROCESS_PRIVATE or PTHREAD_PROCESS_SHARED.
  68  * This is equivalent to setting the USYNC_THREAD/USYNC_PROCESS
  69  * flag in mutex_init().
  70  */
  71 int
  72 pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared)
  73 {
  74         mattr_t *ap;
  75 
  76         if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL ||
  77             (pshared != PTHREAD_PROCESS_PRIVATE &&
  78             pshared != PTHREAD_PROCESS_SHARED))
  79                 return (EINVAL);
  80         ap->pshared = pshared;
  81         return (0);
  82 }
  83 
  84 /*
  85  * pthread_mutexattr_getpshared: gets the shared attribute.
  86  */
  87 #pragma weak _pthread_mutexattr_getpshared = pthread_mutexattr_getpshared
  88 int
  89 pthread_mutexattr_getpshared(const pthread_mutexattr_t *attr, int *pshared)
  90 {
  91         mattr_t *ap;
  92 
  93         if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL ||
  94             pshared == NULL)
  95                 return (EINVAL);
  96         *pshared = ap->pshared;
  97         return (0);
  98 }
  99 
 100 /*
 101  * pthread_mutexattr_setprioceiling: sets the prioceiling attribute.
 102  */
 103 int
 104 pthread_mutexattr_setprioceiling(pthread_mutexattr_t *attr, int prioceiling)
 105 {
 106         const pcclass_t *pccp = get_info_by_policy(SCHED_FIFO);
 107         mattr_t *ap;
 108 
 109         if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL ||
 110             prioceiling < pccp->pcc_primin || prioceiling > pccp->pcc_primax)
 111                 return (EINVAL);
 112         ap->prioceiling = prioceiling;
 113         return (0);
 114 }
 115 
 116 /*
 117  * pthread_mutexattr_getprioceiling: gets the prioceiling attribute.
 118  */
 119 #pragma weak _pthread_mutexattr_getprioceiling = \
 120                         pthread_mutexattr_getprioceiling
 121 int
 122 pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *attr, int *ceiling)
 123 {
 124         mattr_t *ap;
 125 
 126         if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL ||
 127             ceiling == NULL)
 128                 return (EINVAL);
 129         *ceiling = ap->prioceiling;
 130         return (0);
 131 }
 132 
 133 /*
 134  * pthread_mutexattr_setprotocol: sets the protocol attribute.
 135  */
 136 int
 137 pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr, int protocol)
 138 {
 139         mattr_t *ap;
 140 
 141         if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL)
 142                 return (EINVAL);
 143         if (protocol != PTHREAD_PRIO_NONE &&
 144             protocol != PTHREAD_PRIO_INHERIT &&
 145             protocol != PTHREAD_PRIO_PROTECT)
 146                 return (ENOTSUP);
 147         ap->protocol = protocol;
 148         return (0);
 149 }
 150 
 151 /*
 152  * pthread_mutexattr_getprotocol: gets the protocol attribute.
 153  */
 154 #pragma weak _pthread_mutexattr_getprotocol = pthread_mutexattr_getprotocol
 155 int
 156 pthread_mutexattr_getprotocol(const pthread_mutexattr_t *attr, int *protocol)
 157 {
 158         mattr_t *ap;
 159 
 160         if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL ||
 161             protocol == NULL)
 162                 return (EINVAL);
 163         *protocol = ap->protocol;
 164         return (0);
 165 }
 166 
 167 /*
 168  * pthread_mutexattr_setrobust: set the mutex robust attribute.
 169  * pthread_mutexattr_setrobust_np: the historical name.
 170  */
 171 #pragma weak pthread_mutexattr_setrobust_np = pthread_mutexattr_setrobust
 172 int
 173 pthread_mutexattr_setrobust(pthread_mutexattr_t *attr, int robust)
 174 {
 175         mattr_t *ap;
 176 
 177         if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL ||
 178             (robust != PTHREAD_MUTEX_ROBUST && robust != PTHREAD_MUTEX_STALLED))
 179                 return (EINVAL);
 180         ap->robustness = robust;
 181         return (0);
 182 }
 183 
 184 /*
 185  * pthread_mutexattr_getrobust: get the mutex robust attribute.
 186  * pthread_mutexattr_getrobust_np: the historical name.
 187  */
 188 #pragma weak pthread_mutexattr_getrobust_np = pthread_mutexattr_getrobust
 189 int
 190 pthread_mutexattr_getrobust(const pthread_mutexattr_t *attr, int *robust)
 191 {
 192         mattr_t *ap;
 193 
 194         if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL ||
 195             robust == NULL)
 196                 return (EINVAL);
 197         *robust = ap->robustness;
 198         return (0);
 199 }
 200 
 201 /*
 202  * pthread_mutex_init: Initializes the mutex object.  It copies the
 203  * various attributes into one type argument and calls mutex_init().
 204  */
 205 #pragma weak _pthread_mutex_init = pthread_mutex_init
 206 int
 207 pthread_mutex_init(pthread_mutex_t *_RESTRICT_KYWD mutex,
 208     const pthread_mutexattr_t *_RESTRICT_KYWD attr)
 209 {
 210         mattr_t *ap;
 211         int     type;
 212         int     prioceiling = 0;
 213 
 214         /*
 215          * All of the pshared, type, protocol, robust attributes
 216          * translate to bits in the mutex_type field.
 217          */
 218         if (attr != NULL) {
 219                 if ((ap = attr->__pthread_mutexattrp) == NULL)
 220                         return (EINVAL);
 221                 type = ap->pshared | ap->type | ap->protocol | ap->robustness;
 222                 if (ap->protocol == PTHREAD_PRIO_PROTECT)
 223                         prioceiling = ap->prioceiling;
 224         } else {
 225                 type = PTHREAD_PROCESS_PRIVATE | PTHREAD_MUTEX_DEFAULT |
 226                     PTHREAD_PRIO_NONE | PTHREAD_MUTEX_STALLED;
 227         }
 228 
 229         return (mutex_init((mutex_t *)mutex, type, &prioceiling));
 230 }
 231 
 232 /*
 233  * pthread_mutex_setprioceiling: sets the prioceiling.
 234  * From the SUSv3 (POSIX) specification for pthread_mutex_setprioceiling():
 235  *      The process of locking the mutex need not
 236  *      adhere to the priority protect protocol.
 237  * We pass the MUTEX_NOCEIL flag to mutex_lock_internal() so that
 238  * a non-realtime thread can successfully execute this operation.
 239  */
 240 int
 241 pthread_mutex_setprioceiling(pthread_mutex_t *mutex, int ceil, int *oceil)
 242 {
 243         mutex_t *mp = (mutex_t *)mutex;
 244         const pcclass_t *pccp = get_info_by_policy(SCHED_FIFO);
 245         int error;
 246 
 247         if (!(mp->mutex_type & PTHREAD_PRIO_PROTECT) ||
 248             ceil < pccp->pcc_primin || ceil > pccp->pcc_primax)
 249                 return (EINVAL);
 250         error = mutex_lock_internal(mp, NULL, MUTEX_LOCK | MUTEX_NOCEIL);
 251         if (error == 0 || error == EOWNERDEAD || error == ELOCKUNMAPPED) {
 252                 if (oceil)
 253                         *oceil = mp->mutex_ceiling;
 254                 mp->mutex_ceiling = ceil;
 255                 error = mutex_unlock_internal(mp, 1);
 256         }
 257         return (error);
 258 }
 259 
 260 /*
 261  * pthread_mutex_getprioceiling: gets the prioceiling.
 262  */
 263 #pragma weak _pthread_mutex_getprioceiling = pthread_mutex_getprioceiling
 264 int
 265 pthread_mutex_getprioceiling(const pthread_mutex_t *mp, int *ceiling)
 266 {
 267         *ceiling = ((mutex_t *)mp)->mutex_ceiling;
 268         return (0);
 269 }
 270 
 271 /*
 272  * UNIX98
 273  * pthread_mutexattr_settype: sets the type attribute
 274  */
 275 int
 276 pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
 277 {
 278         mattr_t *ap;
 279 
 280         if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL)
 281                 return (EINVAL);
 282         switch (type) {
 283         case PTHREAD_MUTEX_NORMAL:
 284                 type = LOCK_NORMAL;
 285                 break;
 286         case PTHREAD_MUTEX_ERRORCHECK:
 287                 type = LOCK_ERRORCHECK;
 288                 break;
 289         case PTHREAD_MUTEX_RECURSIVE:
 290                 type = LOCK_RECURSIVE | LOCK_ERRORCHECK;
 291                 break;
 292         default:
 293                 return (EINVAL);
 294         }
 295         ap->type = type;
 296         return (0);
 297 }
 298 
 299 /*
 300  * UNIX98
 301  * pthread_mutexattr_gettype: gets the type attribute.
 302  */
 303 int
 304 pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *typep)
 305 {
 306         mattr_t *ap;
 307         int type;
 308 
 309         if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL ||
 310             typep == NULL)
 311                 return (EINVAL);
 312         switch (ap->type) {
 313         case LOCK_NORMAL:
 314                 type = PTHREAD_MUTEX_NORMAL;
 315                 break;
 316         case LOCK_ERRORCHECK:
 317                 type = PTHREAD_MUTEX_ERRORCHECK;
 318                 break;
 319         case LOCK_RECURSIVE | LOCK_ERRORCHECK:
 320                 type = PTHREAD_MUTEX_RECURSIVE;
 321                 break;
 322         default:
 323                 return (EINVAL);
 324         }
 325         *typep = type;
 326         return (0);
 327 }