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         /*
 230          * POSIX mutexes (this interface) make no guarantee about the state of
 231          * the mutex before pthread_mutex_init(3C) is called.  Sun mutexes, upon
 232          * which these are built and which mutex_init(3C) below represents
 233          * require that a robust mutex be initialized to all 0s _prior_ to
 234          * mutex_init() being called, and that mutex_init() of an initialized
 235          * mutex return EBUSY.
 236          *
 237          * We respect both these behaviors by zeroing the mutex here in the
 238          * POSIX implementation if and only if the mutex magic is incorrect,
 239          * and the mutex is robust.
 240          */
 241         if (((type & PTHREAD_MUTEX_ROBUST) != 0) &&
 242             (((mutex_t *)mutex)->mutex_magic != MUTEX_MAGIC)) {
 243                 (void) memset(mutex, 0, sizeof (*mutex));
 244         }
 245 
 246         return (mutex_init((mutex_t *)mutex, type, &prioceiling));
 247 }
 248 
 249 /*
 250  * pthread_mutex_setprioceiling: sets the prioceiling.
 251  * From the SUSv3 (POSIX) specification for pthread_mutex_setprioceiling():
 252  *      The process of locking the mutex need not
 253  *      adhere to the priority protect protocol.
 254  * We pass the MUTEX_NOCEIL flag to mutex_lock_internal() so that
 255  * a non-realtime thread can successfully execute this operation.
 256  */
 257 int
 258 pthread_mutex_setprioceiling(pthread_mutex_t *mutex, int ceil, int *oceil)
 259 {
 260         mutex_t *mp = (mutex_t *)mutex;
 261         const pcclass_t *pccp = get_info_by_policy(SCHED_FIFO);
 262         int error;
 263 
 264         if (!(mp->mutex_type & PTHREAD_PRIO_PROTECT) ||
 265             ceil < pccp->pcc_primin || ceil > pccp->pcc_primax)
 266                 return (EINVAL);
 267         error = mutex_lock_internal(mp, NULL, MUTEX_LOCK | MUTEX_NOCEIL);
 268         if (error == 0 || error == EOWNERDEAD || error == ELOCKUNMAPPED) {
 269                 if (oceil)
 270                         *oceil = mp->mutex_ceiling;
 271                 mp->mutex_ceiling = ceil;
 272                 error = mutex_unlock_internal(mp, 1);
 273         }
 274         return (error);
 275 }
 276 
 277 /*
 278  * pthread_mutex_getprioceiling: gets the prioceiling.
 279  */
 280 #pragma weak _pthread_mutex_getprioceiling = pthread_mutex_getprioceiling
 281 int
 282 pthread_mutex_getprioceiling(const pthread_mutex_t *mp, int *ceiling)
 283 {
 284         *ceiling = ((mutex_t *)mp)->mutex_ceiling;
 285         return (0);
 286 }
 287 
 288 /*
 289  * UNIX98
 290  * pthread_mutexattr_settype: sets the type attribute
 291  */
 292 int
 293 pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
 294 {
 295         mattr_t *ap;
 296 
 297         if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL)
 298                 return (EINVAL);
 299         switch (type) {
 300         case PTHREAD_MUTEX_NORMAL:
 301                 type = LOCK_NORMAL;
 302                 break;
 303         case PTHREAD_MUTEX_ERRORCHECK:
 304                 type = LOCK_ERRORCHECK;
 305                 break;
 306         case PTHREAD_MUTEX_RECURSIVE:
 307                 type = LOCK_RECURSIVE | LOCK_ERRORCHECK;
 308                 break;
 309         default:
 310                 return (EINVAL);
 311         }
 312         ap->type = type;
 313         return (0);
 314 }
 315 
 316 /*
 317  * UNIX98
 318  * pthread_mutexattr_gettype: gets the type attribute.
 319  */
 320 int
 321 pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *typep)
 322 {
 323         mattr_t *ap;
 324         int type;
 325 
 326         if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL ||
 327             typep == NULL)
 328                 return (EINVAL);
 329         switch (ap->type) {
 330         case LOCK_NORMAL:
 331                 type = PTHREAD_MUTEX_NORMAL;
 332                 break;
 333         case LOCK_ERRORCHECK:
 334                 type = PTHREAD_MUTEX_ERRORCHECK;
 335                 break;
 336         case LOCK_RECURSIVE | LOCK_ERRORCHECK:
 337                 type = PTHREAD_MUTEX_RECURSIVE;
 338                 break;
 339         default:
 340                 return (EINVAL);
 341         }
 342         *typep = type;
 343         return (0);
 344 }