171b3fa15SDavid Xu /*
271b3fa15SDavid Xu  * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
3d3b15642Szrj  * Copyright (c) 2006 David Xu <davidxu@freebsd.org>.
471b3fa15SDavid Xu  * All rights reserved.
571b3fa15SDavid Xu  *
671b3fa15SDavid Xu  * Redistribution and use in source and binary forms, with or without
771b3fa15SDavid Xu  * modification, are permitted provided that the following conditions
871b3fa15SDavid Xu  * are met:
971b3fa15SDavid Xu  * 1. Redistributions of source code must retain the above copyright
1071b3fa15SDavid Xu  *    notice, this list of conditions and the following disclaimer.
1171b3fa15SDavid Xu  * 2. Redistributions in binary form must reproduce the above copyright
1271b3fa15SDavid Xu  *    notice, this list of conditions and the following disclaimer in the
1371b3fa15SDavid Xu  *    documentation and/or other materials provided with the distribution.
1471b3fa15SDavid Xu  * 3. All advertising materials mentioning features or use of this software
1571b3fa15SDavid Xu  *    must display the following acknowledgement:
1671b3fa15SDavid Xu  *	This product includes software developed by John Birrell.
1771b3fa15SDavid Xu  * 4. Neither the name of the author nor the names of any co-contributors
1871b3fa15SDavid Xu  *    may be used to endorse or promote products derived from this software
1971b3fa15SDavid Xu  *    without specific prior written permission.
2071b3fa15SDavid Xu  *
2171b3fa15SDavid Xu  * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
2271b3fa15SDavid Xu  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2371b3fa15SDavid Xu  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2471b3fa15SDavid Xu  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2571b3fa15SDavid Xu  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2671b3fa15SDavid Xu  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2771b3fa15SDavid Xu  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2871b3fa15SDavid Xu  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2971b3fa15SDavid Xu  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3071b3fa15SDavid Xu  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3171b3fa15SDavid Xu  * SUCH DAMAGE.
3271b3fa15SDavid Xu  *
3371b3fa15SDavid Xu  */
349e2ee207SJoerg Sonnenberger 
35fc71f871SDavid Xu #include "namespace.h"
369e2ee207SJoerg Sonnenberger #include <machine/tls.h>
3771b3fa15SDavid Xu #include <errno.h>
38fc71f871SDavid Xu #include <stdlib.h>
3971b3fa15SDavid Xu #include <string.h>
4071b3fa15SDavid Xu #include <sys/queue.h>
4171b3fa15SDavid Xu #include <pthread.h>
42fc71f871SDavid Xu #include "un-namespace.h"
43fc71f871SDavid Xu 
4471b3fa15SDavid Xu #include "thr_private.h"
4571b3fa15SDavid Xu 
46fcaa7a3aSMatthew Dillon #ifdef _PTHREADS_DEBUGGING
47fcaa7a3aSMatthew Dillon 
48fcaa7a3aSMatthew Dillon #include <stdio.h>
49fcaa7a3aSMatthew Dillon #include <stdarg.h>
50fcaa7a3aSMatthew Dillon #include <sys/file.h>
51fcaa7a3aSMatthew Dillon 
52fcaa7a3aSMatthew Dillon #endif
53fcaa7a3aSMatthew Dillon 
5471b3fa15SDavid Xu #if defined(_PTHREADS_INVARIANTS)
5571b3fa15SDavid Xu #define MUTEX_INIT_LINK(m)		do {		\
5671b3fa15SDavid Xu 	(m)->m_qe.tqe_prev = NULL;			\
5771b3fa15SDavid Xu 	(m)->m_qe.tqe_next = NULL;			\
5871b3fa15SDavid Xu } while (0)
5971b3fa15SDavid Xu #define MUTEX_ASSERT_IS_OWNED(m)	do {		\
6071b3fa15SDavid Xu 	if ((m)->m_qe.tqe_prev == NULL)			\
6171b3fa15SDavid Xu 		PANIC("mutex is not on list");		\
6271b3fa15SDavid Xu } while (0)
6371b3fa15SDavid Xu #define MUTEX_ASSERT_NOT_OWNED(m)	do {		\
6471b3fa15SDavid Xu 	if (((m)->m_qe.tqe_prev != NULL) ||		\
6571b3fa15SDavid Xu 	    ((m)->m_qe.tqe_next != NULL))		\
6671b3fa15SDavid Xu 		PANIC("mutex is on list");		\
6771b3fa15SDavid Xu } while (0)
6871b3fa15SDavid Xu #define	THR_ASSERT_NOT_IN_SYNCQ(thr)	do {		\
6971b3fa15SDavid Xu 	THR_ASSERT(((thr)->sflags & THR_FLAGS_IN_SYNCQ) == 0, \
7071b3fa15SDavid Xu 	    "thread in syncq when it shouldn't be.");	\
7171b3fa15SDavid Xu } while (0);
7271b3fa15SDavid Xu #else
7371b3fa15SDavid Xu #define MUTEX_INIT_LINK(m)
7471b3fa15SDavid Xu #define MUTEX_ASSERT_IS_OWNED(m)
7571b3fa15SDavid Xu #define MUTEX_ASSERT_NOT_OWNED(m)
7671b3fa15SDavid Xu #define	THR_ASSERT_NOT_IN_SYNCQ(thr)
7771b3fa15SDavid Xu #endif
7871b3fa15SDavid Xu 
7971b3fa15SDavid Xu #define THR_IN_MUTEXQ(thr)	(((thr)->sflags & THR_FLAGS_IN_SYNCQ) != 0)
8071b3fa15SDavid Xu #define	MUTEX_DESTROY(m) do {		\
81e7bf3f77SMatthew Dillon 	__free(m);			\
8271b3fa15SDavid Xu } while (0)
8371b3fa15SDavid Xu 
84e8382b15SDavid Xu umtx_t	_mutex_static_lock;
8571b3fa15SDavid Xu 
86fcaa7a3aSMatthew Dillon #ifdef _PTHREADS_DEBUGGING
87fcaa7a3aSMatthew Dillon 
88fcaa7a3aSMatthew Dillon static
89fcaa7a3aSMatthew Dillon void
mutex_log(const char * ctl,...)90fcaa7a3aSMatthew Dillon mutex_log(const char *ctl, ...)
91fcaa7a3aSMatthew Dillon {
92fcaa7a3aSMatthew Dillon 	char buf[256];
93fcaa7a3aSMatthew Dillon 	va_list va;
94fcaa7a3aSMatthew Dillon 	size_t len;
95fcaa7a3aSMatthew Dillon 
96fcaa7a3aSMatthew Dillon 	va_start(va, ctl);
97fcaa7a3aSMatthew Dillon 	len = vsnprintf(buf, sizeof(buf), ctl, va);
98fcaa7a3aSMatthew Dillon 	va_end(va);
99fcaa7a3aSMatthew Dillon 	_thr_log(buf, len);
100fcaa7a3aSMatthew Dillon }
101fcaa7a3aSMatthew Dillon 
102fcaa7a3aSMatthew Dillon #else
103fcaa7a3aSMatthew Dillon 
104fcaa7a3aSMatthew Dillon static __inline
105fcaa7a3aSMatthew Dillon void
mutex_log(const char * ctl __unused,...)106fcaa7a3aSMatthew Dillon mutex_log(const char *ctl __unused, ...)
107fcaa7a3aSMatthew Dillon {
108fcaa7a3aSMatthew Dillon }
109fcaa7a3aSMatthew Dillon 
110fcaa7a3aSMatthew Dillon #endif
111fcaa7a3aSMatthew Dillon 
112fcaa7a3aSMatthew Dillon #ifdef _PTHREADS_DEBUGGING2
113fcaa7a3aSMatthew Dillon 
114fcaa7a3aSMatthew Dillon static void
mutex_log2(pthread_t curthread,pthread_mutex_t m,int op)115940be950Szrj mutex_log2(pthread_t curthread, pthread_mutex_t m, int op)
116fcaa7a3aSMatthew Dillon {
117fcaa7a3aSMatthew Dillon 	if (curthread) {
118fcaa7a3aSMatthew Dillon 		if (curthread->tid < 32)
119fcaa7a3aSMatthew Dillon 			m->m_lastop[curthread->tid] =
120fcaa7a3aSMatthew Dillon 				(__sys_getpid() << 16) | op;
121fcaa7a3aSMatthew Dillon 	} else {
122fcaa7a3aSMatthew Dillon 			m->m_lastop[0] =
123fcaa7a3aSMatthew Dillon 				(__sys_getpid() << 16) | op;
124fcaa7a3aSMatthew Dillon 	}
125fcaa7a3aSMatthew Dillon }
126fcaa7a3aSMatthew Dillon 
127fcaa7a3aSMatthew Dillon #else
128fcaa7a3aSMatthew Dillon 
129fcaa7a3aSMatthew Dillon static __inline
130fcaa7a3aSMatthew Dillon void
mutex_log2(pthread_t curthread __unused,pthread_mutex_t m __unused,int op __unused)131940be950Szrj mutex_log2(pthread_t curthread __unused,
132940be950Szrj 	   pthread_mutex_t m __unused, int op __unused)
133fcaa7a3aSMatthew Dillon {
134fcaa7a3aSMatthew Dillon }
135fcaa7a3aSMatthew Dillon 
136fcaa7a3aSMatthew Dillon #endif
137fcaa7a3aSMatthew Dillon 
13871b3fa15SDavid Xu /*
13971b3fa15SDavid Xu  * Prototypes
14071b3fa15SDavid Xu  */
141fc71f871SDavid Xu static int	mutex_self_trylock(pthread_mutex_t);
142fc71f871SDavid Xu static int	mutex_self_lock(pthread_mutex_t,
14371b3fa15SDavid Xu 			const struct timespec *abstime);
144f84e38f4SDavid Xu static int	mutex_unlock_common(pthread_mutex_t *);
14571b3fa15SDavid Xu 
146fc71f871SDavid Xu int __pthread_mutex_init(pthread_mutex_t *mutex,
147fc71f871SDavid Xu 	const pthread_mutexattr_t *mutex_attr);
148fc71f871SDavid Xu int __pthread_mutex_trylock(pthread_mutex_t *mutex);
149fc71f871SDavid Xu int __pthread_mutex_lock(pthread_mutex_t *mutex);
150fc71f871SDavid Xu int __pthread_mutex_timedlock(pthread_mutex_t *mutex,
151fc71f871SDavid Xu 	const struct timespec *abs_timeout);
152fc71f871SDavid Xu 
15371b3fa15SDavid Xu static int
mutex_check_attr(const struct __pthread_mutexattr_s * attr)154*cf8046a9Szrj mutex_check_attr(const struct __pthread_mutexattr_s *attr)
15571b3fa15SDavid Xu {
156113768d8SDavid Xu 	if (attr->m_type < PTHREAD_MUTEX_ERRORCHECK ||
157b8ee06c5Szrj 	    attr->m_type >= PTHREAD_MUTEX_TYPE_MAX)
158113768d8SDavid Xu 		return (EINVAL);
159113768d8SDavid Xu 	if (attr->m_protocol < PTHREAD_PRIO_NONE ||
160113768d8SDavid Xu 	    attr->m_protocol > PTHREAD_PRIO_PROTECT)
161113768d8SDavid Xu 		return (EINVAL);
162a1f9998fSzrj 	return (0);
16371b3fa15SDavid Xu }
164113768d8SDavid Xu 
165a1f9998fSzrj static void
mutex_init_body(pthread_mutex_t pmutex,const struct __pthread_mutexattr_s * attr,int private)166*cf8046a9Szrj mutex_init_body(pthread_mutex_t pmutex,
167*cf8046a9Szrj     const struct __pthread_mutexattr_s *attr, int private)
168a1f9998fSzrj {
169113768d8SDavid Xu 	_thr_umtx_init(&pmutex->m_lock);
170113768d8SDavid Xu 	pmutex->m_type = attr->m_type;
171113768d8SDavid Xu 	pmutex->m_protocol = attr->m_protocol;
17271b3fa15SDavid Xu 	TAILQ_INIT(&pmutex->m_queue);
173fcaa7a3aSMatthew Dillon 	mutex_log2(tls_get_curthread(), pmutex, 32);
174113768d8SDavid Xu 	pmutex->m_owner = NULL;
175113768d8SDavid Xu 	pmutex->m_flags = attr->m_flags | MUTEX_FLAGS_INITED;
17671b3fa15SDavid Xu 	if (private)
17771b3fa15SDavid Xu 		pmutex->m_flags |= MUTEX_FLAGS_PRIVATE;
178113768d8SDavid Xu 	pmutex->m_count = 0;
17971b3fa15SDavid Xu 	pmutex->m_refcount = 0;
180113768d8SDavid Xu 	if (attr->m_protocol == PTHREAD_PRIO_PROTECT)
181113768d8SDavid Xu 		pmutex->m_prio = attr->m_ceiling;
18271b3fa15SDavid Xu 	else
18371b3fa15SDavid Xu 		pmutex->m_prio = -1;
18471b3fa15SDavid Xu 	pmutex->m_saved_prio = 0;
18571b3fa15SDavid Xu 	MUTEX_INIT_LINK(pmutex);
186a1f9998fSzrj }
187a1f9998fSzrj 
188a1f9998fSzrj static int
mutex_init(pthread_mutex_t * mutex,const pthread_mutexattr_t * mutex_attr,int private)189a1f9998fSzrj mutex_init(pthread_mutex_t *mutex,
190a1f9998fSzrj     const pthread_mutexattr_t *mutex_attr, int private)
191a1f9998fSzrj {
192*cf8046a9Szrj 	const struct __pthread_mutexattr_s *attr;
193*cf8046a9Szrj 	pthread_mutex_t pmutex;
194a1f9998fSzrj 	int error;
195a1f9998fSzrj 
196a1f9998fSzrj 	if (mutex_attr == NULL) {
197a1f9998fSzrj 		attr = &_pthread_mutexattr_default;
198a1f9998fSzrj 	} else {
199a1f9998fSzrj 		attr = *mutex_attr;
200a1f9998fSzrj 		error = mutex_check_attr(attr);
201a1f9998fSzrj 		if (error != 0)
202a1f9998fSzrj 			return (error);
203a1f9998fSzrj 	}
204e7bf3f77SMatthew Dillon 
205*cf8046a9Szrj 	pmutex = __malloc(sizeof(struct __pthread_mutex_s));
206e7bf3f77SMatthew Dillon 	if (pmutex == NULL)
207a1f9998fSzrj 		return (ENOMEM);
208a1f9998fSzrj 	mutex_init_body(pmutex, attr, private);
20971b3fa15SDavid Xu 	*mutex = pmutex;
210113768d8SDavid Xu 	return (0);
21171b3fa15SDavid Xu }
21271b3fa15SDavid Xu 
21371b3fa15SDavid Xu static int
init_static(pthread_t thread,pthread_mutex_t * mutex)214940be950Szrj init_static(pthread_t thread, pthread_mutex_t *mutex)
21571b3fa15SDavid Xu {
21671b3fa15SDavid Xu 	int ret;
21771b3fa15SDavid Xu 
21871b3fa15SDavid Xu 	THR_LOCK_ACQUIRE(thread, &_mutex_static_lock);
21971b3fa15SDavid Xu 
22071b3fa15SDavid Xu 	if (*mutex == NULL)
22171b3fa15SDavid Xu 		ret = mutex_init(mutex, NULL, 0);
22271b3fa15SDavid Xu 	else
22371b3fa15SDavid Xu 		ret = 0;
22471b3fa15SDavid Xu 	THR_LOCK_RELEASE(thread, &_mutex_static_lock);
22571b3fa15SDavid Xu 
22671b3fa15SDavid Xu 	return (ret);
22771b3fa15SDavid Xu }
22871b3fa15SDavid Xu 
22971b3fa15SDavid Xu static int
init_static_private(pthread_t thread,pthread_mutex_t * mutex)230940be950Szrj init_static_private(pthread_t thread, pthread_mutex_t *mutex)
23171b3fa15SDavid Xu {
23271b3fa15SDavid Xu 	int ret;
23371b3fa15SDavid Xu 
23471b3fa15SDavid Xu 	THR_LOCK_ACQUIRE(thread, &_mutex_static_lock);
23571b3fa15SDavid Xu 
23671b3fa15SDavid Xu 	if (*mutex == NULL)
23771b3fa15SDavid Xu 		ret = mutex_init(mutex, NULL, 1);
23871b3fa15SDavid Xu 	else
23971b3fa15SDavid Xu 		ret = 0;
24071b3fa15SDavid Xu 
24171b3fa15SDavid Xu 	THR_LOCK_RELEASE(thread, &_mutex_static_lock);
24271b3fa15SDavid Xu 
24371b3fa15SDavid Xu 	return (ret);
24471b3fa15SDavid Xu }
24571b3fa15SDavid Xu 
24671b3fa15SDavid Xu int
_pthread_mutex_init(pthread_mutex_t * __restrict mutex,const pthread_mutexattr_t * __restrict mutex_attr)247d33005aaSSascha Wildner _pthread_mutex_init(pthread_mutex_t * __restrict mutex,
248d33005aaSSascha Wildner     const pthread_mutexattr_t * __restrict mutex_attr)
24971b3fa15SDavid Xu {
25071b3fa15SDavid Xu 	return mutex_init(mutex, mutex_attr, 1);
25171b3fa15SDavid Xu }
25271b3fa15SDavid Xu 
25371b3fa15SDavid Xu int
__pthread_mutex_init(pthread_mutex_t * mutex,const pthread_mutexattr_t * mutex_attr)25471b3fa15SDavid Xu __pthread_mutex_init(pthread_mutex_t *mutex,
25571b3fa15SDavid Xu     const pthread_mutexattr_t *mutex_attr)
25671b3fa15SDavid Xu {
25771b3fa15SDavid Xu 	return mutex_init(mutex, mutex_attr, 0);
25871b3fa15SDavid Xu }
25971b3fa15SDavid Xu 
260fcaa7a3aSMatthew Dillon #if 0
26171b3fa15SDavid Xu int
262fcaa7a3aSMatthew Dillon _mutex_reinit(pthread_mutex_t *mutexp)
26371b3fa15SDavid Xu {
264fcaa7a3aSMatthew Dillon 	pthread_mutex_t mutex = *mutexp;
265fcaa7a3aSMatthew Dillon 
266fcaa7a3aSMatthew Dillon 	_thr_umtx_init(&mutex->m_lock);
267fcaa7a3aSMatthew Dillon 	TAILQ_INIT(&mutex->m_queue);
268fcaa7a3aSMatthew Dillon 	MUTEX_INIT_LINK(mutex);
269fcaa7a3aSMatthew Dillon 	mutex_log2(tls_get_curthread(), mutex, 33);
270fcaa7a3aSMatthew Dillon 	mutex->m_owner = NULL;
271fcaa7a3aSMatthew Dillon 	mutex->m_count = 0;
272fcaa7a3aSMatthew Dillon 	mutex->m_refcount = 0;
273fcaa7a3aSMatthew Dillon 	mutex->m_prio = 0;
274fcaa7a3aSMatthew Dillon 	mutex->m_saved_prio = 0;
275fcaa7a3aSMatthew Dillon 
27671b3fa15SDavid Xu 	return (0);
27771b3fa15SDavid Xu }
278fcaa7a3aSMatthew Dillon #endif
27971b3fa15SDavid Xu 
28071b3fa15SDavid Xu void
_mutex_fork(pthread_t curthread,lwpid_t tid)281940be950Szrj _mutex_fork(pthread_t curthread, lwpid_t tid)
28271b3fa15SDavid Xu {
283940be950Szrj 	pthread_mutex_t m;
28471b3fa15SDavid Xu 
28571b3fa15SDavid Xu 	TAILQ_FOREACH(m, &curthread->mutexq, m_qe)
2864cc8110fSMatthew Dillon 		m->m_lock = tid;
28771b3fa15SDavid Xu }
28871b3fa15SDavid Xu 
28971b3fa15SDavid Xu int
_pthread_mutex_destroy(pthread_mutex_t * mutex)29071b3fa15SDavid Xu _pthread_mutex_destroy(pthread_mutex_t *mutex)
29171b3fa15SDavid Xu {
292940be950Szrj 	pthread_t curthread = tls_get_curthread();
29371b3fa15SDavid Xu 	pthread_mutex_t m;
29471b3fa15SDavid Xu 	int ret = 0;
29571b3fa15SDavid Xu 
296fcaa7a3aSMatthew Dillon 	if (mutex == NULL) {
29771b3fa15SDavid Xu 		ret = EINVAL;
298fcaa7a3aSMatthew Dillon 	} else if (*mutex == NULL) {
299146da5fcSMichael Neumann 		ret = 0;
300fcaa7a3aSMatthew Dillon 	} else {
30171b3fa15SDavid Xu 		/*
30271b3fa15SDavid Xu 		 * Try to lock the mutex structure, we only need to
303fcaa7a3aSMatthew Dillon 		 * try once, if failed, the mutex is in use.
30471b3fa15SDavid Xu 		 */
305721505deSMatthew Dillon 		ret = THR_UMTX_TRYLOCK_PERSIST(curthread, &(*mutex)->m_lock);
30671b3fa15SDavid Xu 		if (ret)
30771b3fa15SDavid Xu 			return (ret);
30871b3fa15SDavid Xu 
30971b3fa15SDavid Xu 		/*
31071b3fa15SDavid Xu 		 * Check mutex other fields to see if this mutex is
31171b3fa15SDavid Xu 		 * in use. Mostly for prority mutex types, or there
31271b3fa15SDavid Xu 		 * are condition variables referencing it.
31371b3fa15SDavid Xu 		 */
31471b3fa15SDavid Xu 		if (((*mutex)->m_owner != NULL) ||
31571b3fa15SDavid Xu 		    (TAILQ_FIRST(&(*mutex)->m_queue) != NULL) ||
31671b3fa15SDavid Xu 		    ((*mutex)->m_refcount != 0)) {
317721505deSMatthew Dillon 			THR_UMTX_UNLOCK_PERSIST(curthread, &(*mutex)->m_lock);
31871b3fa15SDavid Xu 			ret = EBUSY;
31971b3fa15SDavid Xu 		} else {
32071b3fa15SDavid Xu 			/*
32171b3fa15SDavid Xu 			 * Save a pointer to the mutex so it can be free'd
32271b3fa15SDavid Xu 			 * and set the caller's pointer to NULL:
32371b3fa15SDavid Xu 			 */
32471b3fa15SDavid Xu 			m = *mutex;
32571b3fa15SDavid Xu 			*mutex = NULL;
32671b3fa15SDavid Xu 
32771b3fa15SDavid Xu 			/* Unlock the mutex structure: */
328721505deSMatthew Dillon 			THR_UMTX_UNLOCK_PERSIST(curthread, &m->m_lock);
32971b3fa15SDavid Xu 
33071b3fa15SDavid Xu 			/*
33171b3fa15SDavid Xu 			 * Free the memory allocated for the mutex
33271b3fa15SDavid Xu 			 * structure:
33371b3fa15SDavid Xu 			 */
33471b3fa15SDavid Xu 			MUTEX_ASSERT_NOT_OWNED(m);
33571b3fa15SDavid Xu 			MUTEX_DESTROY(m);
33671b3fa15SDavid Xu 		}
33771b3fa15SDavid Xu 	}
33871b3fa15SDavid Xu 
33971b3fa15SDavid Xu 	/* Return the completion status: */
34071b3fa15SDavid Xu 	return (ret);
34171b3fa15SDavid Xu }
34271b3fa15SDavid Xu 
34371b3fa15SDavid Xu static int
mutex_trylock_common(pthread_t curthread,pthread_mutex_t * mutex)344940be950Szrj mutex_trylock_common(pthread_t curthread, pthread_mutex_t *mutex)
34571b3fa15SDavid Xu {
346940be950Szrj 	pthread_mutex_t m;
347a4472baeSDavid Xu 	int ret;
34871b3fa15SDavid Xu 
349a4472baeSDavid Xu 	m = *mutex;
350fcaa7a3aSMatthew Dillon 	mutex_log("mutex_lock_trylock_common %p\n", m);
351721505deSMatthew Dillon 	ret = THR_UMTX_TRYLOCK_PERSIST(curthread, &m->m_lock);
35271b3fa15SDavid Xu 	if (ret == 0) {
353fcaa7a3aSMatthew Dillon 		mutex_log2(curthread, m, 1);
354a4472baeSDavid Xu 		m->m_owner = curthread;
35571b3fa15SDavid Xu 		/* Add to the list of owned mutexes: */
356a4472baeSDavid Xu 		MUTEX_ASSERT_NOT_OWNED(m);
357fcaa7a3aSMatthew Dillon 		TAILQ_INSERT_TAIL(&curthread->mutexq, m, m_qe);
358a4472baeSDavid Xu 	} else if (m->m_owner == curthread) {
359fcaa7a3aSMatthew Dillon 		mutex_log2(curthread, m, 2);
360a4472baeSDavid Xu 		ret = mutex_self_trylock(m);
36171b3fa15SDavid Xu 	} /* else {} */
362fcaa7a3aSMatthew Dillon 	mutex_log("mutex_lock_trylock_common %p (returns %d)\n", m, ret);
36371b3fa15SDavid Xu 
36471b3fa15SDavid Xu 	return (ret);
36571b3fa15SDavid Xu }
36671b3fa15SDavid Xu 
36771b3fa15SDavid Xu int
__pthread_mutex_trylock(pthread_mutex_t * m)368a4472baeSDavid Xu __pthread_mutex_trylock(pthread_mutex_t *m)
36971b3fa15SDavid Xu {
370940be950Szrj 	pthread_t curthread = tls_get_curthread();
371a4472baeSDavid Xu 	int ret;
37271b3fa15SDavid Xu 
3738db03831SMatthew Dillon 	if (__predict_false(m == NULL))
3748db03831SMatthew Dillon 		return(EINVAL);
37571b3fa15SDavid Xu 	/*
37671b3fa15SDavid Xu 	 * If the mutex is statically initialized, perform the dynamic
37771b3fa15SDavid Xu 	 * initialization:
37871b3fa15SDavid Xu 	 */
379a4472baeSDavid Xu 	if (__predict_false(*m == NULL)) {
380a4472baeSDavid Xu 		ret = init_static(curthread, m);
381f84e38f4SDavid Xu 		if (__predict_false(ret != 0))
38271b3fa15SDavid Xu 			return (ret);
38371b3fa15SDavid Xu 	}
384a4472baeSDavid Xu 	return (mutex_trylock_common(curthread, m));
385a4472baeSDavid Xu }
38671b3fa15SDavid Xu 
38771b3fa15SDavid Xu int
_pthread_mutex_trylock(pthread_mutex_t * m)388a4472baeSDavid Xu _pthread_mutex_trylock(pthread_mutex_t *m)
38971b3fa15SDavid Xu {
390940be950Szrj 	pthread_t curthread = tls_get_curthread();
39171b3fa15SDavid Xu 	int	ret = 0;
39271b3fa15SDavid Xu 
39371b3fa15SDavid Xu 	/*
39471b3fa15SDavid Xu 	 * If the mutex is statically initialized, perform the dynamic
39571b3fa15SDavid Xu 	 * initialization marking the mutex private (delete safe):
39671b3fa15SDavid Xu 	 */
397a4472baeSDavid Xu 	if (__predict_false(*m == NULL)) {
398a4472baeSDavid Xu 		ret = init_static_private(curthread, m);
399f84e38f4SDavid Xu 		if (__predict_false(ret != 0))
40071b3fa15SDavid Xu 			return (ret);
40171b3fa15SDavid Xu 	}
402a4472baeSDavid Xu 	return (mutex_trylock_common(curthread, m));
403a4472baeSDavid Xu }
40471b3fa15SDavid Xu 
40571b3fa15SDavid Xu static int
mutex_lock_common(pthread_t curthread,pthread_mutex_t * mutex,const struct timespec * abstime)406940be950Szrj mutex_lock_common(pthread_t curthread, pthread_mutex_t *mutex,
40771b3fa15SDavid Xu 	const struct timespec * abstime)
40871b3fa15SDavid Xu {
40971b3fa15SDavid Xu 	struct  timespec ts, ts2;
410940be950Szrj 	pthread_mutex_t m;
41171b3fa15SDavid Xu 	int	ret = 0;
41271b3fa15SDavid Xu 
413a4472baeSDavid Xu 	m = *mutex;
414fcaa7a3aSMatthew Dillon 	mutex_log("mutex_lock_common %p\n", m);
415721505deSMatthew Dillon 	ret = THR_UMTX_TRYLOCK_PERSIST(curthread, &m->m_lock);
41671b3fa15SDavid Xu 	if (ret == 0) {
417fcaa7a3aSMatthew Dillon 		mutex_log2(curthread, m, 3);
418a4472baeSDavid Xu 		m->m_owner = curthread;
41971b3fa15SDavid Xu 		/* Add to the list of owned mutexes: */
420a4472baeSDavid Xu 		MUTEX_ASSERT_NOT_OWNED(m);
421fcaa7a3aSMatthew Dillon 		TAILQ_INSERT_TAIL(&curthread->mutexq, m, m_qe);
422a4472baeSDavid Xu 	} else if (m->m_owner == curthread) {
423a4472baeSDavid Xu 		ret = mutex_self_lock(m, abstime);
42471b3fa15SDavid Xu 	} else {
42571b3fa15SDavid Xu 		if (abstime == NULL) {
426721505deSMatthew Dillon 			THR_UMTX_LOCK_PERSIST(curthread, &m->m_lock);
42771b3fa15SDavid Xu 			ret = 0;
428a4472baeSDavid Xu 		} else if (__predict_false(
429a4472baeSDavid Xu 			abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
430a4472baeSDavid Xu 			abstime->tv_nsec >= 1000000000)) {
431a4472baeSDavid Xu 				ret = EINVAL;
43271b3fa15SDavid Xu 		} else {
43371b3fa15SDavid Xu 			clock_gettime(CLOCK_REALTIME, &ts);
434ce96aca2SSascha Wildner 			timespecsub(abstime, &ts, &ts2);
435721505deSMatthew Dillon 			ret = THR_UMTX_TIMEDLOCK_PERSIST(curthread,
436721505deSMatthew Dillon 							 &m->m_lock, &ts2);
43771b3fa15SDavid Xu 		}
43871b3fa15SDavid Xu 		if (ret == 0) {
439fcaa7a3aSMatthew Dillon 			mutex_log2(curthread, m, 4);
440a4472baeSDavid Xu 			m->m_owner = curthread;
44171b3fa15SDavid Xu 			/* Add to the list of owned mutexes: */
442a4472baeSDavid Xu 			MUTEX_ASSERT_NOT_OWNED(m);
443fcaa7a3aSMatthew Dillon 			TAILQ_INSERT_TAIL(&curthread->mutexq, m, m_qe);
44471b3fa15SDavid Xu 		}
44571b3fa15SDavid Xu 	}
446fcaa7a3aSMatthew Dillon 	mutex_log("mutex_lock_common %p (returns %d) lock %d,%d\n",
447fcaa7a3aSMatthew Dillon 		  m, ret, m->m_lock, m->m_count);
44871b3fa15SDavid Xu 	return (ret);
44971b3fa15SDavid Xu }
45071b3fa15SDavid Xu 
45171b3fa15SDavid Xu int
__pthread_mutex_lock(pthread_mutex_t * m)45271b3fa15SDavid Xu __pthread_mutex_lock(pthread_mutex_t *m)
45371b3fa15SDavid Xu {
454940be950Szrj 	pthread_t curthread;
455a4472baeSDavid Xu 	int	ret;
45671b3fa15SDavid Xu 
4578db03831SMatthew Dillon 	if (__predict_false(m == NULL))
4588db03831SMatthew Dillon 		return(EINVAL);
45971b3fa15SDavid Xu 
46071b3fa15SDavid Xu 	/*
46171b3fa15SDavid Xu 	 * If the mutex is statically initialized, perform the dynamic
46271b3fa15SDavid Xu 	 * initialization:
46371b3fa15SDavid Xu 	 */
4648db03831SMatthew Dillon 	curthread = tls_get_curthread();
465a4472baeSDavid Xu 	if (__predict_false(*m == NULL)) {
466a4472baeSDavid Xu 		ret = init_static(curthread, m);
467a4472baeSDavid Xu 		if (__predict_false(ret))
46871b3fa15SDavid Xu 			return (ret);
46971b3fa15SDavid Xu 	}
470a4472baeSDavid Xu 	return (mutex_lock_common(curthread, m, NULL));
471a4472baeSDavid Xu }
47271b3fa15SDavid Xu 
47371b3fa15SDavid Xu int
_pthread_mutex_lock(pthread_mutex_t * m)47471b3fa15SDavid Xu _pthread_mutex_lock(pthread_mutex_t *m)
47571b3fa15SDavid Xu {
476940be950Szrj 	pthread_t curthread;
477a4472baeSDavid Xu 	int	ret;
47871b3fa15SDavid Xu 
4798b03c2a2Szrj 	_thr_check_init();
4808b03c2a2Szrj 
4818db03831SMatthew Dillon 	if (__predict_false(m == NULL))
4828db03831SMatthew Dillon 		return(EINVAL);
48371b3fa15SDavid Xu 
48471b3fa15SDavid Xu 	/*
48571b3fa15SDavid Xu 	 * If the mutex is statically initialized, perform the dynamic
48671b3fa15SDavid Xu 	 * initialization marking it private (delete safe):
48771b3fa15SDavid Xu 	 */
4888db03831SMatthew Dillon 	curthread = tls_get_curthread();
489a4472baeSDavid Xu 	if (__predict_false(*m == NULL)) {
490a4472baeSDavid Xu 		ret = init_static_private(curthread, m);
491a4472baeSDavid Xu 		if (__predict_false(ret))
49271b3fa15SDavid Xu 			return (ret);
49371b3fa15SDavid Xu 	}
494a4472baeSDavid Xu 	return (mutex_lock_common(curthread, m, NULL));
495a4472baeSDavid Xu }
49671b3fa15SDavid Xu 
49771b3fa15SDavid Xu int
__pthread_mutex_timedlock(pthread_mutex_t * __restrict m,const struct timespec * __restrict abs_timeout)498d33005aaSSascha Wildner __pthread_mutex_timedlock(pthread_mutex_t * __restrict m,
499d33005aaSSascha Wildner     const struct timespec * __restrict abs_timeout)
50071b3fa15SDavid Xu {
501940be950Szrj 	pthread_t curthread;
502a4472baeSDavid Xu 	int	ret;
50371b3fa15SDavid Xu 
5048b03c2a2Szrj 	_thr_check_init();
5058b03c2a2Szrj 
5068db03831SMatthew Dillon 	if (__predict_false(m == NULL))
5078db03831SMatthew Dillon 		return(EINVAL);
50871b3fa15SDavid Xu 
50971b3fa15SDavid Xu 	/*
51071b3fa15SDavid Xu 	 * If the mutex is statically initialized, perform the dynamic
51171b3fa15SDavid Xu 	 * initialization:
51271b3fa15SDavid Xu 	 */
5138db03831SMatthew Dillon 	curthread = tls_get_curthread();
514a4472baeSDavid Xu 	if (__predict_false(*m == NULL)) {
515a4472baeSDavid Xu 		ret = init_static(curthread, m);
516a4472baeSDavid Xu 		if (__predict_false(ret))
51771b3fa15SDavid Xu 			return (ret);
51871b3fa15SDavid Xu 	}
519a4472baeSDavid Xu 	return (mutex_lock_common(curthread, m, abs_timeout));
520a4472baeSDavid Xu }
52171b3fa15SDavid Xu 
52271b3fa15SDavid Xu int
_pthread_mutex_timedlock(pthread_mutex_t * m,const struct timespec * abs_timeout)52371b3fa15SDavid Xu _pthread_mutex_timedlock(pthread_mutex_t *m,
52471b3fa15SDavid Xu 	const struct timespec *abs_timeout)
52571b3fa15SDavid Xu {
526940be950Szrj 	pthread_t curthread;
527a4472baeSDavid Xu 	int	ret;
52871b3fa15SDavid Xu 
5298db03831SMatthew Dillon 	if (__predict_false(m == NULL))
5308db03831SMatthew Dillon 		return(EINVAL);
5318db03831SMatthew Dillon 
5329e2ee207SJoerg Sonnenberger 	curthread = tls_get_curthread();
53371b3fa15SDavid Xu 
53471b3fa15SDavid Xu 	/*
53571b3fa15SDavid Xu 	 * If the mutex is statically initialized, perform the dynamic
53671b3fa15SDavid Xu 	 * initialization marking it private (delete safe):
53771b3fa15SDavid Xu 	 */
538a4472baeSDavid Xu 	if (__predict_false(*m == NULL)) {
539a4472baeSDavid Xu 		ret = init_static_private(curthread, m);
540a4472baeSDavid Xu 		if (__predict_false(ret))
54171b3fa15SDavid Xu 			return (ret);
54271b3fa15SDavid Xu 	}
543a4472baeSDavid Xu 	return (mutex_lock_common(curthread, m, abs_timeout));
544a4472baeSDavid Xu }
54571b3fa15SDavid Xu 
54671b3fa15SDavid Xu int
_pthread_mutex_unlock(pthread_mutex_t * m)54771b3fa15SDavid Xu _pthread_mutex_unlock(pthread_mutex_t *m)
54871b3fa15SDavid Xu {
5498db03831SMatthew Dillon 	if (__predict_false(m == NULL))
5508db03831SMatthew Dillon 		return(EINVAL);
551f84e38f4SDavid Xu 	return (mutex_unlock_common(m));
55271b3fa15SDavid Xu }
55371b3fa15SDavid Xu 
55471b3fa15SDavid Xu static int
mutex_self_trylock(pthread_mutex_t m)555fc71f871SDavid Xu mutex_self_trylock(pthread_mutex_t m)
55671b3fa15SDavid Xu {
55771b3fa15SDavid Xu 	int	ret;
55871b3fa15SDavid Xu 
55971b3fa15SDavid Xu 	switch (m->m_type) {
56071b3fa15SDavid Xu 	/* case PTHREAD_MUTEX_DEFAULT: */
56171b3fa15SDavid Xu 	case PTHREAD_MUTEX_ERRORCHECK:
56271b3fa15SDavid Xu 	case PTHREAD_MUTEX_NORMAL:
56371b3fa15SDavid Xu 		ret = EBUSY;
56471b3fa15SDavid Xu 		break;
56571b3fa15SDavid Xu 
56671b3fa15SDavid Xu 	case PTHREAD_MUTEX_RECURSIVE:
56771b3fa15SDavid Xu 		/* Increment the lock count: */
56871b3fa15SDavid Xu 		if (m->m_count + 1 > 0) {
56971b3fa15SDavid Xu 			m->m_count++;
57071b3fa15SDavid Xu 			ret = 0;
57171b3fa15SDavid Xu 		} else
57271b3fa15SDavid Xu 			ret = EAGAIN;
57371b3fa15SDavid Xu 		break;
57471b3fa15SDavid Xu 
57571b3fa15SDavid Xu 	default:
57671b3fa15SDavid Xu 		/* Trap invalid mutex types; */
57771b3fa15SDavid Xu 		ret = EINVAL;
57871b3fa15SDavid Xu 	}
57971b3fa15SDavid Xu 
58071b3fa15SDavid Xu 	return (ret);
58171b3fa15SDavid Xu }
58271b3fa15SDavid Xu 
58371b3fa15SDavid Xu static int
mutex_self_lock(pthread_mutex_t m,const struct timespec * abstime)584fc71f871SDavid Xu mutex_self_lock(pthread_mutex_t m, const struct timespec *abstime)
58571b3fa15SDavid Xu {
58671b3fa15SDavid Xu 	struct timespec ts1, ts2;
58771b3fa15SDavid Xu 	int ret;
58871b3fa15SDavid Xu 
58971b3fa15SDavid Xu 	switch (m->m_type) {
59071b3fa15SDavid Xu 	/* case PTHREAD_MUTEX_DEFAULT: */
59171b3fa15SDavid Xu 	case PTHREAD_MUTEX_ERRORCHECK:
59271b3fa15SDavid Xu 		if (abstime) {
59371b3fa15SDavid Xu 			clock_gettime(CLOCK_REALTIME, &ts1);
594ce96aca2SSascha Wildner 			timespecsub(abstime, &ts1, &ts2);
59571b3fa15SDavid Xu 			__sys_nanosleep(&ts2, NULL);
59671b3fa15SDavid Xu 			ret = ETIMEDOUT;
59771b3fa15SDavid Xu 		} else {
59871b3fa15SDavid Xu 			/*
59971b3fa15SDavid Xu 			 * POSIX specifies that mutexes should return
60071b3fa15SDavid Xu 			 * EDEADLK if a recursive lock is detected.
60171b3fa15SDavid Xu 			 */
60271b3fa15SDavid Xu 			ret = EDEADLK;
60371b3fa15SDavid Xu 		}
60471b3fa15SDavid Xu 		break;
60571b3fa15SDavid Xu 
60671b3fa15SDavid Xu 	case PTHREAD_MUTEX_NORMAL:
60771b3fa15SDavid Xu 		/*
60871b3fa15SDavid Xu 		 * What SS2 define as a 'normal' mutex.  Intentionally
60971b3fa15SDavid Xu 		 * deadlock on attempts to get a lock you already own.
61071b3fa15SDavid Xu 		 */
61171b3fa15SDavid Xu 		ret = 0;
61271b3fa15SDavid Xu 		if (abstime) {
61371b3fa15SDavid Xu 			clock_gettime(CLOCK_REALTIME, &ts1);
614ce96aca2SSascha Wildner 			timespecsub(abstime, &ts1, &ts2);
61571b3fa15SDavid Xu 			__sys_nanosleep(&ts2, NULL);
61671b3fa15SDavid Xu 			ret = ETIMEDOUT;
61771b3fa15SDavid Xu 		} else {
61871b3fa15SDavid Xu 			ts1.tv_sec = 30;
61971b3fa15SDavid Xu 			ts1.tv_nsec = 0;
62071b3fa15SDavid Xu 			for (;;)
62171b3fa15SDavid Xu 				__sys_nanosleep(&ts1, NULL);
62271b3fa15SDavid Xu 		}
62371b3fa15SDavid Xu 		break;
62471b3fa15SDavid Xu 
62571b3fa15SDavid Xu 	case PTHREAD_MUTEX_RECURSIVE:
62671b3fa15SDavid Xu 		/* Increment the lock count: */
62771b3fa15SDavid Xu 		if (m->m_count + 1 > 0) {
62871b3fa15SDavid Xu 			m->m_count++;
62971b3fa15SDavid Xu 			ret = 0;
63071b3fa15SDavid Xu 		} else
63171b3fa15SDavid Xu 			ret = EAGAIN;
63271b3fa15SDavid Xu 		break;
63371b3fa15SDavid Xu 
63471b3fa15SDavid Xu 	default:
63571b3fa15SDavid Xu 		/* Trap invalid mutex types; */
63671b3fa15SDavid Xu 		ret = EINVAL;
63771b3fa15SDavid Xu 	}
63871b3fa15SDavid Xu 
63971b3fa15SDavid Xu 	return (ret);
64071b3fa15SDavid Xu }
64171b3fa15SDavid Xu 
64271b3fa15SDavid Xu static int
mutex_unlock_common(pthread_mutex_t * mutex)643f84e38f4SDavid Xu mutex_unlock_common(pthread_mutex_t *mutex)
64471b3fa15SDavid Xu {
645940be950Szrj 	pthread_t curthread = tls_get_curthread();
646940be950Szrj 	pthread_mutex_t m;
64771b3fa15SDavid Xu 
648fcaa7a3aSMatthew Dillon 	if (__predict_false((m = *mutex) == NULL)) {
649fcaa7a3aSMatthew Dillon 		mutex_log2(curthread, m, 252);
650a8851a0fSDavid Xu 		return (EINVAL);
651fcaa7a3aSMatthew Dillon 	}
652fcaa7a3aSMatthew Dillon 	mutex_log("mutex_unlock_common %p\n", m);
653fcaa7a3aSMatthew Dillon 	if (__predict_false(m->m_owner != curthread)) {
654fcaa7a3aSMatthew Dillon 		mutex_log("mutex_unlock_common %p (failedA)\n", m);
655fcaa7a3aSMatthew Dillon 		mutex_log2(curthread, m, 253);
656a8851a0fSDavid Xu 		return (EPERM);
657fcaa7a3aSMatthew Dillon 	}
658a8851a0fSDavid Xu 
659fcaa7a3aSMatthew Dillon 	if (__predict_false(m->m_type == PTHREAD_MUTEX_RECURSIVE &&
660a8851a0fSDavid Xu 			    m->m_count > 0)) {
661a8851a0fSDavid Xu 		m->m_count--;
662fcaa7a3aSMatthew Dillon 		mutex_log("mutex_unlock_common %p (returns 0, partial)\n", m);
663fcaa7a3aSMatthew Dillon 		mutex_log2(curthread, m, 254);
66471b3fa15SDavid Xu 	} else {
66571b3fa15SDavid Xu 		/*
666a8851a0fSDavid Xu 		 * Clear the count in case this is a recursive mutex.
66771b3fa15SDavid Xu 		 */
668a8851a0fSDavid Xu 		m->m_count = 0;
669a8851a0fSDavid Xu 		m->m_owner = NULL;
67071b3fa15SDavid Xu 		/* Remove the mutex from the threads queue. */
671a8851a0fSDavid Xu 		MUTEX_ASSERT_IS_OWNED(m);
672a8851a0fSDavid Xu 		TAILQ_REMOVE(&curthread->mutexq, m, m_qe);
673fcaa7a3aSMatthew Dillon 		mutex_log2(tls_get_curthread(), m, 35);
674a8851a0fSDavid Xu 		MUTEX_INIT_LINK(m);
675fcaa7a3aSMatthew Dillon 		mutex_log2(tls_get_curthread(), m, 36);
67671b3fa15SDavid Xu 		/*
677a8851a0fSDavid Xu 		 * Hand off the mutex to the next waiting thread.
67871b3fa15SDavid Xu 		 */
679fcaa7a3aSMatthew Dillon 		mutex_log("mutex_unlock_common %p (returns 0) lock %d\n",
680fcaa7a3aSMatthew Dillon 			  m, m->m_lock);
681721505deSMatthew Dillon 		THR_UMTX_UNLOCK_PERSIST(curthread, &m->m_lock);
682fcaa7a3aSMatthew Dillon 		mutex_log2(tls_get_curthread(), m, 37);
683fcaa7a3aSMatthew Dillon 		mutex_log2(curthread, m, 255);
684e8382b15SDavid Xu 	}
685f84e38f4SDavid Xu 	return (0);
686f84e38f4SDavid Xu }
687f84e38f4SDavid Xu 
688f84e38f4SDavid Xu int
_pthread_mutex_getprioceiling(const pthread_mutex_t * __restrict mutex,int * __restrict prioceiling)6893337d96bSSascha Wildner _pthread_mutex_getprioceiling(const pthread_mutex_t * __restrict mutex,
690d33005aaSSascha Wildner     int * __restrict prioceiling)
691808e48a1Szrj {
692808e48a1Szrj 	if ((mutex == NULL) || (*mutex == NULL))
6938979fd9cSzrj 		return (EINVAL);
6948979fd9cSzrj 	if ((*mutex)->m_protocol != PTHREAD_PRIO_PROTECT)
6958979fd9cSzrj 		return (EINVAL);
696808e48a1Szrj 	*prioceiling = (*mutex)->m_prio;
6978979fd9cSzrj 	return (0);
698808e48a1Szrj }
699808e48a1Szrj 
700808e48a1Szrj int
_pthread_mutex_setprioceiling(pthread_mutex_t * __restrict mutex,int prioceiling,int * __restrict old_ceiling)701d33005aaSSascha Wildner _pthread_mutex_setprioceiling(pthread_mutex_t * __restrict mutex,
702d33005aaSSascha Wildner     int prioceiling, int * __restrict old_ceiling)
703808e48a1Szrj {
704808e48a1Szrj 	int ret = 0;
705808e48a1Szrj 	int tmp;
706808e48a1Szrj 
707808e48a1Szrj 	if ((mutex == NULL) || (*mutex == NULL))
708808e48a1Szrj 		ret = EINVAL;
709808e48a1Szrj 	else if ((*mutex)->m_protocol != PTHREAD_PRIO_PROTECT)
710808e48a1Szrj 		ret = EINVAL;
711808e48a1Szrj 	else if ((ret = _pthread_mutex_lock(mutex)) == 0) {
712808e48a1Szrj 		tmp = (*mutex)->m_prio;
713808e48a1Szrj 		(*mutex)->m_prio = prioceiling;
714808e48a1Szrj 		ret = _pthread_mutex_unlock(mutex);
715808e48a1Szrj 		*old_ceiling = tmp;
716808e48a1Szrj 	}
717808e48a1Szrj 	return(ret);
718808e48a1Szrj }
719808e48a1Szrj 
720808e48a1Szrj int
_mutex_cv_lock(pthread_mutex_t * m,int count)721f84e38f4SDavid Xu _mutex_cv_lock(pthread_mutex_t *m, int count)
722f84e38f4SDavid Xu {
723f84e38f4SDavid Xu 	int	ret;
724f84e38f4SDavid Xu 
725f84e38f4SDavid Xu 	if ((ret = _pthread_mutex_lock(m)) == 0) {
726f84e38f4SDavid Xu 		(*m)->m_refcount--;
727f84e38f4SDavid Xu 		(*m)->m_count += count;
728f84e38f4SDavid Xu 	}
72971b3fa15SDavid Xu 	return (ret);
73071b3fa15SDavid Xu }
73171b3fa15SDavid Xu 
732f84e38f4SDavid Xu int
_mutex_cv_unlock(pthread_mutex_t * mutex,int * count)733f84e38f4SDavid Xu _mutex_cv_unlock(pthread_mutex_t *mutex, int *count)
734f84e38f4SDavid Xu {
735940be950Szrj 	pthread_t curthread = tls_get_curthread();
736940be950Szrj 	pthread_mutex_t m;
737f84e38f4SDavid Xu 
7388db03831SMatthew Dillon 	if (__predict_false(mutex == NULL))
7398db03831SMatthew Dillon 		return (EINVAL);
740f84e38f4SDavid Xu 	if (__predict_false((m = *mutex) == NULL))
741f84e38f4SDavid Xu 		return (EINVAL);
742f84e38f4SDavid Xu 	if (__predict_false(m->m_owner != curthread))
743f84e38f4SDavid Xu 		return (EPERM);
744f84e38f4SDavid Xu 
745f84e38f4SDavid Xu 	*count = m->m_count;
746f84e38f4SDavid Xu 	m->m_count = 0;
747f84e38f4SDavid Xu 	m->m_refcount++;
748fcaa7a3aSMatthew Dillon 	mutex_log2(tls_get_curthread(), m, 45);
749f84e38f4SDavid Xu 	m->m_owner = NULL;
750f84e38f4SDavid Xu 	/* Remove the mutex from the threads queue. */
751f84e38f4SDavid Xu 	MUTEX_ASSERT_IS_OWNED(m);
752f84e38f4SDavid Xu 	TAILQ_REMOVE(&curthread->mutexq, m, m_qe);
753f84e38f4SDavid Xu 	MUTEX_INIT_LINK(m);
754721505deSMatthew Dillon 	THR_UMTX_UNLOCK_PERSIST(curthread, &m->m_lock);
755fcaa7a3aSMatthew Dillon 	mutex_log2(curthread, m, 250);
756f84e38f4SDavid Xu 	return (0);
757f84e38f4SDavid Xu }
758f84e38f4SDavid Xu 
75971b3fa15SDavid Xu void
_mutex_unlock_private(pthread_t pthread)76071b3fa15SDavid Xu _mutex_unlock_private(pthread_t pthread)
76171b3fa15SDavid Xu {
762940be950Szrj 	pthread_mutex_t	m, m_next;
76371b3fa15SDavid Xu 
764e8382b15SDavid Xu 	for (m = TAILQ_FIRST(&pthread->mutexq); m != NULL; m = m_next) {
76571b3fa15SDavid Xu 		m_next = TAILQ_NEXT(m, m_qe);
76671b3fa15SDavid Xu 		if ((m->m_flags & MUTEX_FLAGS_PRIVATE) != 0)
767fc71f871SDavid Xu 			_pthread_mutex_unlock(&m);
76871b3fa15SDavid Xu 	}
76971b3fa15SDavid Xu }
77071b3fa15SDavid Xu 
7715a1048c8SDavid Xu __strong_reference(__pthread_mutex_init, pthread_mutex_init);
7725a1048c8SDavid Xu __strong_reference(__pthread_mutex_lock, pthread_mutex_lock);
7735a1048c8SDavid Xu __strong_reference(__pthread_mutex_timedlock, pthread_mutex_timedlock);
7745a1048c8SDavid Xu __strong_reference(__pthread_mutex_trylock, pthread_mutex_trylock);
7755a1048c8SDavid Xu 
7765a1048c8SDavid Xu /* Single underscore versions provided for libc internal usage: */
7775a1048c8SDavid Xu /* No difference between libc and application usage of these: */
7785a1048c8SDavid Xu __strong_reference(_pthread_mutex_destroy, pthread_mutex_destroy);
7795a1048c8SDavid Xu __strong_reference(_pthread_mutex_unlock, pthread_mutex_unlock);
780808e48a1Szrj __strong_reference(_pthread_mutex_getprioceiling, pthread_mutex_getprioceiling);
781808e48a1Szrj __strong_reference(_pthread_mutex_setprioceiling, pthread_mutex_setprioceiling);
782