2 * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by John Birrell.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * $FreeBSD: src/lib/libc_r/uthread/uthread_mutex.c,v 1.20.2.8 2002/10/22 14:44:03 fjoe Exp $
37 #include <sys/param.h>
38 #include <sys/queue.h>
40 #include "pthread_private.h"
42 #if defined(_PTHREADS_INVARIANTS)
43 #define _MUTEX_INIT_LINK(m) do { \
44 (m)->m_qe.tqe_prev = NULL; \
45 (m)->m_qe.tqe_next = NULL; \
47 #define _MUTEX_ASSERT_IS_OWNED(m) do { \
48 if ((m)->m_qe.tqe_prev == NULL) \
49 PANIC("mutex is not on list"); \
51 #define _MUTEX_ASSERT_NOT_OWNED(m) do { \
52 if (((m)->m_qe.tqe_prev != NULL) || \
53 ((m)->m_qe.tqe_next != NULL)) \
54 PANIC("mutex is on list"); \
57 #define _MUTEX_INIT_LINK(m)
58 #define _MUTEX_ASSERT_IS_OWNED(m)
59 #define _MUTEX_ASSERT_NOT_OWNED(m)
65 static inline int mutex_self_trylock(pthread_mutex_t);
66 static inline int mutex_self_lock(pthread_mutex_t);
67 static inline int mutex_unlock_common(pthread_mutex_t *, int);
68 static void mutex_priority_adjust(pthread_mutex_t);
69 static void mutex_rescan_owned (pthread_t, pthread_mutex_t);
70 static inline pthread_t mutex_queue_deq(pthread_mutex_t);
71 static inline void mutex_queue_remove(pthread_mutex_t, pthread_t);
72 static inline void mutex_queue_enq(pthread_mutex_t, pthread_t);
75 static spinlock_t static_init_lock = _SPINLOCK_INITIALIZER;
77 /* Reinitialize a mutex to defaults. */
79 _mutex_reinit(pthread_mutex_t * mutex)
85 else if (*mutex == NULL)
86 ret = pthread_mutex_init(mutex, NULL);
89 * Initialize the mutex structure:
91 (*mutex)->m_type = PTHREAD_MUTEX_DEFAULT;
92 (*mutex)->m_protocol = PTHREAD_PRIO_NONE;
93 TAILQ_INIT(&(*mutex)->m_queue);
94 (*mutex)->m_owner = NULL;
95 (*mutex)->m_data.m_count = 0;
96 (*mutex)->m_flags &= MUTEX_FLAGS_PRIVATE;
97 (*mutex)->m_flags |= MUTEX_FLAGS_INITED;
98 (*mutex)->m_refcount = 0;
100 (*mutex)->m_saved_prio = 0;
101 _MUTEX_INIT_LINK(*mutex);
102 memset(&(*mutex)->lock, 0, sizeof((*mutex)->lock));
108 _pthread_mutex_init(pthread_mutex_t * __restrict mutex,
109 const pthread_mutexattr_t * __restrict mutex_attr)
111 enum pthread_mutextype type;
114 pthread_mutex_t pmutex;
120 /* Check if default mutex attributes: */
121 else if (mutex_attr == NULL || *mutex_attr == NULL) {
122 /* Default to a (error checking) POSIX mutex: */
123 type = PTHREAD_MUTEX_ERRORCHECK;
124 protocol = PTHREAD_PRIO_NONE;
125 ceiling = PTHREAD_MAX_PRIORITY;
128 /* Check mutex type: */
129 else if (((*mutex_attr)->m_type < PTHREAD_MUTEX_ERRORCHECK) ||
130 ((*mutex_attr)->m_type >= PTHREAD_MUTEX_TYPE_MAX))
131 /* Return an invalid argument error: */
134 /* Check mutex protocol: */
135 else if (((*mutex_attr)->m_protocol < PTHREAD_PRIO_NONE) ||
136 ((*mutex_attr)->m_protocol > PTHREAD_MUTEX_RECURSIVE))
137 /* Return an invalid argument error: */
141 /* Use the requested mutex type and protocol: */
142 type = (*mutex_attr)->m_type;
143 protocol = (*mutex_attr)->m_protocol;
144 ceiling = (*mutex_attr)->m_ceiling;
147 /* Check no errors so far: */
149 if ((pmutex = (pthread_mutex_t)
150 malloc(sizeof(struct pthread_mutex))) == NULL)
153 /* Reset the mutex flags: */
156 /* Process according to mutex type: */
158 /* case PTHREAD_MUTEX_DEFAULT: */
159 case PTHREAD_MUTEX_ERRORCHECK:
160 case PTHREAD_MUTEX_NORMAL:
161 /* Nothing to do here. */
164 /* Single UNIX Spec 2 recursive mutex: */
165 case PTHREAD_MUTEX_RECURSIVE:
166 /* Reset the mutex count: */
167 pmutex->m_data.m_count = 0;
170 /* Trap invalid mutex types: */
172 /* Return an invalid argument error: */
177 /* Initialise the rest of the mutex: */
178 TAILQ_INIT(&pmutex->m_queue);
179 pmutex->m_flags |= MUTEX_FLAGS_INITED;
180 pmutex->m_owner = NULL;
181 pmutex->m_type = type;
182 pmutex->m_protocol = protocol;
183 pmutex->m_refcount = 0;
184 if (protocol == PTHREAD_PRIO_PROTECT)
185 pmutex->m_prio = ceiling;
188 pmutex->m_saved_prio = 0;
189 _MUTEX_INIT_LINK(pmutex);
190 memset(&pmutex->lock, 0, sizeof(pmutex->lock));
198 /* Return the completion status: */
203 _pthread_mutex_destroy(pthread_mutex_t * mutex)
207 if (mutex == NULL || *mutex == NULL)
210 /* Lock the mutex structure: */
211 _SPINLOCK(&(*mutex)->lock);
214 * Check to see if this mutex is in use:
216 if (((*mutex)->m_owner != NULL) ||
217 (TAILQ_FIRST(&(*mutex)->m_queue) != NULL) ||
218 ((*mutex)->m_refcount != 0)) {
221 /* Unlock the mutex structure: */
222 _SPINUNLOCK(&(*mutex)->lock);
226 * Free the memory allocated for the mutex
229 _MUTEX_ASSERT_NOT_OWNED(*mutex);
233 * Leave the caller's pointer NULL now that
234 * the mutex has been destroyed:
240 /* Return the completion status: */
245 init_static(pthread_mutex_t *mutex)
249 _SPINLOCK(&static_init_lock);
252 ret = pthread_mutex_init(mutex, NULL);
256 _SPINUNLOCK(&static_init_lock);
262 _pthread_mutex_trylock(pthread_mutex_t * mutex)
264 struct pthread *curthread = _get_curthread();
271 * If the mutex is statically initialized, perform the dynamic
274 else if (*mutex != NULL || (ret = init_static(mutex)) == 0) {
276 * Defer signals to protect the scheduling queues from
277 * access by the signal handler:
279 _thread_kern_sig_defer();
281 /* Lock the mutex structure: */
282 _SPINLOCK(&(*mutex)->lock);
285 * If the mutex was statically allocated, properly
286 * initialize the tail queue.
288 if (((*mutex)->m_flags & MUTEX_FLAGS_INITED) == 0) {
289 TAILQ_INIT(&(*mutex)->m_queue);
290 _MUTEX_INIT_LINK(*mutex);
291 (*mutex)->m_flags |= MUTEX_FLAGS_INITED;
294 /* Process according to mutex type: */
295 switch ((*mutex)->m_protocol) {
296 /* Default POSIX mutex: */
297 case PTHREAD_PRIO_NONE:
298 /* Check if this mutex is not locked: */
299 if ((*mutex)->m_owner == NULL) {
300 /* Lock the mutex for the running thread: */
301 (*mutex)->m_owner = curthread;
303 /* Add to the list of owned mutexes: */
304 _MUTEX_ASSERT_NOT_OWNED(*mutex);
305 TAILQ_INSERT_TAIL(&curthread->mutexq,
307 } else if ((*mutex)->m_owner == curthread)
308 ret = mutex_self_trylock(*mutex);
310 /* Return a busy error: */
314 /* POSIX priority inheritance mutex: */
315 case PTHREAD_PRIO_INHERIT:
316 /* Check if this mutex is not locked: */
317 if ((*mutex)->m_owner == NULL) {
318 /* Lock the mutex for the running thread: */
319 (*mutex)->m_owner = curthread;
321 /* Track number of priority mutexes owned: */
322 curthread->priority_mutex_count++;
325 * The mutex takes on the attributes of the
326 * running thread when there are no waiters.
328 (*mutex)->m_prio = curthread->active_priority;
329 (*mutex)->m_saved_prio =
330 curthread->inherited_priority;
332 /* Add to the list of owned mutexes: */
333 _MUTEX_ASSERT_NOT_OWNED(*mutex);
334 TAILQ_INSERT_TAIL(&curthread->mutexq,
336 } else if ((*mutex)->m_owner == curthread)
337 ret = mutex_self_trylock(*mutex);
339 /* Return a busy error: */
343 /* POSIX priority protection mutex: */
344 case PTHREAD_PRIO_PROTECT:
345 /* Check for a priority ceiling violation: */
346 if (curthread->active_priority > (*mutex)->m_prio)
349 /* Check if this mutex is not locked: */
350 else if ((*mutex)->m_owner == NULL) {
351 /* Lock the mutex for the running thread: */
352 (*mutex)->m_owner = curthread;
354 /* Track number of priority mutexes owned: */
355 curthread->priority_mutex_count++;
358 * The running thread inherits the ceiling
359 * priority of the mutex and executes at that
362 curthread->active_priority = (*mutex)->m_prio;
363 (*mutex)->m_saved_prio =
364 curthread->inherited_priority;
365 curthread->inherited_priority =
368 /* Add to the list of owned mutexes: */
369 _MUTEX_ASSERT_NOT_OWNED(*mutex);
370 TAILQ_INSERT_TAIL(&curthread->mutexq,
372 } else if ((*mutex)->m_owner == curthread)
373 ret = mutex_self_trylock(*mutex);
375 /* Return a busy error: */
379 /* Trap invalid mutex types: */
381 /* Return an invalid argument error: */
386 /* Unlock the mutex structure: */
387 _SPINUNLOCK(&(*mutex)->lock);
390 * Undefer and handle pending signals, yielding if
393 _thread_kern_sig_undefer();
396 /* Return the completion status: */
401 _pthread_mutex_lock(pthread_mutex_t * mutex)
403 struct pthread *curthread = _get_curthread();
406 if (_thread_initial == NULL)
413 * If the mutex is statically initialized, perform the dynamic
416 if ((*mutex == NULL) &&
417 ((ret = init_static(mutex)) != 0))
420 /* Reset the interrupted flag: */
421 curthread->interrupted = 0;
424 * Enter a loop waiting to become the mutex owner. We need a
425 * loop in case the waiting thread is interrupted by a signal
426 * to execute a signal handler. It is not (currently) possible
427 * to remain in the waiting queue while running a handler.
428 * Instead, the thread is interrupted and backed out of the
429 * waiting queue prior to executing the signal handler.
433 * Defer signals to protect the scheduling queues from
434 * access by the signal handler:
436 _thread_kern_sig_defer();
438 /* Lock the mutex structure: */
439 _SPINLOCK(&(*mutex)->lock);
442 * If the mutex was statically allocated, properly
443 * initialize the tail queue.
445 if (((*mutex)->m_flags & MUTEX_FLAGS_INITED) == 0) {
446 TAILQ_INIT(&(*mutex)->m_queue);
447 (*mutex)->m_flags |= MUTEX_FLAGS_INITED;
448 _MUTEX_INIT_LINK(*mutex);
451 /* Process according to mutex type: */
452 switch ((*mutex)->m_protocol) {
453 /* Default POSIX mutex: */
454 case PTHREAD_PRIO_NONE:
455 if ((*mutex)->m_owner == NULL) {
456 /* Lock the mutex for this thread: */
457 (*mutex)->m_owner = curthread;
459 /* Add to the list of owned mutexes: */
460 _MUTEX_ASSERT_NOT_OWNED(*mutex);
461 TAILQ_INSERT_TAIL(&curthread->mutexq,
464 } else if ((*mutex)->m_owner == curthread)
465 ret = mutex_self_lock(*mutex);
468 * Join the queue of threads waiting to lock
471 mutex_queue_enq(*mutex, curthread);
474 * Keep a pointer to the mutex this thread
477 curthread->data.mutex = *mutex;
480 * Unlock the mutex structure and schedule the
483 _thread_kern_sched_state_unlock(PS_MUTEX_WAIT,
484 &(*mutex)->lock, __FILE__, __LINE__);
486 /* Lock the mutex structure again: */
487 _SPINLOCK(&(*mutex)->lock);
491 /* POSIX priority inheritance mutex: */
492 case PTHREAD_PRIO_INHERIT:
493 /* Check if this mutex is not locked: */
494 if ((*mutex)->m_owner == NULL) {
495 /* Lock the mutex for this thread: */
496 (*mutex)->m_owner = curthread;
498 /* Track number of priority mutexes owned: */
499 curthread->priority_mutex_count++;
502 * The mutex takes on attributes of the
503 * running thread when there are no waiters.
505 (*mutex)->m_prio = curthread->active_priority;
506 (*mutex)->m_saved_prio =
507 curthread->inherited_priority;
508 curthread->inherited_priority =
511 /* Add to the list of owned mutexes: */
512 _MUTEX_ASSERT_NOT_OWNED(*mutex);
513 TAILQ_INSERT_TAIL(&curthread->mutexq,
516 } else if ((*mutex)->m_owner == curthread)
517 ret = mutex_self_lock(*mutex);
520 * Join the queue of threads waiting to lock
523 mutex_queue_enq(*mutex, curthread);
526 * Keep a pointer to the mutex this thread
529 curthread->data.mutex = *mutex;
531 if (curthread->active_priority >
533 /* Adjust priorities: */
534 mutex_priority_adjust(*mutex);
537 * Unlock the mutex structure and schedule the
540 _thread_kern_sched_state_unlock(PS_MUTEX_WAIT,
541 &(*mutex)->lock, __FILE__, __LINE__);
543 /* Lock the mutex structure again: */
544 _SPINLOCK(&(*mutex)->lock);
548 /* POSIX priority protection mutex: */
549 case PTHREAD_PRIO_PROTECT:
550 /* Check for a priority ceiling violation: */
551 if (curthread->active_priority > (*mutex)->m_prio)
554 /* Check if this mutex is not locked: */
555 else if ((*mutex)->m_owner == NULL) {
557 * Lock the mutex for the running
560 (*mutex)->m_owner = curthread;
562 /* Track number of priority mutexes owned: */
563 curthread->priority_mutex_count++;
566 * The running thread inherits the ceiling
567 * priority of the mutex and executes at that
570 curthread->active_priority = (*mutex)->m_prio;
571 (*mutex)->m_saved_prio =
572 curthread->inherited_priority;
573 curthread->inherited_priority =
576 /* Add to the list of owned mutexes: */
577 _MUTEX_ASSERT_NOT_OWNED(*mutex);
578 TAILQ_INSERT_TAIL(&curthread->mutexq,
580 } else if ((*mutex)->m_owner == curthread)
581 ret = mutex_self_lock(*mutex);
584 * Join the queue of threads waiting to lock
587 mutex_queue_enq(*mutex, curthread);
590 * Keep a pointer to the mutex this thread
593 curthread->data.mutex = *mutex;
595 /* Clear any previous error: */
599 * Unlock the mutex structure and schedule the
602 _thread_kern_sched_state_unlock(PS_MUTEX_WAIT,
603 &(*mutex)->lock, __FILE__, __LINE__);
605 /* Lock the mutex structure again: */
606 _SPINLOCK(&(*mutex)->lock);
609 * The threads priority may have changed while
610 * waiting for the mutex causing a ceiling
618 /* Trap invalid mutex types: */
620 /* Return an invalid argument error: */
626 * Check to see if this thread was interrupted and
627 * is still in the mutex queue of waiting threads:
629 if (curthread->interrupted != 0)
630 mutex_queue_remove(*mutex, curthread);
632 /* Unlock the mutex structure: */
633 _SPINUNLOCK(&(*mutex)->lock);
636 * Undefer and handle pending signals, yielding if
639 _thread_kern_sig_undefer();
640 } while (((*mutex)->m_owner != curthread) && (ret == 0) &&
641 (curthread->interrupted == 0));
643 if (curthread->interrupted != 0 &&
644 curthread->continuation != NULL)
645 curthread->continuation((void *) curthread);
647 /* Return the completion status: */
652 _pthread_mutex_unlock(pthread_mutex_t * mutex)
654 return (mutex_unlock_common(mutex, /* add reference */ 0));
658 _mutex_cv_unlock(pthread_mutex_t * mutex)
660 return (mutex_unlock_common(mutex, /* add reference */ 1));
664 _mutex_cv_lock(pthread_mutex_t * mutex)
667 if ((ret = pthread_mutex_lock(mutex)) == 0)
668 (*mutex)->m_refcount--;
673 mutex_self_trylock(pthread_mutex_t mutex)
677 switch (mutex->m_type) {
679 /* case PTHREAD_MUTEX_DEFAULT: */
680 case PTHREAD_MUTEX_ERRORCHECK:
681 case PTHREAD_MUTEX_NORMAL:
683 * POSIX specifies that mutexes should return EDEADLK if a
684 * recursive lock is detected.
689 case PTHREAD_MUTEX_RECURSIVE:
690 /* Increment the lock count: */
691 mutex->m_data.m_count++;
695 /* Trap invalid mutex types; */
703 mutex_self_lock(pthread_mutex_t mutex)
707 switch (mutex->m_type) {
708 /* case PTHREAD_MUTEX_DEFAULT: */
709 case PTHREAD_MUTEX_ERRORCHECK:
711 * POSIX specifies that mutexes should return EDEADLK if a
712 * recursive lock is detected.
717 case PTHREAD_MUTEX_NORMAL:
719 * What SS2 define as a 'normal' mutex. Intentionally
720 * deadlock on attempts to get a lock you already own.
722 _thread_kern_sched_state_unlock(PS_DEADLOCK,
723 &mutex->lock, __FILE__, __LINE__);
726 case PTHREAD_MUTEX_RECURSIVE:
727 /* Increment the lock count: */
728 mutex->m_data.m_count++;
732 /* Trap invalid mutex types; */
740 mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
742 struct pthread *curthread = _get_curthread();
745 if (mutex == NULL || *mutex == NULL) {
749 * Defer signals to protect the scheduling queues from
750 * access by the signal handler:
752 _thread_kern_sig_defer();
754 /* Lock the mutex structure: */
755 _SPINLOCK(&(*mutex)->lock);
757 /* Process according to mutex type: */
758 switch ((*mutex)->m_protocol) {
759 /* Default POSIX mutex: */
760 case PTHREAD_PRIO_NONE:
762 * Check if the running thread is not the owner of the
765 if ((*mutex)->m_owner != curthread) {
767 * Return an invalid argument error for no
768 * owner and a permission error otherwise:
770 ret = (*mutex)->m_owner == NULL ? EINVAL : EPERM;
772 else if (((*mutex)->m_type == PTHREAD_MUTEX_RECURSIVE) &&
773 ((*mutex)->m_data.m_count > 0)) {
774 /* Decrement the count: */
775 (*mutex)->m_data.m_count--;
778 * Clear the count in case this is recursive
781 (*mutex)->m_data.m_count = 0;
783 /* Remove the mutex from the threads queue. */
784 _MUTEX_ASSERT_IS_OWNED(*mutex);
785 TAILQ_REMOVE(&(*mutex)->m_owner->mutexq,
787 _MUTEX_INIT_LINK(*mutex);
790 * Get the next thread from the queue of
791 * threads waiting on the mutex:
793 if (((*mutex)->m_owner =
794 mutex_queue_deq(*mutex)) != NULL) {
795 /* Make the new owner runnable: */
796 PTHREAD_NEW_STATE((*mutex)->m_owner,
800 * Add the mutex to the threads list of
803 TAILQ_INSERT_TAIL(&(*mutex)->m_owner->mutexq,
807 * The owner is no longer waiting for
810 (*mutex)->m_owner->data.mutex = NULL;
815 /* POSIX priority inheritance mutex: */
816 case PTHREAD_PRIO_INHERIT:
818 * Check if the running thread is not the owner of the
821 if ((*mutex)->m_owner != curthread) {
823 * Return an invalid argument error for no
824 * owner and a permission error otherwise:
826 ret = (*mutex)->m_owner == NULL ? EINVAL : EPERM;
828 else if (((*mutex)->m_type == PTHREAD_MUTEX_RECURSIVE) &&
829 ((*mutex)->m_data.m_count > 0)) {
830 /* Decrement the count: */
831 (*mutex)->m_data.m_count--;
834 * Clear the count in case this is recursive
837 (*mutex)->m_data.m_count = 0;
840 * Restore the threads inherited priority and
841 * recompute the active priority (being careful
842 * not to override changes in the threads base
843 * priority subsequent to locking the mutex).
845 curthread->inherited_priority =
846 (*mutex)->m_saved_prio;
847 curthread->active_priority =
848 MAX(curthread->inherited_priority,
849 curthread->base_priority);
852 * This thread now owns one less priority mutex.
854 curthread->priority_mutex_count--;
856 /* Remove the mutex from the threads queue. */
857 _MUTEX_ASSERT_IS_OWNED(*mutex);
858 TAILQ_REMOVE(&(*mutex)->m_owner->mutexq,
860 _MUTEX_INIT_LINK(*mutex);
863 * Get the next thread from the queue of threads
864 * waiting on the mutex:
866 if (((*mutex)->m_owner =
867 mutex_queue_deq(*mutex)) == NULL)
868 /* This mutex has no priority. */
869 (*mutex)->m_prio = 0;
872 * Track number of priority mutexes owned:
874 (*mutex)->m_owner->priority_mutex_count++;
877 * Add the mutex to the threads list
880 TAILQ_INSERT_TAIL(&(*mutex)->m_owner->mutexq,
884 * The owner is no longer waiting for
887 (*mutex)->m_owner->data.mutex = NULL;
890 * Set the priority of the mutex. Since
891 * our waiting threads are in descending
892 * priority order, the priority of the
893 * mutex becomes the active priority of
894 * the thread we just dequeued.
897 (*mutex)->m_owner->active_priority;
900 * Save the owning threads inherited
903 (*mutex)->m_saved_prio =
904 (*mutex)->m_owner->inherited_priority;
907 * The owning threads inherited priority
908 * now becomes his active priority (the
909 * priority of the mutex).
911 (*mutex)->m_owner->inherited_priority =
915 * Make the new owner runnable:
917 PTHREAD_NEW_STATE((*mutex)->m_owner,
923 /* POSIX priority ceiling mutex: */
924 case PTHREAD_PRIO_PROTECT:
926 * Check if the running thread is not the owner of the
929 if ((*mutex)->m_owner != curthread) {
931 * Return an invalid argument error for no
932 * owner and a permission error otherwise:
934 ret = (*mutex)->m_owner == NULL ? EINVAL : EPERM;
936 else if (((*mutex)->m_type == PTHREAD_MUTEX_RECURSIVE) &&
937 ((*mutex)->m_data.m_count > 0)) {
938 /* Decrement the count: */
939 (*mutex)->m_data.m_count--;
942 * Clear the count in case this is recursive
945 (*mutex)->m_data.m_count = 0;
948 * Restore the threads inherited priority and
949 * recompute the active priority (being careful
950 * not to override changes in the threads base
951 * priority subsequent to locking the mutex).
953 curthread->inherited_priority =
954 (*mutex)->m_saved_prio;
955 curthread->active_priority =
956 MAX(curthread->inherited_priority,
957 curthread->base_priority);
960 * This thread now owns one less priority mutex.
962 curthread->priority_mutex_count--;
964 /* Remove the mutex from the threads queue. */
965 _MUTEX_ASSERT_IS_OWNED(*mutex);
966 TAILQ_REMOVE(&(*mutex)->m_owner->mutexq,
968 _MUTEX_INIT_LINK(*mutex);
971 * Enter a loop to find a waiting thread whose
972 * active priority will not cause a ceiling
975 while ((((*mutex)->m_owner =
976 mutex_queue_deq(*mutex)) != NULL) &&
977 ((*mutex)->m_owner->active_priority >
980 * Either the mutex ceiling priority
981 * been lowered and/or this threads
982 * priority has been raised subsequent
983 * to this thread being queued on the
986 tls_set_tcb((*mutex)->m_owner->tcb);
988 tls_set_tcb(curthread->tcb);
989 PTHREAD_NEW_STATE((*mutex)->m_owner,
992 * The thread is no longer waiting for
995 (*mutex)->m_owner->data.mutex = NULL;
998 /* Check for a new owner: */
999 if ((*mutex)->m_owner != NULL) {
1001 * Track number of priority mutexes owned:
1003 (*mutex)->m_owner->priority_mutex_count++;
1006 * Add the mutex to the threads list
1009 TAILQ_INSERT_TAIL(&(*mutex)->m_owner->mutexq,
1013 * The owner is no longer waiting for
1016 (*mutex)->m_owner->data.mutex = NULL;
1019 * Save the owning threads inherited
1022 (*mutex)->m_saved_prio =
1023 (*mutex)->m_owner->inherited_priority;
1026 * The owning thread inherits the
1027 * ceiling priority of the mutex and
1028 * executes at that priority:
1030 (*mutex)->m_owner->inherited_priority =
1032 (*mutex)->m_owner->active_priority =
1036 * Make the new owner runnable:
1038 PTHREAD_NEW_STATE((*mutex)->m_owner,
1044 /* Trap invalid mutex types: */
1046 /* Return an invalid argument error: */
1051 if ((ret == 0) && (add_reference != 0)) {
1052 /* Increment the reference count: */
1053 (*mutex)->m_refcount++;
1056 /* Unlock the mutex structure: */
1057 _SPINUNLOCK(&(*mutex)->lock);
1060 * Undefer and handle pending signals, yielding if
1063 _thread_kern_sig_undefer();
1066 /* Return the completion status: */
1072 * This function is called when a change in base priority occurs for
1073 * a thread that is holding or waiting for a priority protection or
1074 * inheritance mutex. A change in a threads base priority can effect
1075 * changes to active priorities of other threads and to the ordering
1076 * of mutex locking by waiting threads.
1078 * This must be called while thread scheduling is deferred.
1081 _mutex_notify_priochange(pthread_t pthread)
1083 /* Adjust the priorites of any owned priority mutexes: */
1084 if (pthread->priority_mutex_count > 0) {
1086 * Rescan the mutexes owned by this thread and correct
1087 * their priorities to account for this threads change
1088 * in priority. This has the side effect of changing
1089 * the threads active priority.
1091 mutex_rescan_owned(pthread, /* rescan all owned */ NULL);
1095 * If this thread is waiting on a priority inheritance mutex,
1096 * check for priority adjustments. A change in priority can
1097 * also effect a ceiling violation(*) for a thread waiting on
1098 * a priority protection mutex; we don't perform the check here
1099 * as it is done in pthread_mutex_unlock.
1101 * (*) It should be noted that a priority change to a thread
1102 * _after_ taking and owning a priority ceiling mutex
1103 * does not affect ownership of that mutex; the ceiling
1104 * priority is only checked before mutex ownership occurs.
1106 if (pthread->state == PS_MUTEX_WAIT) {
1107 /* Lock the mutex structure: */
1108 _SPINLOCK(&pthread->data.mutex->lock);
1111 * Check to make sure this thread is still in the same state
1112 * (the spinlock above can yield the CPU to another thread):
1114 if (pthread->state == PS_MUTEX_WAIT) {
1116 * Remove and reinsert this thread into the list of
1117 * waiting threads to preserve decreasing priority
1120 mutex_queue_remove(pthread->data.mutex, pthread);
1121 mutex_queue_enq(pthread->data.mutex, pthread);
1123 if (pthread->data.mutex->m_protocol ==
1124 PTHREAD_PRIO_INHERIT) {
1125 /* Adjust priorities: */
1126 mutex_priority_adjust(pthread->data.mutex);
1130 /* Unlock the mutex structure: */
1131 _SPINUNLOCK(&pthread->data.mutex->lock);
1136 * Called when a new thread is added to the mutex waiting queue or
1137 * when a threads priority changes that is already in the mutex
1141 mutex_priority_adjust(pthread_mutex_t mutex)
1143 pthread_t pthread_next, pthread = mutex->m_owner;
1145 pthread_mutex_t m = mutex;
1148 * Calculate the mutex priority as the maximum of the highest
1149 * active priority of any waiting threads and the owning threads
1150 * active priority(*).
1152 * (*) Because the owning threads current active priority may
1153 * reflect priority inherited from this mutex (and the mutex
1154 * priority may have changed) we must recalculate the active
1155 * priority based on the threads saved inherited priority
1156 * and its base priority.
1158 pthread_next = TAILQ_FIRST(&m->m_queue); /* should never be NULL */
1159 temp_prio = MAX(pthread_next->active_priority,
1160 MAX(m->m_saved_prio, pthread->base_priority));
1162 /* See if this mutex really needs adjusting: */
1163 if (temp_prio == m->m_prio)
1164 /* No need to propagate the priority: */
1167 /* Set new priority of the mutex: */
1168 m->m_prio = temp_prio;
1172 * Save the threads priority before rescanning the
1175 temp_prio = pthread->active_priority;
1178 * Fix the priorities for all the mutexes this thread has
1179 * locked since taking this mutex. This also has a
1180 * potential side-effect of changing the threads priority.
1182 mutex_rescan_owned(pthread, m);
1185 * If the thread is currently waiting on a mutex, check
1186 * to see if the threads new priority has affected the
1187 * priority of the mutex.
1189 if ((temp_prio != pthread->active_priority) &&
1190 (pthread->state == PS_MUTEX_WAIT) &&
1191 (pthread->data.mutex->m_protocol == PTHREAD_PRIO_INHERIT)) {
1192 /* Grab the mutex this thread is waiting on: */
1193 m = pthread->data.mutex;
1196 * The priority for this thread has changed. Remove
1197 * and reinsert this thread into the list of waiting
1198 * threads to preserve decreasing priority order.
1200 mutex_queue_remove(m, pthread);
1201 mutex_queue_enq(m, pthread);
1203 /* Grab the waiting thread with highest priority: */
1204 pthread_next = TAILQ_FIRST(&m->m_queue);
1207 * Calculate the mutex priority as the maximum of the
1208 * highest active priority of any waiting threads and
1209 * the owning threads active priority.
1211 temp_prio = MAX(pthread_next->active_priority,
1212 MAX(m->m_saved_prio, m->m_owner->base_priority));
1214 if (temp_prio != m->m_prio) {
1216 * The priority needs to be propagated to the
1217 * mutex this thread is waiting on and up to
1218 * the owner of that mutex.
1220 m->m_prio = temp_prio;
1221 pthread = m->m_owner;
1235 mutex_rescan_owned(pthread_t pthread, pthread_mutex_t mutex)
1237 int active_prio, inherited_prio;
1239 pthread_t pthread_next;
1242 * Start walking the mutexes the thread has taken since
1243 * taking this mutex.
1245 if (mutex == NULL) {
1247 * A null mutex means start at the beginning of the owned
1250 m = TAILQ_FIRST(&pthread->mutexq);
1252 /* There is no inherited priority yet. */
1257 * The caller wants to start after a specific mutex. It
1258 * is assumed that this mutex is a priority inheritance
1259 * mutex and that its priority has been correctly
1262 m = TAILQ_NEXT(mutex, m_qe);
1264 /* Start inheriting priority from the specified mutex. */
1265 inherited_prio = mutex->m_prio;
1267 active_prio = MAX(inherited_prio, pthread->base_priority);
1271 * We only want to deal with priority inheritance
1272 * mutexes. This might be optimized by only placing
1273 * priority inheritance mutexes into the owned mutex
1274 * list, but it may prove to be useful having all
1275 * owned mutexes in this list. Consider a thread
1276 * exiting while holding mutexes...
1278 if (m->m_protocol == PTHREAD_PRIO_INHERIT) {
1280 * Fix the owners saved (inherited) priority to
1281 * reflect the priority of the previous mutex.
1283 m->m_saved_prio = inherited_prio;
1285 if ((pthread_next = TAILQ_FIRST(&m->m_queue)) != NULL)
1286 /* Recalculate the priority of the mutex: */
1287 m->m_prio = MAX(active_prio,
1288 pthread_next->active_priority);
1290 m->m_prio = active_prio;
1292 /* Recalculate new inherited and active priorities: */
1293 inherited_prio = m->m_prio;
1294 active_prio = MAX(m->m_prio, pthread->base_priority);
1297 /* Advance to the next mutex owned by this thread: */
1298 m = TAILQ_NEXT(m, m_qe);
1302 * Fix the threads inherited priority and recalculate its
1305 pthread->inherited_priority = inherited_prio;
1306 active_prio = MAX(inherited_prio, pthread->base_priority);
1308 if (active_prio != pthread->active_priority) {
1310 * If this thread is in the priority queue, it must be
1311 * removed and reinserted for its new priority.
1313 if (pthread->flags & PTHREAD_FLAGS_IN_PRIOQ) {
1315 * Remove the thread from the priority queue
1316 * before changing its priority:
1318 PTHREAD_PRIOQ_REMOVE(pthread);
1321 * POSIX states that if the priority is being
1322 * lowered, the thread must be inserted at the
1323 * head of the queue for its priority if it owns
1324 * any priority protection or inheritance mutexes.
1326 if ((active_prio < pthread->active_priority) &&
1327 (pthread->priority_mutex_count > 0)) {
1328 /* Set the new active priority. */
1329 pthread->active_priority = active_prio;
1331 PTHREAD_PRIOQ_INSERT_HEAD(pthread);
1334 /* Set the new active priority. */
1335 pthread->active_priority = active_prio;
1337 PTHREAD_PRIOQ_INSERT_TAIL(pthread);
1341 /* Set the new active priority. */
1342 pthread->active_priority = active_prio;
1348 _mutex_unlock_private(pthread_t pthread)
1350 struct pthread_mutex *m, *m_next;
1352 for (m = TAILQ_FIRST(&pthread->mutexq); m != NULL; m = m_next) {
1353 m_next = TAILQ_NEXT(m, m_qe);
1354 if ((m->m_flags & MUTEX_FLAGS_PRIVATE) != 0)
1355 pthread_mutex_unlock(&m);
1360 _mutex_lock_backout(pthread_t pthread)
1362 struct pthread_mutex *mutex;
1365 * Defer signals to protect the scheduling queues from
1366 * access by the signal handler:
1368 _thread_kern_sig_defer();
1369 if ((pthread->flags & PTHREAD_FLAGS_IN_MUTEXQ) != 0) {
1370 mutex = pthread->data.mutex;
1372 /* Lock the mutex structure: */
1373 _SPINLOCK(&mutex->lock);
1375 mutex_queue_remove(mutex, pthread);
1377 /* This thread is no longer waiting for the mutex: */
1378 pthread->data.mutex = NULL;
1380 /* Unlock the mutex structure: */
1381 _SPINUNLOCK(&mutex->lock);
1385 * Undefer and handle pending signals, yielding if
1388 _thread_kern_sig_undefer();
1392 * Dequeue a waiting thread from the head of a mutex queue in descending
1395 static inline pthread_t
1396 mutex_queue_deq(pthread_mutex_t mutex)
1400 while ((pthread = TAILQ_FIRST(&mutex->m_queue)) != NULL) {
1401 TAILQ_REMOVE(&mutex->m_queue, pthread, sqe);
1402 pthread->flags &= ~PTHREAD_FLAGS_IN_MUTEXQ;
1405 * Only exit the loop if the thread hasn't been
1408 if (pthread->interrupted == 0)
1416 * Remove a waiting thread from a mutex queue in descending priority order.
1419 mutex_queue_remove(pthread_mutex_t mutex, pthread_t pthread)
1421 if ((pthread->flags & PTHREAD_FLAGS_IN_MUTEXQ) != 0) {
1422 TAILQ_REMOVE(&mutex->m_queue, pthread, sqe);
1423 pthread->flags &= ~PTHREAD_FLAGS_IN_MUTEXQ;
1428 * Enqueue a waiting thread to a queue in descending priority order.
1431 mutex_queue_enq(pthread_mutex_t mutex, pthread_t pthread)
1433 pthread_t tid = TAILQ_LAST(&mutex->m_queue, mutex_head);
1435 PTHREAD_ASSERT_NOT_IN_SYNCQ(pthread);
1437 * For the common case of all threads having equal priority,
1438 * we perform a quick check against the priority of the thread
1439 * at the tail of the queue.
1441 if ((tid == NULL) || (pthread->active_priority <= tid->active_priority))
1442 TAILQ_INSERT_TAIL(&mutex->m_queue, pthread, sqe);
1444 tid = TAILQ_FIRST(&mutex->m_queue);
1445 while (pthread->active_priority <= tid->active_priority)
1446 tid = TAILQ_NEXT(tid, sqe);
1447 TAILQ_INSERT_BEFORE(tid, pthread, sqe);
1449 pthread->flags |= PTHREAD_FLAGS_IN_MUTEXQ;
1452 __strong_reference(_pthread_mutex_init, pthread_mutex_init);
1453 __strong_reference(_pthread_mutex_destroy, pthread_mutex_destroy);
1454 __strong_reference(_pthread_mutex_trylock, pthread_mutex_trylock);
1455 __strong_reference(_pthread_mutex_lock, pthread_mutex_lock);
1456 __strong_reference(_pthread_mutex_unlock, pthread_mutex_unlock);