From 04e1818f60ad8f90ea502f2f6c6ea61e6e61644c Mon Sep 17 00:00:00 2001 From: Richard Braun Date: Sun, 14 Apr 2013 18:29:12 +0200 Subject: kern/{condition,mutex}: refactor common code The condition module intrusively uses mutexes. Augment the interface of the mutex module so that mutexes and conditions share common code. As a side effect, the implementation should have gained in clarity. --- kern/mutex.c | 87 ++++++++---------------------------------------------------- 1 file changed, 11 insertions(+), 76 deletions(-) (limited to 'kern/mutex.c') diff --git a/kern/mutex.c b/kern/mutex.c index 90922903..e49c56c8 100644 --- a/kern/mutex.c +++ b/kern/mutex.c @@ -15,101 +15,36 @@ * along with this program. If not, see . */ -#include -#include #include +#include #include #include -#include void -mutex_init(struct mutex *mutex) -{ - mutex->state = MUTEX_UNLOCKED; - spinlock_init(&mutex->lock); - list_init(&mutex->waiters); -} - -int -mutex_trylock(struct mutex *mutex) -{ - unsigned long state; - - state = atomic_cas(&mutex->state, MUTEX_UNLOCKED, MUTEX_LOCKED); - - if (state == MUTEX_UNLOCKED) - return 0; - - return 1; -} - -void -mutex_lock(struct mutex *mutex) +mutex_lock_slow(struct mutex *mutex) { struct mutex_waiter waiter; unsigned long state; - state = atomic_cas(&mutex->state, MUTEX_UNLOCKED, MUTEX_LOCKED); - - if (state == MUTEX_UNLOCKED) - return; - - /* - * The mutex was either locked or contended. Unconditionnally update its - * state to reflect it is now contended, and to check the previous state - * while holding the waiters lock so that the current thread doesn't miss - * a wakeup when the owner unlocks. - */ - - assert((state == MUTEX_LOCKED) || (state == MUTEX_CONTENDED)); - spinlock_lock(&mutex->lock); - state = atomic_swap(&mutex->state, MUTEX_CONTENDED); + state = mutex_tryacquire_slow(mutex); - if (state == MUTEX_UNLOCKED) - goto out; - - waiter.thread = thread_self(); - list_insert_tail(&mutex->waiters, &waiter.node); - - do { - thread_sleep(&mutex->lock); - state = atomic_swap(&mutex->state, MUTEX_CONTENDED); - } while (state != MUTEX_UNLOCKED); - - list_remove(&waiter.node); - -out: - if (list_empty(&mutex->waiters)) { - state = atomic_swap(&mutex->state, MUTEX_LOCKED); - assert(state == MUTEX_CONTENDED); + if (state != MUTEX_UNLOCKED) { + waiter.thread = thread_self(); + mutex_queue(mutex, &waiter); + mutex_wait(mutex, &waiter); } + mutex_trydowngrade(mutex); + spinlock_unlock(&mutex->lock); } void -mutex_unlock(struct mutex *mutex) +mutex_unlock_slow(struct mutex *mutex) { - struct mutex_waiter *waiter; - unsigned long state; - - state = atomic_swap(&mutex->state, MUTEX_UNLOCKED); - - if (state == MUTEX_LOCKED) - return; - - /* The mutex was contended, wake up the next waiter if any */ - - assert(state == MUTEX_CONTENDED); - spinlock_lock(&mutex->lock); - - if (!list_empty(&mutex->waiters)) { - waiter = list_first_entry(&mutex->waiters, struct mutex_waiter, node); - thread_wakeup(waiter->thread); - } - + mutex_signal(mutex); spinlock_unlock(&mutex->lock); } -- cgit v1.2.3