xref: /illumos-gate/usr/src/lib/libc/port/threads/pthr_mutex.c (revision 1d9df23bbf4124f12ca7832d6eaaa600e0aa8eda)
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 #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 attribute
70  * to PTHREAD_PROCESS_PRIVATE or PTHREAD_PROCESS_SHARED.
71  * This is equivalent to setting the USYNC_THREAD/USYNC_PROCESS
72  * flag in mutex_init().
73  */
74 #pragma weak pthread_mutexattr_setpshared =  _pthread_mutexattr_setpshared
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 #pragma weak pthread_mutexattr_setprioceiling = \
108 					_pthread_mutexattr_setprioceiling
109 int
110 _pthread_mutexattr_setprioceiling(pthread_mutexattr_t *attr, int prioceiling)
111 {
112 	const pcclass_t *pccp = get_info_by_policy(SCHED_FIFO);
113 	mattr_t	*ap;
114 
115 	if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL ||
116 	    prioceiling < pccp->pcc_primin || prioceiling > pccp->pcc_primax)
117 		return (EINVAL);
118 	ap->prioceiling = prioceiling;
119 	return (0);
120 }
121 
122 /*
123  * pthread_mutexattr_getprioceiling: gets the prioceiling attribute.
124  */
125 #pragma weak pthread_mutexattr_getprioceiling = \
126 					_pthread_mutexattr_getprioceiling
127 int
128 _pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *attr, int *ceiling)
129 {
130 	mattr_t	*ap;
131 
132 	if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL ||
133 	    ceiling == NULL)
134 		return (EINVAL);
135 	*ceiling = ap->prioceiling;
136 	return (0);
137 }
138 
139 /*
140  * pthread_mutexattr_setprotocol: sets the protocol attribute.
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  */
161 #pragma weak pthread_mutexattr_getprotocol =  _pthread_mutexattr_getprotocol
162 int
163 _pthread_mutexattr_getprotocol(const pthread_mutexattr_t *attr, int *protocol)
164 {
165 	mattr_t	*ap;
166 
167 	if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL ||
168 	    protocol == NULL)
169 		return (EINVAL);
170 	*protocol = ap->protocol;
171 	return (0);
172 }
173 
174 /*
175  * pthread_mutexattr_setrobust_np: sets the robustness attribute
176  * to PTHREAD_MUTEX_ROBUST_NP or PTHREAD_MUTEX_STALL_NP.
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 attribute.
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_init: Initializes the mutex object.  It copies the
212  * various attributes into one type argument and calls mutex_init().
213  */
214 #pragma weak pthread_mutex_init = _pthread_mutex_init
215 int
216 _pthread_mutex_init(pthread_mutex_t *mutex, pthread_mutexattr_t *attr)
217 {
218 	mattr_t *ap;
219 	int	type;
220 	int	prioceiling = 0;
221 
222 	/*
223 	 * All of the pshared, type, protocol, robust attributes
224 	 * translate to bits in the mutex_type field.
225 	 */
226 	if (attr != NULL) {
227 		if ((ap = attr->__pthread_mutexattrp) == NULL)
228 			return (EINVAL);
229 		type = ap->pshared | ap->type | ap->protocol | ap->robustness;
230 		if (ap->protocol == PTHREAD_PRIO_PROTECT)
231 			prioceiling = ap->prioceiling;
232 	} else {
233 		type = DEFAULT_TYPE | PTHREAD_MUTEX_DEFAULT |
234 		    PTHREAD_PRIO_NONE | PTHREAD_MUTEX_STALL_NP;
235 	}
236 
237 	return (_private_mutex_init((mutex_t *)mutex, type, &prioceiling));
238 }
239 
240 /*
241  * pthread_mutex_setprioceiling: sets the prioceiling.
242  * From the SUSv3 (POSIX) specification for pthread_mutex_setprioceiling():
243  *	The process of locking the mutex need not
244  *	adhere to the priority protect protocol.
245  * We pass the MUTEX_NOCEIL flag to mutex_lock_internal() so that
246  * a non-realtime thread can successfully execute this operation.
247  */
248 #pragma weak pthread_mutex_setprioceiling =  _pthread_mutex_setprioceiling
249 int
250 _pthread_mutex_setprioceiling(pthread_mutex_t *mutex, int ceil, int *oceil)
251 {
252 	mutex_t *mp = (mutex_t *)mutex;
253 	const pcclass_t *pccp = get_info_by_policy(SCHED_FIFO);
254 	int error;
255 
256 	if (!(mp->mutex_type & PTHREAD_PRIO_PROTECT) ||
257 	    ceil < pccp->pcc_primin || ceil > pccp->pcc_primax)
258 		return (EINVAL);
259 	error = mutex_lock_internal(mp, NULL, MUTEX_LOCK | MUTEX_NOCEIL);
260 	if (error == 0) {
261 		if (oceil)
262 			*oceil = mp->mutex_ceiling;
263 		mp->mutex_ceiling = ceil;
264 		error = mutex_unlock_internal(mp, 0);
265 	}
266 	return (error);
267 }
268 
269 /*
270  * pthread_mutex_getprioceiling: gets the prioceiling.
271  */
272 #pragma weak pthread_mutex_getprioceiling =  _pthread_mutex_getprioceiling
273 int
274 _pthread_mutex_getprioceiling(const pthread_mutex_t *mp, int *ceiling)
275 {
276 	*ceiling = ((mutex_t *)mp)->mutex_ceiling;
277 	return (0);
278 }
279 
280 /*
281  * UNIX98
282  * pthread_mutexattr_settype: sets the type attribute
283  */
284 #pragma weak pthread_mutexattr_settype =  _pthread_mutexattr_settype
285 int
286 _pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
287 {
288 	mattr_t	*ap;
289 
290 	if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL)
291 		return (EINVAL);
292 	switch (type) {
293 	case PTHREAD_MUTEX_NORMAL:
294 		type = LOCK_NORMAL;
295 		break;
296 	case PTHREAD_MUTEX_ERRORCHECK:
297 		type = LOCK_ERRORCHECK;
298 		break;
299 	case PTHREAD_MUTEX_RECURSIVE:
300 		type = LOCK_RECURSIVE | LOCK_ERRORCHECK;
301 		break;
302 	default:
303 		return (EINVAL);
304 	}
305 	ap->type = type;
306 	return (0);
307 }
308 
309 /*
310  * UNIX98
311  * pthread_mutexattr_gettype: gets the type attribute.
312  */
313 #pragma weak pthread_mutexattr_gettype =  _pthread_mutexattr_gettype
314 int
315 _pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *typep)
316 {
317 	mattr_t	*ap;
318 	int type;
319 
320 	if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL ||
321 	    typep == NULL)
322 		return (EINVAL);
323 	switch (ap->type) {
324 	case LOCK_NORMAL:
325 		type = PTHREAD_MUTEX_NORMAL;
326 		break;
327 	case LOCK_ERRORCHECK:
328 		type = PTHREAD_MUTEX_ERRORCHECK;
329 		break;
330 	case LOCK_RECURSIVE | LOCK_ERRORCHECK:
331 		type = PTHREAD_MUTEX_RECURSIVE;
332 		break;
333 	default:
334 		return (EINVAL);
335 	}
336 	*typep = type;
337 	return (0);
338 }
339