xref: /illumos-gate/usr/src/lib/libc/port/threads/pthr_mutex.c (revision 6a5dded72533447331efa78c840a7d3d2d04e877)
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 various
203  * attributes into one type argument and calls mutex_init().  Unlike other
204  * values, the types that are used in the mutex attributes are not 1:1 mapped to
205  * our underlying lock types at this time so we can properly honor the semantics
206  * of someone asking for a PTHREAD_MUTEX_NORMAL lock that must deadlock. The
207  * underlying threads implementation does not do this by default for
208  * USYNC_THREAD and so we don't do this unless explicitly asked for it.
209  */
210 #pragma weak _pthread_mutex_init = pthread_mutex_init
211 int
212 pthread_mutex_init(pthread_mutex_t *_RESTRICT_KYWD mutex,
213     const pthread_mutexattr_t *_RESTRICT_KYWD attr)
214 {
215 	mattr_t		*ap;
216 	int		type, ret;
217 	int		prioceiling = 0;
218 	uint16_t	flags = 0;
219 
220 	/*
221 	 * All of the pshared, type, protocol, robust attributes
222 	 * translate to bits in the mutex_type field.
223 	 */
224 	if (attr != NULL) {
225 		if ((ap = attr->__pthread_mutexattrp) == NULL)
226 			return (EINVAL);
227 		switch (ap->type) {
228 		case PTHREAD_MUTEX_NORMAL:
229 			type = LOCK_NORMAL;
230 			flags = LOCK_DEADLOCK;
231 			break;
232 		case PTHREAD_MUTEX_ERRORCHECK:
233 			type = LOCK_ERRORCHECK;
234 			break;
235 		case PTHREAD_MUTEX_RECURSIVE:
236 			type = LOCK_RECURSIVE;
237 			break;
238 		default:
239 			/*
240 			 * This covers PTHREAD_MUTEX_DEFAULT, which should be
241 			 * the only remaining valid value.
242 			 */
243 			type = LOCK_NORMAL;
244 			break;
245 		}
246 
247 		type |= ap->pshared | ap->protocol | ap->robustness;
248 		if (ap->protocol == PTHREAD_PRIO_PROTECT)
249 			prioceiling = ap->prioceiling;
250 	} else {
251 		type = PTHREAD_PROCESS_PRIVATE | LOCK_NORMAL |
252 		    PTHREAD_PRIO_NONE | PTHREAD_MUTEX_STALLED;
253 	}
254 
255 	/*
256 	 * POSIX mutexes (this interface) make no guarantee about the state of
257 	 * the mutex before pthread_mutex_init(3C) is called.  Sun mutexes, upon
258 	 * which these are built and which mutex_init(3C) below represents
259 	 * require that a robust mutex be initialized to all 0s _prior_ to
260 	 * mutex_init() being called, and that mutex_init() of an initialized
261 	 * mutex return EBUSY.
262 	 *
263 	 * We respect both these behaviors by zeroing the mutex here in the
264 	 * POSIX implementation if and only if the mutex magic is incorrect,
265 	 * and the mutex is robust.
266 	 */
267 	if (((type & PTHREAD_MUTEX_ROBUST) != 0) &&
268 	    (((mutex_t *)mutex)->mutex_magic != MUTEX_MAGIC)) {
269 		(void) memset(mutex, 0, sizeof (*mutex));
270 	}
271 
272 	ret = mutex_init((mutex_t *)mutex, type, &prioceiling);
273 
274 	/*
275 	 * If we have a normal mutex, we need to set that deadlock behavior is
276 	 * required.
277 	 */
278 	if (ret == 0 && flags != 0) {
279 		mutex_t *mp = (mutex_t *)mutex;
280 		mp->mutex_flag |= flags;
281 	}
282 
283 	return (ret);
284 }
285 
286 /*
287  * pthread_mutex_setprioceiling: sets the prioceiling.
288  * From the SUSv3 (POSIX) specification for pthread_mutex_setprioceiling():
289  *	The process of locking the mutex need not
290  *	adhere to the priority protect protocol.
291  * We pass the MUTEX_NOCEIL flag to mutex_lock_internal() so that
292  * a non-realtime thread can successfully execute this operation.
293  */
294 int
295 pthread_mutex_setprioceiling(pthread_mutex_t *mutex, int ceil, int *oceil)
296 {
297 	mutex_t *mp = (mutex_t *)mutex;
298 	const pcclass_t *pccp = get_info_by_policy(SCHED_FIFO);
299 	int error;
300 
301 	if (!(mp->mutex_type & PTHREAD_PRIO_PROTECT) ||
302 	    ceil < pccp->pcc_primin || ceil > pccp->pcc_primax)
303 		return (EINVAL);
304 	error = mutex_lock_internal(mp, NULL, MUTEX_LOCK | MUTEX_NOCEIL);
305 	if (error == 0 || error == EOWNERDEAD || error == ELOCKUNMAPPED) {
306 		if (oceil)
307 			*oceil = mp->mutex_ceiling;
308 		mp->mutex_ceiling = ceil;
309 		error = mutex_unlock_internal(mp, 1);
310 	}
311 	return (error);
312 }
313 
314 /*
315  * pthread_mutex_getprioceiling: gets the prioceiling.
316  */
317 #pragma weak _pthread_mutex_getprioceiling = pthread_mutex_getprioceiling
318 int
319 pthread_mutex_getprioceiling(const pthread_mutex_t *mp, int *ceiling)
320 {
321 	*ceiling = ((mutex_t *)mp)->mutex_ceiling;
322 	return (0);
323 }
324 
325 /*
326  * UNIX98
327  * pthread_mutexattr_settype: sets the type attribute
328  *
329  * Type attributes are kept in terms of POSIX mutex types until the mutex is
330  * initialized, after which it is translated into the corresponding underlying
331  * lock type.
332  */
333 int
334 pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
335 {
336 	mattr_t	*ap;
337 
338 	if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL)
339 		return (EINVAL);
340 	switch (type) {
341 	case PTHREAD_MUTEX_NORMAL:
342 	case PTHREAD_MUTEX_ERRORCHECK:
343 	case PTHREAD_MUTEX_RECURSIVE:
344 	case PTHREAD_MUTEX_DEFAULT:
345 		break;
346 	default:
347 		return (EINVAL);
348 	}
349 	ap->type = type;
350 	return (0);
351 }
352 
353 /*
354  * UNIX98
355  * pthread_mutexattr_gettype: gets the type attribute.
356  */
357 int
358 pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *typep)
359 {
360 	mattr_t	*ap;
361 	int type;
362 
363 	if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL ||
364 	    typep == NULL)
365 		return (EINVAL);
366 	*typep = type;
367 	return (0);
368 }
369