xref: /illumos-gate/usr/src/lib/libc/port/threads/pthr_mutex.c (revision 4de2612967d06c4fdbf524a62556a1e8118a006f)
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 1999-2003 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 #include <pthread.h>
32 
33 /*
34  * pthread_mutexattr_init: allocates the mutex attribute object and
35  * initializes it with the default values.
36  */
37 #pragma weak pthread_mutexattr_init = _pthread_mutexattr_init
38 int
39 _pthread_mutexattr_init(pthread_mutexattr_t *attr)
40 {
41 	mattr_t	*ap;
42 
43 	if ((ap = lmalloc(sizeof (mattr_t))) == NULL)
44 		return (ENOMEM);
45 	ap->pshared = DEFAULT_TYPE;
46 	ap->type = PTHREAD_MUTEX_DEFAULT;
47 	ap->protocol = PTHREAD_PRIO_NONE;
48 	ap->robustness = PTHREAD_MUTEX_STALL_NP;
49 	attr->__pthread_mutexattrp = ap;
50 	return (0);
51 }
52 
53 /*
54  * pthread_mutexattr_destroy: frees the mutex attribute object and
55  * invalidates it with NULL value.
56  */
57 #pragma weak pthread_mutexattr_destroy =  _pthread_mutexattr_destroy
58 int
59 _pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
60 {
61 	if (attr == NULL || attr->__pthread_mutexattrp == NULL)
62 		return (EINVAL);
63 	lfree(attr->__pthread_mutexattrp, sizeof (mattr_t));
64 	attr->__pthread_mutexattrp = NULL;
65 	return (0);
66 }
67 
68 /*
69  * pthread_mutexattr_setpshared: sets the shared attr to PRIVATE or SHARED.
70  * This is equivalent to setting USYNC_PROCESS/USYNC_THREAD flag in
71  * mutex_init().
72  */
73 #pragma weak pthread_mutexattr_setpshared =  _pthread_mutexattr_setpshared
74 int
75 _pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared)
76 {
77 	mattr_t	*ap;
78 
79 	if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL ||
80 	    (pshared != PTHREAD_PROCESS_PRIVATE &&
81 	    pshared != PTHREAD_PROCESS_SHARED))
82 		return (EINVAL);
83 	ap->pshared = pshared;
84 	return (0);
85 }
86 
87 /*
88  * pthread_mutexattr_getpshared: gets the shared attr.
89  */
90 #pragma weak pthread_mutexattr_getpshared =  _pthread_mutexattr_getpshared
91 int
92 _pthread_mutexattr_getpshared(const pthread_mutexattr_t *attr, int *pshared)
93 {
94 	mattr_t	*ap;
95 
96 	if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL ||
97 	    pshared == NULL)
98 		return (EINVAL);
99 	*pshared = ap->pshared;
100 	return (0);
101 }
102 
103 /*
104  * pthread_mutexattr_setprioceiling: sets the prioceiling attr.
105  */
106 #pragma weak pthread_mutexattr_setprioceiling = \
107 					_pthread_mutexattr_setprioceiling
108 int
109 _pthread_mutexattr_setprioceiling(pthread_mutexattr_t *attr, int prioceiling)
110 {
111 	mattr_t	*ap;
112 
113 	if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL ||
114 	    _validate_rt_prio(SCHED_FIFO, prioceiling))
115 		return (EINVAL);
116 	ap->prioceiling = prioceiling;
117 	return (0);
118 }
119 
120 /*
121  * pthread_mutexattr_getprioceiling: gets the prioceiling attr.
122  * Currently unsupported.
123  */
124 #pragma weak pthread_mutexattr_getprioceiling = \
125 					_pthread_mutexattr_getprioceiling
126 int
127 _pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *attr, int *ceiling)
128 {
129 	mattr_t	*ap;
130 
131 	if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL ||
132 	    ceiling == NULL)
133 		return (EINVAL);
134 	*ceiling = ap->prioceiling;
135 	return (0);
136 }
137 
138 /*
139  * pthread_mutexattr_setprotocol: sets the protocol attribute.
140  * Currently unsupported.
141  */
142 #pragma weak pthread_mutexattr_setprotocol =  _pthread_mutexattr_setprotocol
143 int
144 _pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr, int protocol)
145 {
146 	mattr_t	*ap;
147 
148 	if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL)
149 		return (EINVAL);
150 	if (protocol != PTHREAD_PRIO_NONE &&
151 	    protocol != PTHREAD_PRIO_INHERIT &&
152 	    protocol != PTHREAD_PRIO_PROTECT)
153 		return (ENOTSUP);
154 	ap->protocol = protocol;
155 	return (0);
156 }
157 
158 /*
159  * pthread_mutexattr_getprotocol: gets the protocol attribute.
160  * Currently unsupported.
161  */
162 #pragma weak pthread_mutexattr_getprotocol =  _pthread_mutexattr_getprotocol
163 int
164 _pthread_mutexattr_getprotocol(const pthread_mutexattr_t *attr, int *protocol)
165 {
166 	mattr_t	*ap;
167 
168 	if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL ||
169 	    protocol == NULL)
170 		return (EINVAL);
171 	*protocol = ap->protocol;
172 	return (0);
173 }
174 
175 /*
176  * pthread_mutexattr_setrobust_np: sets the robustness attr to ROBUST or STALL.
177  */
178 #pragma weak pthread_mutexattr_setrobust_np = \
179 					_pthread_mutexattr_setrobust_np
180 int
181 _pthread_mutexattr_setrobust_np(pthread_mutexattr_t *attr, int robust)
182 {
183 	mattr_t	*ap;
184 
185 	if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL ||
186 	    (robust != PTHREAD_MUTEX_ROBUST_NP &&
187 	    robust != PTHREAD_MUTEX_STALL_NP))
188 		return (EINVAL);
189 	ap->robustness = robust;
190 	return (0);
191 }
192 
193 /*
194  * pthread_mutexattr_getrobust_np: gets the robustness attr.
195  */
196 #pragma weak pthread_mutexattr_getrobust_np = \
197 					_pthread_mutexattr_getrobust_np
198 int
199 _pthread_mutexattr_getrobust_np(const pthread_mutexattr_t *attr, int *robust)
200 {
201 	mattr_t	*ap;
202 
203 	if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL ||
204 	    robust == NULL)
205 		return (EINVAL);
206 	*robust = ap->robustness;
207 	return (0);
208 }
209 
210 /*
211  * pthread_mutex_consistent_np: make an inconsistent mutex consistent.
212  * The mutex must have been made inconsistent due to the last owner of it
213  * having died. Currently, no validation is done to check if:
214  *      - the caller owns the mutex
215  * Since this function is supported only for PI/robust locks, to check
216  * if the caller owns the mutex, one needs to call the kernel. For now,
217  * such extra validation does not seem necessary.
218  */
219 #pragma weak pthread_mutex_consistent_np = _pthread_mutex_consistent_np
220 int
221 _pthread_mutex_consistent_np(pthread_mutex_t *pmp)
222 {
223 	mutex_t *mp = (mutex_t *)pmp;
224 
225 	/*
226 	 * Do this only for an inconsistent, initialized, PI, Robust lock.
227 	 * For all other cases, return EINVAL.
228 	 */
229 	if ((mp->mutex_type & PTHREAD_PRIO_INHERIT) &&
230 	    (mp->mutex_type & PTHREAD_MUTEX_ROBUST_NP) &&
231 	    (mp->mutex_flag & LOCK_INITED) &&
232 	    (mp->mutex_flag & LOCK_OWNERDEAD)) {
233 		mp->mutex_flag &= ~LOCK_OWNERDEAD;
234 		return (0);
235 	}
236 	return (EINVAL);
237 }
238 
239 /*
240  * pthread_mutex_init: Initializes the mutex object. It copies the
241  * pshared attr into type argument and calls mutex_init().
242  */
243 #pragma weak pthread_mutex_init = _pthread_mutex_init
244 int
245 _pthread_mutex_init(pthread_mutex_t *mutex, pthread_mutexattr_t *attr)
246 {
247 	mutex_t *mp = (mutex_t *)mutex;
248 	int	type;
249 	int	pshared;
250 	int	protocol;
251 	int	prioceiling = 0;
252 	int	robust;
253 	int	error;
254 	mattr_t *ap;
255 
256 	if (attr != NULL) {
257 		if ((ap = attr->__pthread_mutexattrp) == NULL)
258 			return (EINVAL);
259 		pshared = ap->pshared;
260 		type = ap->type;
261 		protocol = ap->protocol;
262 		if (protocol == PTHREAD_PRIO_PROTECT)
263 			prioceiling = ap->prioceiling;
264 		robust = ap->robustness;
265 		/*
266 		 * Support robust mutexes only for PI locks.
267 		 */
268 		if (robust == PTHREAD_MUTEX_ROBUST_NP &&
269 		    protocol != PTHREAD_PRIO_INHERIT)
270 			return (EINVAL);
271 	} else {
272 		pshared = DEFAULT_TYPE;
273 		type = PTHREAD_MUTEX_DEFAULT;
274 		protocol = PTHREAD_PRIO_NONE;
275 		robust = PTHREAD_MUTEX_STALL_NP;
276 	}
277 
278 	error = _private_mutex_init(mp, pshared, NULL);
279 	if (error == 0) {
280 		/*
281 		 * Use the same routine to set the protocol, and robustness
282 		 * attributes, as that used to set the type attribute, since
283 		 * all of these attributes translate to bits in the mutex_type
284 		 * field.
285 		 *
286 		 * Note that robustness is a new bit, not the Solaris robust
287 		 * bit - the latter implies USYNC_PROCESS_ROBUST, or
288 		 * SHARED,ROBUST together. For POSIX, since robustness is an
289 		 * orthogonal attribute, both SHARED,ROBUST and PRIVATE,ROBUST
290 		 * should be valid combinations for the future. Hence,
291 		 * introduce a new bit in the mutex type field. See
292 		 * sys/synch.h or pthread.h. In the future, if we ever
293 		 * introduce a USYNC_THREAD_ROBUST, the latter could use this
294 		 * new bit...
295 		 */
296 		_mutex_set_typeattr(mp, type|protocol|robust);
297 		mp->mutex_ceiling = (uint8_t)prioceiling;
298 	}
299 	return (error);
300 }
301 
302 /*
303  * pthread_mutex_setprioceiling: sets the prioceiling.
304  */
305 #pragma weak pthread_mutex_setprioceiling =  _pthread_mutex_setprioceiling
306 int
307 _pthread_mutex_setprioceiling(pthread_mutex_t *mutex, int ceil, int *oceil)
308 {
309 	mutex_t *mp = (mutex_t *)mutex;
310 	int error;
311 
312 	if (!(mp->mutex_type & PTHREAD_PRIO_PROTECT) ||
313 	    _validate_rt_prio(SCHED_FIFO, ceil) != 0)
314 		return (EINVAL);
315 	error = _private_mutex_lock(mp);
316 	if (error == 0) {
317 		if (oceil)
318 			*oceil = mp->mutex_ceiling;
319 		mp->mutex_ceiling = (uint8_t)ceil;
320 		error = _private_mutex_unlock(mp);
321 	}
322 	return (error);
323 }
324 
325 /*
326  * pthread_mutex_getprioceiling: gets the prioceiling.
327  */
328 #pragma weak pthread_mutex_getprioceiling =  _pthread_mutex_getprioceiling
329 int
330 _pthread_mutex_getprioceiling(const pthread_mutex_t *mp, int *ceiling)
331 {
332 	*ceiling = ((mutex_t *)mp)->mutex_ceiling;
333 	return (0);
334 }
335 
336 /*
337  * UNIX98
338  * pthread_mutexattr_settype: sets the type attribute
339  */
340 #pragma weak pthread_mutexattr_settype =  _pthread_mutexattr_settype
341 int
342 _pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
343 {
344 	mattr_t	*ap;
345 
346 	if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL)
347 		return (EINVAL);
348 	switch (type) {
349 	case PTHREAD_MUTEX_NORMAL:
350 		type = LOCK_NORMAL;
351 		break;
352 	case PTHREAD_MUTEX_ERRORCHECK:
353 		type = LOCK_ERRORCHECK;
354 		break;
355 	case PTHREAD_MUTEX_RECURSIVE:
356 		type = LOCK_RECURSIVE|LOCK_ERRORCHECK;
357 		break;
358 	default:
359 		return (EINVAL);
360 	}
361 	ap->type = type;
362 	return (0);
363 }
364 
365 /*
366  * UNIX98
367  * pthread_mutexattr_gettype: gets the type attr.
368  */
369 #pragma weak pthread_mutexattr_gettype =  _pthread_mutexattr_gettype
370 int
371 _pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *typep)
372 {
373 	mattr_t	*ap;
374 	int type;
375 
376 	if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL ||
377 	    typep == NULL)
378 		return (EINVAL);
379 	switch (ap->type) {
380 	case LOCK_NORMAL:
381 		type = PTHREAD_MUTEX_NORMAL;
382 		break;
383 	case LOCK_ERRORCHECK:
384 		type = PTHREAD_MUTEX_ERRORCHECK;
385 		break;
386 	case LOCK_RECURSIVE|LOCK_ERRORCHECK:
387 		type = PTHREAD_MUTEX_RECURSIVE;
388 		break;
389 	default:
390 		return (EINVAL);
391 	}
392 	*typep = type;
393 	return (0);
394 }
395