summaryrefslogtreecommitdiff
path: root/kern/mutex.c
diff options
context:
space:
mode:
Diffstat (limited to 'kern/mutex.c')
-rw-r--r--kern/mutex.c44
1 files changed, 29 insertions, 15 deletions
diff --git a/kern/mutex.c b/kern/mutex.c
index 58e24513..1a1c2ea7 100644
--- a/kern/mutex.c
+++ b/kern/mutex.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2014 Richard Braun.
+ * Copyright (c) 2013-2017 Richard Braun.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,36 +15,50 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <stddef.h>
+
#include <kern/mutex.h>
#include <kern/mutex_i.h>
-#include <kern/spinlock.h>
-#include <kern/thread.h>
+#include <kern/sleepq.h>
void
mutex_lock_slow(struct mutex *mutex)
{
- struct mutex_waiter waiter;
+ struct sleepq *sleepq;
unsigned int state;
- spinlock_lock(&mutex->lock);
+ sleepq = sleepq_lend(mutex, false);
+
+ for (;;) {
+ state = atomic_swap_uint(&mutex->state, MUTEX_CONTENDED);
- state = mutex_tryacquire_slow(mutex);
+ if (state == MUTEX_UNLOCKED) {
+ break;
+ }
- if (state != MUTEX_UNLOCKED) {
- waiter.thread = thread_self();
- mutex_queue(mutex, &waiter);
- mutex_wait(mutex, &waiter);
+ sleepq_wait(sleepq, "mutex");
}
- mutex_trydowngrade(mutex);
+ if (sleepq_empty(sleepq)) {
+ state = atomic_swap_uint(&mutex->state, MUTEX_LOCKED);
+ assert(state == MUTEX_CONTENDED);
+ }
- spinlock_unlock(&mutex->lock);
+ sleepq_return(sleepq);
}
void
mutex_unlock_slow(struct mutex *mutex)
{
- spinlock_lock(&mutex->lock);
- mutex_signal(mutex);
- spinlock_unlock(&mutex->lock);
+ struct sleepq *sleepq;
+
+ sleepq = sleepq_acquire(mutex, false);
+
+ if (sleepq == NULL) {
+ return;
+ }
+
+ sleepq_signal(sleepq);
+
+ sleepq_release(sleepq);
}