xref: /illumos-gate/usr/src/lib/libc/port/threads/pthr_mutex.c (revision 628e3cbed6489fa1db545d8524a06cd6535af456)
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 int
58 pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
59 {
60 	if (attr == NULL || attr->__pthread_mutexattrp == NULL)
61 		return (EINVAL);
62 	lfree(attr->__pthread_mutexattrp, sizeof (mattr_t));
63 	attr->__pthread_mutexattrp = NULL;
64 	return (0);
65 }
66 
67 /*
68  * pthread_mutexattr_setpshared: sets the shared attribute
69  * to PTHREAD_PROCESS_PRIVATE or PTHREAD_PROCESS_SHARED.
70  * This is equivalent to setting the USYNC_THREAD/USYNC_PROCESS
71  * flag in mutex_init().
72  */
73 int
74 pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared)
75 {
76 	mattr_t	*ap;
77 
78 	if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL ||
79 	    (pshared != PTHREAD_PROCESS_PRIVATE &&
80 	    pshared != PTHREAD_PROCESS_SHARED))
81 		return (EINVAL);
82 	ap->pshared = pshared;
83 	return (0);
84 }
85 
86 /*
87  * pthread_mutexattr_getpshared: gets the shared attribute.
88  */
89 #pragma weak _pthread_mutexattr_getpshared = pthread_mutexattr_getpshared
90 int
91 pthread_mutexattr_getpshared(const pthread_mutexattr_t *attr, int *pshared)
92 {
93 	mattr_t	*ap;
94 
95 	if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL ||
96 	    pshared == NULL)
97 		return (EINVAL);
98 	*pshared = ap->pshared;
99 	return (0);
100 }
101 
102 /*
103  * pthread_mutexattr_setprioceiling: sets the prioceiling attribute.
104  */
105 int
106 pthread_mutexattr_setprioceiling(pthread_mutexattr_t *attr, int prioceiling)
107 {
108 	const pcclass_t *pccp = get_info_by_policy(SCHED_FIFO);
109 	mattr_t	*ap;
110 
111 	if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL ||
112 	    prioceiling < pccp->pcc_primin || prioceiling > pccp->pcc_primax)
113 		return (EINVAL);
114 	ap->prioceiling = prioceiling;
115 	return (0);
116 }
117 
118 /*
119  * pthread_mutexattr_getprioceiling: gets the prioceiling attribute.
120  */
121 #pragma weak _pthread_mutexattr_getprioceiling = \
122 			pthread_mutexattr_getprioceiling
123 int
124 pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *attr, int *ceiling)
125 {
126 	mattr_t	*ap;
127 
128 	if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL ||
129 	    ceiling == NULL)
130 		return (EINVAL);
131 	*ceiling = ap->prioceiling;
132 	return (0);
133 }
134 
135 /*
136  * pthread_mutexattr_setprotocol: sets the protocol attribute.
137  */
138 int
139 pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr, int protocol)
140 {
141 	mattr_t	*ap;
142 
143 	if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL)
144 		return (EINVAL);
145 	if (protocol != PTHREAD_PRIO_NONE &&
146 	    protocol != PTHREAD_PRIO_INHERIT &&
147 	    protocol != PTHREAD_PRIO_PROTECT)
148 		return (ENOTSUP);
149 	ap->protocol = protocol;
150 	return (0);
151 }
152 
153 /*
154  * pthread_mutexattr_getprotocol: gets the protocol attribute.
155  */
156 #pragma weak _pthread_mutexattr_getprotocol = pthread_mutexattr_getprotocol
157 int
158 pthread_mutexattr_getprotocol(const pthread_mutexattr_t *attr, int *protocol)
159 {
160 	mattr_t	*ap;
161 
162 	if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL ||
163 	    protocol == NULL)
164 		return (EINVAL);
165 	*protocol = ap->protocol;
166 	return (0);
167 }
168 
169 /*
170  * pthread_mutexattr_setrobust_np: sets the robustness attribute
171  * to PTHREAD_MUTEX_ROBUST_NP or PTHREAD_MUTEX_STALL_NP.
172  */
173 int
174 pthread_mutexattr_setrobust_np(pthread_mutexattr_t *attr, int robust)
175 {
176 	mattr_t	*ap;
177 
178 	if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL ||
179 	    (robust != PTHREAD_MUTEX_ROBUST_NP &&
180 	    robust != PTHREAD_MUTEX_STALL_NP))
181 		return (EINVAL);
182 	ap->robustness = robust;
183 	return (0);
184 }
185 
186 /*
187  * pthread_mutexattr_getrobust_np: gets the robustness attribute.
188  */
189 int
190 pthread_mutexattr_getrobust_np(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 = DEFAULT_TYPE | PTHREAD_MUTEX_DEFAULT |
226 		    PTHREAD_PRIO_NONE | PTHREAD_MUTEX_STALL_NP;
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) {
252 		if (oceil)
253 			*oceil = mp->mutex_ceiling;
254 		mp->mutex_ceiling = ceil;
255 		error = mutex_unlock_internal(mp, 0);
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 }
328