xref: /illumos-gate/usr/src/lib/libc/port/threads/pthr_mutex.c (revision da7002c4941931fa102b3ecd9c22f84ad95d6f42)
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 /*
28  * Copyright 2024 Oxide Computer Company
29  */
30 
31 #include "lint.h"
32 #include "thr_uberdata.h"
33 #include <pthread.h>
34 
35 /*
36  * pthread_mutexattr_init: allocates the mutex attribute object and
37  * initializes it with the default values.
38  */
39 #pragma weak _pthread_mutexattr_init = pthread_mutexattr_init
40 int
pthread_mutexattr_init(pthread_mutexattr_t * attr)41 pthread_mutexattr_init(pthread_mutexattr_t *attr)
42 {
43 	mattr_t	*ap;
44 
45 	if ((ap = lmalloc(sizeof (mattr_t))) == NULL)
46 		return (ENOMEM);
47 	ap->pshared = PTHREAD_PROCESS_PRIVATE;
48 	ap->type = PTHREAD_MUTEX_DEFAULT;
49 	ap->protocol = PTHREAD_PRIO_NONE;
50 	ap->robustness = PTHREAD_MUTEX_STALLED;
51 	attr->__pthread_mutexattrp = ap;
52 	return (0);
53 }
54 
55 /*
56  * pthread_mutexattr_destroy: frees the mutex attribute object and
57  * invalidates it with NULL value.
58  */
59 int
pthread_mutexattr_destroy(pthread_mutexattr_t * attr)60 pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
61 {
62 	if (attr == NULL || attr->__pthread_mutexattrp == NULL)
63 		return (EINVAL);
64 	lfree(attr->__pthread_mutexattrp, sizeof (mattr_t));
65 	attr->__pthread_mutexattrp = NULL;
66 	return (0);
67 }
68 
69 /*
70  * pthread_mutexattr_setpshared: sets the shared attribute
71  * to PTHREAD_PROCESS_PRIVATE or PTHREAD_PROCESS_SHARED.
72  * This is equivalent to setting the USYNC_THREAD/USYNC_PROCESS
73  * flag in mutex_init().
74  */
75 int
pthread_mutexattr_setpshared(pthread_mutexattr_t * attr,int pshared)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
pthread_mutexattr_getpshared(const pthread_mutexattr_t * attr,int * pshared)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 int
pthread_mutexattr_setprioceiling(pthread_mutexattr_t * attr,int prioceiling)108 pthread_mutexattr_setprioceiling(pthread_mutexattr_t *attr, int prioceiling)
109 {
110 	const pcclass_t *pccp = get_info_by_policy(SCHED_FIFO);
111 	mattr_t	*ap;
112 
113 	if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL ||
114 	    prioceiling < pccp->pcc_primin || prioceiling > pccp->pcc_primax)
115 		return (EINVAL);
116 	ap->prioceiling = prioceiling;
117 	return (0);
118 }
119 
120 /*
121  * pthread_mutexattr_getprioceiling: gets the prioceiling attribute.
122  */
123 #pragma weak _pthread_mutexattr_getprioceiling = \
124 			pthread_mutexattr_getprioceiling
125 int
pthread_mutexattr_getprioceiling(const pthread_mutexattr_t * attr,int * ceiling)126 pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *attr, int *ceiling)
127 {
128 	mattr_t	*ap;
129 
130 	if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL ||
131 	    ceiling == NULL)
132 		return (EINVAL);
133 	*ceiling = ap->prioceiling;
134 	return (0);
135 }
136 
137 /*
138  * pthread_mutexattr_setprotocol: sets the protocol attribute.
139  */
140 int
pthread_mutexattr_setprotocol(pthread_mutexattr_t * attr,int protocol)141 pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr, int protocol)
142 {
143 	mattr_t	*ap;
144 
145 	if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL)
146 		return (EINVAL);
147 	if (protocol != PTHREAD_PRIO_NONE &&
148 	    protocol != PTHREAD_PRIO_INHERIT &&
149 	    protocol != PTHREAD_PRIO_PROTECT)
150 		return (ENOTSUP);
151 	ap->protocol = protocol;
152 	return (0);
153 }
154 
155 /*
156  * pthread_mutexattr_getprotocol: gets the protocol attribute.
157  */
158 #pragma weak _pthread_mutexattr_getprotocol = pthread_mutexattr_getprotocol
159 int
pthread_mutexattr_getprotocol(const pthread_mutexattr_t * attr,int * protocol)160 pthread_mutexattr_getprotocol(const pthread_mutexattr_t *attr, int *protocol)
161 {
162 	mattr_t	*ap;
163 
164 	if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL ||
165 	    protocol == NULL)
166 		return (EINVAL);
167 	*protocol = ap->protocol;
168 	return (0);
169 }
170 
171 /*
172  * pthread_mutexattr_setrobust: set the mutex robust attribute.
173  * pthread_mutexattr_setrobust_np: the historical name.
174  */
175 #pragma weak pthread_mutexattr_setrobust_np = pthread_mutexattr_setrobust
176 int
pthread_mutexattr_setrobust(pthread_mutexattr_t * attr,int robust)177 pthread_mutexattr_setrobust(pthread_mutexattr_t *attr, int robust)
178 {
179 	mattr_t	*ap;
180 
181 	if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL ||
182 	    (robust != PTHREAD_MUTEX_ROBUST && robust != PTHREAD_MUTEX_STALLED))
183 		return (EINVAL);
184 	ap->robustness = robust;
185 	return (0);
186 }
187 
188 /*
189  * pthread_mutexattr_getrobust: get the mutex robust attribute.
190  * pthread_mutexattr_getrobust_np: the historical name.
191  */
192 #pragma weak pthread_mutexattr_getrobust_np = pthread_mutexattr_getrobust
193 int
pthread_mutexattr_getrobust(const pthread_mutexattr_t * attr,int * robust)194 pthread_mutexattr_getrobust(const pthread_mutexattr_t *attr, int *robust)
195 {
196 	mattr_t	*ap;
197 
198 	if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL ||
199 	    robust == NULL)
200 		return (EINVAL);
201 	*robust = ap->robustness;
202 	return (0);
203 }
204 
205 /*
206  * pthread_mutex_init: Initializes the mutex object.  It copies the various
207  * attributes into one type argument and calls mutex_init().  Unlike other
208  * values, the types that are used in the mutex attributes are not 1:1 mapped to
209  * our underlying lock types at this time so we can properly honor the semantics
210  * of someone asking for a PTHREAD_MUTEX_NORMAL lock that must deadlock. The
211  * underlying threads implementation does not do this by default for
212  * USYNC_THREAD and so we don't do this unless explicitly asked for it.
213  */
214 #pragma weak _pthread_mutex_init = pthread_mutex_init
215 int
pthread_mutex_init(pthread_mutex_t * _RESTRICT_KYWD mutex,const pthread_mutexattr_t * _RESTRICT_KYWD attr)216 pthread_mutex_init(pthread_mutex_t *_RESTRICT_KYWD mutex,
217     const pthread_mutexattr_t *_RESTRICT_KYWD attr)
218 {
219 	mattr_t		*ap;
220 	int		type, ret;
221 	int		prioceiling = 0;
222 	uint16_t	flags = 0;
223 
224 	/*
225 	 * All of the pshared, type, protocol, robust attributes
226 	 * translate to bits in the mutex_type field.
227 	 */
228 	if (attr != NULL) {
229 		if ((ap = attr->__pthread_mutexattrp) == NULL)
230 			return (EINVAL);
231 		switch (ap->type) {
232 		case PTHREAD_MUTEX_NORMAL:
233 			type = LOCK_NORMAL;
234 			flags = LOCK_DEADLOCK;
235 			break;
236 		case PTHREAD_MUTEX_ERRORCHECK:
237 			type = LOCK_ERRORCHECK;
238 			break;
239 		case PTHREAD_MUTEX_RECURSIVE:
240 			type = LOCK_RECURSIVE | LOCK_ERRORCHECK;
241 			break;
242 		default:
243 			/*
244 			 * This covers PTHREAD_MUTEX_DEFAULT, which should be
245 			 * the only remaining valid value.
246 			 */
247 			type = LOCK_NORMAL;
248 			break;
249 		}
250 
251 		type |= ap->pshared | ap->protocol | ap->robustness;
252 		if (ap->protocol == PTHREAD_PRIO_PROTECT)
253 			prioceiling = ap->prioceiling;
254 	} else {
255 		type = PTHREAD_PROCESS_PRIVATE | LOCK_NORMAL |
256 		    PTHREAD_PRIO_NONE | PTHREAD_MUTEX_STALLED;
257 	}
258 
259 	/*
260 	 * POSIX mutexes (this interface) make no guarantee about the state of
261 	 * the mutex before pthread_mutex_init(3C) is called.  Sun mutexes, upon
262 	 * which these are built and which mutex_init(3C) below represents
263 	 * require that a robust mutex be initialized to all 0s _prior_ to
264 	 * mutex_init() being called, and that mutex_init() of an initialized
265 	 * mutex return EBUSY.
266 	 *
267 	 * We respect both these behaviors by zeroing the mutex here in the
268 	 * POSIX implementation if and only if the mutex magic is incorrect,
269 	 * and the mutex is robust.
270 	 */
271 	if (((type & PTHREAD_MUTEX_ROBUST) != 0) &&
272 	    (((mutex_t *)mutex)->mutex_magic != MUTEX_MAGIC)) {
273 		(void) memset(mutex, 0, sizeof (*mutex));
274 	}
275 
276 	ret = mutex_init((mutex_t *)mutex, type, &prioceiling);
277 
278 	/*
279 	 * If we have a normal mutex, we need to set that deadlock behavior is
280 	 * required.
281 	 */
282 	if (ret == 0 && flags != 0) {
283 		mutex_t *mp = (mutex_t *)mutex;
284 		mp->mutex_flag |= flags;
285 	}
286 
287 	return (ret);
288 }
289 
290 /*
291  * pthread_mutex_setprioceiling: sets the prioceiling.
292  * From the SUSv3 (POSIX) specification for pthread_mutex_setprioceiling():
293  *	The process of locking the mutex need not
294  *	adhere to the priority protect protocol.
295  * We pass the MUTEX_NOCEIL flag to mutex_lock_internal() so that
296  * a non-realtime thread can successfully execute this operation.
297  */
298 int
pthread_mutex_setprioceiling(pthread_mutex_t * mutex,int ceil,int * oceil)299 pthread_mutex_setprioceiling(pthread_mutex_t *mutex, int ceil, int *oceil)
300 {
301 	mutex_t *mp = (mutex_t *)mutex;
302 	const pcclass_t *pccp = get_info_by_policy(SCHED_FIFO);
303 	int error;
304 
305 	if (!(mp->mutex_type & PTHREAD_PRIO_PROTECT) ||
306 	    ceil < pccp->pcc_primin || ceil > pccp->pcc_primax)
307 		return (EINVAL);
308 	error = mutex_lock_internal(mp, NULL, MUTEX_LOCK | MUTEX_NOCEIL);
309 	if (error == 0 || error == EOWNERDEAD || error == ELOCKUNMAPPED) {
310 		if (oceil)
311 			*oceil = mp->mutex_ceiling;
312 		mp->mutex_ceiling = ceil;
313 		error = mutex_unlock_internal(mp, 1);
314 	}
315 	return (error);
316 }
317 
318 /*
319  * pthread_mutex_getprioceiling: gets the prioceiling.
320  */
321 #pragma weak _pthread_mutex_getprioceiling = pthread_mutex_getprioceiling
322 int
pthread_mutex_getprioceiling(const pthread_mutex_t * mp,int * ceiling)323 pthread_mutex_getprioceiling(const pthread_mutex_t *mp, int *ceiling)
324 {
325 	*ceiling = ((mutex_t *)mp)->mutex_ceiling;
326 	return (0);
327 }
328 
329 /*
330  * UNIX98
331  * pthread_mutexattr_settype: sets the type attribute
332  *
333  * Type attributes are kept in terms of POSIX mutex types until the mutex is
334  * initialized, after which it is translated into the corresponding underlying
335  * lock type.
336  */
337 int
pthread_mutexattr_settype(pthread_mutexattr_t * attr,int type)338 pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
339 {
340 	mattr_t	*ap;
341 
342 	if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL)
343 		return (EINVAL);
344 	switch (type) {
345 	case PTHREAD_MUTEX_NORMAL:
346 	case PTHREAD_MUTEX_ERRORCHECK:
347 	case PTHREAD_MUTEX_RECURSIVE:
348 	case PTHREAD_MUTEX_DEFAULT:
349 		break;
350 	default:
351 		return (EINVAL);
352 	}
353 	ap->type = type;
354 	return (0);
355 }
356 
357 /*
358  * UNIX98
359  * pthread_mutexattr_gettype: gets the type attribute.
360  */
361 int
pthread_mutexattr_gettype(const pthread_mutexattr_t * attr,int * typep)362 pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *typep)
363 {
364 	mattr_t	*ap;
365 	int type;
366 
367 	if (attr == NULL || (ap = attr->__pthread_mutexattrp) == NULL ||
368 	    typep == NULL)
369 		return (EINVAL);
370 	*typep = type;
371 	return (0);
372 }
373