summaryrefslogtreecommitdiff
path: root/lib/libpthread/uthread/uthread_mutex.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libpthread/uthread/uthread_mutex.c')
-rw-r--r--lib/libpthread/uthread/uthread_mutex.c208
1 files changed, 128 insertions, 80 deletions
diff --git a/lib/libpthread/uthread/uthread_mutex.c b/lib/libpthread/uthread/uthread_mutex.c
index 8cb8760046c..1ddce4f6131 100644
--- a/lib/libpthread/uthread/uthread_mutex.c
+++ b/lib/libpthread/uthread/uthread_mutex.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uthread_mutex.c,v 1.8 1999/06/09 07:06:54 d Exp $ */
+/* $OpenBSD: uthread_mutex.c,v 1.9 1999/11/25 07:01:38 d Exp $ */
/*
* Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
* All rights reserved.
@@ -30,6 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
+ * $FreeBSD: uthread_mutex.c,v 1.16 1999/08/28 00:03:40 peter Exp $
*/
#include <stdlib.h>
#include <errno.h>
@@ -40,6 +41,25 @@
#include <pthread.h>
#include "pthread_private.h"
+#if defined(_PTHREADS_INVARIANTS)
+#define _MUTEX_INIT_LINK(m) do { \
+ (m)->m_qe.tqe_prev = NULL; \
+ (m)->m_qe.tqe_next = NULL; \
+} while (0)
+#define _MUTEX_ASSERT_IS_OWNED(m) do { \
+ if ((m)->m_qe.tqe_prev == NULL) \
+ PANIC("mutex is not on list"); \
+} while (0)
+#define _MUTEX_ASSERT_NOT_OWNED(m) do { \
+ if (((m)->m_qe.tqe_prev != NULL) || \
+ ((m)->m_qe.tqe_next != NULL)) \
+ PANIC("mutex is on list"); \
+} while (0)
+#else
+#define _MUTEX_INIT_LINK(m)
+#define _MUTEX_ASSERT_IS_OWNED(m)
+#define _MUTEX_ASSERT_NOT_OWNED(m)
+#endif
/*
* Prototypes
@@ -56,6 +76,34 @@ static inline void mutex_queue_enq(pthread_mutex_t, pthread_t);
static spinlock_t static_init_lock = _SPINLOCK_INITIALIZER;
+/* Reinitialize a mutex to defaults. */
+int
+_mutex_reinit(pthread_mutex_t * mutex)
+{
+ int ret = 0;
+
+ if (mutex == NULL)
+ ret = EINVAL;
+ else if (*mutex == NULL)
+ ret = pthread_mutex_init(mutex, NULL);
+ else {
+ /*
+ * Initialize the mutex structure:
+ */
+ (*mutex)->m_type = PTHREAD_MUTEX_DEFAULT;
+ (*mutex)->m_protocol = PTHREAD_PRIO_NONE;
+ TAILQ_INIT(&(*mutex)->m_queue);
+ (*mutex)->m_owner = NULL;
+ (*mutex)->m_data.m_count = 0;
+ (*mutex)->m_flags = MUTEX_FLAGS_INITED;
+ (*mutex)->m_refcount = 0;
+ (*mutex)->m_prio = 0;
+ (*mutex)->m_saved_prio = 0;
+ _MUTEX_INIT_LINK(*mutex);
+ _SPINLOCK_INIT(&(*mutex)->lock);
+ }
+ return (ret);
+}
int
pthread_mutex_init(pthread_mutex_t * mutex,
@@ -139,7 +187,8 @@ pthread_mutex_init(pthread_mutex_t * mutex,
else
pmutex->m_prio = 0;
pmutex->m_saved_prio = 0;
- _SPINUNLOCK(&pmutex->lock);
+ _MUTEX_INIT_LINK(pmutex);
+ memset(&pmutex->lock, 0, sizeof(pmutex->lock));
*mutex = pmutex;
} else {
free(pmutex);
@@ -148,7 +197,7 @@ pthread_mutex_init(pthread_mutex_t * mutex,
}
}
/* Return the completion status: */
- return (ret);
+ return(ret);
}
int
@@ -178,6 +227,7 @@ pthread_mutex_destroy(pthread_mutex_t * mutex)
* Free the memory allocated for the mutex
* structure:
*/
+ _MUTEX_ASSERT_NOT_OWNED(*mutex);
free(*mutex);
/*
@@ -223,28 +273,24 @@ pthread_mutex_trylock(pthread_mutex_t * mutex)
*/
else if (*mutex != NULL || (ret = init_static(mutex)) == 0) {
/*
+ * Defer signals to protect the scheduling queues from
+ * access by the signal handler:
+ */
+ _thread_kern_sig_defer();
+
+ /* Lock the mutex structure: */
+ _SPINLOCK(&(*mutex)->lock);
+
+ /*
* If the mutex was statically allocated, properly
* initialize the tail queue.
*/
if (((*mutex)->m_flags & MUTEX_FLAGS_INITED) == 0) {
TAILQ_INIT(&(*mutex)->m_queue);
+ _MUTEX_INIT_LINK(*mutex);
(*mutex)->m_flags |= MUTEX_FLAGS_INITED;
}
- /*
- * Guard against being preempted by a scheduling signal.
- * To support priority inheritence mutexes, we need to
- * maintain lists of mutex ownerships for each thread as
- * well as lists of waiting threads for each mutex. In
- * order to propagate priorities we need to atomically
- * walk these lists and cannot rely on a single mutex
- * lock to provide protection against modification.
- */
- _thread_kern_sched_defer();
-
- /* Lock the mutex structure: */
- _SPINLOCK(&(*mutex)->lock);
-
/* Process according to mutex type: */
switch ((*mutex)->m_protocol) {
/* Default POSIX mutex: */
@@ -255,6 +301,7 @@ pthread_mutex_trylock(pthread_mutex_t * mutex)
(*mutex)->m_owner = _thread_run;
/* Add to the list of owned mutexes: */
+ _MUTEX_ASSERT_NOT_OWNED(*mutex);
TAILQ_INSERT_TAIL(&_thread_run->mutexq,
(*mutex), m_qe);
} else if ((*mutex)->m_owner == _thread_run)
@@ -283,6 +330,7 @@ pthread_mutex_trylock(pthread_mutex_t * mutex)
_thread_run->inherited_priority;
/* Add to the list of owned mutexes: */
+ _MUTEX_ASSERT_NOT_OWNED(*mutex);
TAILQ_INSERT_TAIL(&_thread_run->mutexq,
(*mutex), m_qe);
} else if ((*mutex)->m_owner == _thread_run)
@@ -318,6 +366,7 @@ pthread_mutex_trylock(pthread_mutex_t * mutex)
(*mutex)->m_prio;
/* Add to the list of owned mutexes: */
+ _MUTEX_ASSERT_NOT_OWNED(*mutex);
TAILQ_INSERT_TAIL(&_thread_run->mutexq,
(*mutex), m_qe);
} else if ((*mutex)->m_owner == _thread_run)
@@ -338,10 +387,10 @@ pthread_mutex_trylock(pthread_mutex_t * mutex)
_SPINUNLOCK(&(*mutex)->lock);
/*
- * Renable preemption and yield if a scheduling signal
- * arrived while in the critical region:
+ * Undefer and handle pending signals, yielding if
+ * necessary:
*/
- _thread_kern_sched_undefer();
+ _thread_kern_sig_undefer();
}
/* Return the completion status: */
@@ -362,28 +411,24 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
*/
else if (*mutex != NULL || (ret = init_static(mutex)) == 0) {
/*
+ * Defer signals to protect the scheduling queues from
+ * access by the signal handler:
+ */
+ _thread_kern_sig_defer();
+
+ /* Lock the mutex structure: */
+ _SPINLOCK(&(*mutex)->lock);
+
+ /*
* If the mutex was statically allocated, properly
* initialize the tail queue.
*/
if (((*mutex)->m_flags & MUTEX_FLAGS_INITED) == 0) {
TAILQ_INIT(&(*mutex)->m_queue);
(*mutex)->m_flags |= MUTEX_FLAGS_INITED;
+ _MUTEX_INIT_LINK(*mutex);
}
- /*
- * Guard against being preempted by a scheduling signal.
- * To support priority inheritence mutexes, we need to
- * maintain lists of mutex ownerships for each thread as
- * well as lists of waiting threads for each mutex. In
- * order to propagate priorities we need to atomically
- * walk these lists and cannot rely on a single mutex
- * lock to provide protection against modification.
- */
- _thread_kern_sched_defer();
-
- /* Lock the mutex structure: */
- _SPINLOCK(&(*mutex)->lock);
-
/* Process according to mutex type: */
switch ((*mutex)->m_protocol) {
/* Default POSIX mutex: */
@@ -393,6 +438,7 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
(*mutex)->m_owner = _thread_run;
/* Add to the list of owned mutexes: */
+ _MUTEX_ASSERT_NOT_OWNED(*mutex);
TAILQ_INSERT_TAIL(&_thread_run->mutexq,
(*mutex), m_qe);
@@ -420,12 +466,6 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
/* Lock the mutex structure again: */
_SPINLOCK(&(*mutex)->lock);
-
- /*
- * This thread is no longer waiting for
- * the mutex:
- */
- _thread_run->data.mutex = NULL;
}
break;
@@ -450,6 +490,7 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
(*mutex)->m_prio;
/* Add to the list of owned mutexes: */
+ _MUTEX_ASSERT_NOT_OWNED(*mutex);
TAILQ_INSERT_TAIL(&_thread_run->mutexq,
(*mutex), m_qe);
@@ -482,12 +523,6 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
/* Lock the mutex structure again: */
_SPINLOCK(&(*mutex)->lock);
-
- /*
- * This thread is no longer waiting for
- * the mutex:
- */
- _thread_run->data.mutex = NULL;
}
break;
@@ -520,6 +555,7 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
(*mutex)->m_prio;
/* Add to the list of owned mutexes: */
+ _MUTEX_ASSERT_NOT_OWNED(*mutex);
TAILQ_INSERT_TAIL(&_thread_run->mutexq,
(*mutex), m_qe);
} else if ((*mutex)->m_owner == _thread_run)
@@ -557,12 +593,6 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
*/
ret = _thread_run->error;
_thread_run->error = 0;
-
- /*
- * This thread is no longer waiting for
- * the mutex:
- */
- _thread_run->data.mutex = NULL;
}
break;
@@ -577,10 +607,10 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
_SPINUNLOCK(&(*mutex)->lock);
/*
- * Renable preemption and yield if a scheduling signal
- * arrived while in the critical region:
+ * Undefer and handle pending signals, yielding if
+ * necessary:
*/
- _thread_kern_sched_undefer();
+ _thread_kern_sig_undefer();
}
/* Return the completion status: */
@@ -684,15 +714,10 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
ret = EINVAL;
} else {
/*
- * Guard against being preempted by a scheduling signal.
- * To support priority inheritence mutexes, we need to
- * maintain lists of mutex ownerships for each thread as
- * well as lists of waiting threads for each mutex. In
- * order to propagate priorities we need to atomically
- * walk these lists and cannot rely on a single mutex
- * lock to provide protection against modification.
+ * Defer signals to protect the scheduling queues from
+ * access by the signal handler:
*/
- _thread_kern_sched_defer();
+ _thread_kern_sig_defer();
/* Lock the mutex structure: */
_SPINLOCK(&(*mutex)->lock);
@@ -707,8 +732,8 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
*/
if ((*mutex)->m_owner != _thread_run) {
/*
- * Return a permission error when the thread
- * doesn't own the lock:
+ * Return a permission error when the
+ * thread doesn't own the lock.
*/
ret = EPERM;
}
@@ -724,8 +749,10 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
(*mutex)->m_data.m_count = 0;
/* Remove the mutex from the threads queue. */
+ _MUTEX_ASSERT_IS_OWNED(*mutex);
TAILQ_REMOVE(&(*mutex)->m_owner->mutexq,
(*mutex), m_qe);
+ _MUTEX_INIT_LINK(*mutex);
/*
* Get the next thread from the queue of
@@ -739,6 +766,19 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
*/
PTHREAD_NEW_STATE((*mutex)->m_owner,
PS_RUNNING);
+
+ /*
+ * Add the mutex to the threads list of
+ * owned mutexes:
+ */
+ TAILQ_INSERT_TAIL(&(*mutex)->m_owner->mutexq,
+ (*mutex), m_qe);
+
+ /*
+ * The owner is no longer waiting for
+ * this mutex:
+ */
+ (*mutex)->m_owner->data.mutex = NULL;
}
}
break;
@@ -751,8 +791,8 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
*/
if ((*mutex)->m_owner != _thread_run) {
/*
- * Return a permission error when the thread
- * doesn't own the lock:
+ * Return a permission error when the
+ * thread doesn't own the lock.
*/
ret = EPERM;
}
@@ -785,8 +825,10 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
_thread_run->priority_mutex_count--;
/* Remove the mutex from the threads queue. */
+ _MUTEX_ASSERT_IS_OWNED(*mutex);
TAILQ_REMOVE(&(*mutex)->m_owner->mutexq,
(*mutex), m_qe);
+ _MUTEX_INIT_LINK(*mutex);
/*
* Get the next thread from the queue of threads
@@ -858,8 +900,8 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
*/
if ((*mutex)->m_owner != _thread_run) {
/*
- * Return a permission error when the thread
- * doesn't own the lock:
+ * Return a permission error when the
+ * thread doesn't own the lock.
*/
ret = EPERM;
}
@@ -892,8 +934,10 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
_thread_run->priority_mutex_count--;
/* Remove the mutex from the threads queue. */
+ _MUTEX_ASSERT_IS_OWNED(*mutex);
TAILQ_REMOVE(&(*mutex)->m_owner->mutexq,
- (*mutex), m_qe);
+ (*mutex), m_qe);
+ _MUTEX_INIT_LINK(*mutex);
/*
* Enter a loop to find a waiting thread whose
@@ -914,6 +958,11 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
(*mutex)->m_owner->error = EINVAL;
PTHREAD_NEW_STATE((*mutex)->m_owner,
PS_RUNNING);
+ /*
+ * The thread is no longer waiting for
+ * this mutex:
+ */
+ (*mutex)->m_owner->data.mutex = NULL;
}
/* Check for a new owner: */
@@ -979,10 +1028,10 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
_SPINUNLOCK(&(*mutex)->lock);
/*
- * Renable preemption and yield if a scheduling signal
- * arrived while in the critical region:
+ * Undefer and handle pending signals, yielding if
+ * necessary:
*/
- _thread_kern_sched_undefer();
+ _thread_kern_sig_undefer();
}
/* Return the completion status: */
@@ -991,11 +1040,11 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
/*
- * This function is called when a change in base priority occurs
- * for a thread that is thread holding, or waiting for, a priority
- * protection or inheritence mutex. A change in a threads base
- * priority can effect changes to active priorities of other threads
- * and to the ordering of mutex locking by waiting threads.
+ * This function is called when a change in base priority occurs for
+ * a thread that is holding or waiting for a priority protection or
+ * inheritence mutex. A change in a threads base priority can effect
+ * changes to active priorities of other threads and to the ordering
+ * of mutex locking by waiting threads.
*
* This must be called while thread scheduling is deferred.
*/
@@ -1232,8 +1281,7 @@ mutex_rescan_owned (pthread_t pthread, pthread_mutex_t mutex)
* If this thread is in the priority queue, it must be
* removed and reinserted for its new priority.
*/
- if ((pthread != _thread_run) &&
- (pthread->state == PS_RUNNING)) {
+ if (pthread->flags & PTHREAD_FLAGS_IN_PRIOQ) {
/*
* Remove the thread from the priority queue
* before changing its priority: