summaryrefslogtreecommitdiff
path: root/kern/mutex
diff options
context:
space:
mode:
authorRichard Braun <rbraun@sceen.net>2017-08-27 16:48:54 +0200
committerRichard Braun <rbraun@sceen.net>2017-08-27 16:48:54 +0200
commitc32a06eae07bd0bc0b4017ea5286b91d6518ec7f (patch)
tree73bfb9b6ba05e4b7ea6d30ba83e7089095cec217 /kern/mutex
parent791a6563cd955f59e04084f1fc20aadbbc6ae25f (diff)
kern/mutex/mutex_plain: implement timed waits
Diffstat (limited to 'kern/mutex')
-rw-r--r--kern/mutex/mutex_plain.c55
-rw-r--r--kern/mutex/mutex_plain_i.h16
2 files changed, 65 insertions, 6 deletions
diff --git a/kern/mutex/mutex_plain.c b/kern/mutex/mutex_plain.c
index 5e4ba53..58fc487 100644
--- a/kern/mutex/mutex_plain.c
+++ b/kern/mutex/mutex_plain.c
@@ -15,20 +15,25 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
+#include <stdint.h>
#include <kern/atomic.h>
#include <kern/mutex.h>
#include <kern/mutex_types.h>
#include <kern/sleepq.h>
-void
-mutex_plain_lock_slow(struct mutex *mutex)
+static int
+mutex_plain_lock_slow_common(struct mutex *mutex, bool timed, uint64_t ticks)
{
unsigned int state;
struct sleepq *sleepq;
unsigned long flags;
+ int error;
+
+ error = 0;
sleepq = sleepq_lend(mutex, false, &flags);
@@ -39,14 +44,49 @@ mutex_plain_lock_slow(struct mutex *mutex)
break;
}
- sleepq_wait(sleepq, "mutex");
+ if (!timed) {
+ sleepq_wait(sleepq, "mutex");
+ } else {
+ error = sleepq_timedwait(sleepq, "mutex", ticks);
+
+ if (error) {
+ break;
+ }
+ }
+ }
+
+ if (error) {
+ if (sleepq_empty(sleepq)) {
+ atomic_cas(&mutex->state, MUTEX_CONTENDED,
+ MUTEX_LOCKED, ATOMIC_RELAXED);
+ }
+
+ goto out;
}
if (sleepq_empty(sleepq)) {
atomic_store(&mutex->state, MUTEX_LOCKED, ATOMIC_RELAXED);
}
+out:
sleepq_return(sleepq, flags);
+
+ return error;
+}
+
+void
+mutex_plain_lock_slow(struct mutex *mutex)
+{
+ int error;
+
+ error = mutex_plain_lock_slow_common(mutex, false, 0);
+ assert(!error);
+}
+
+int
+mutex_plain_timedlock_slow(struct mutex *mutex, uint64_t ticks)
+{
+ return mutex_plain_lock_slow_common(mutex, true, ticks);
}
void
@@ -57,8 +97,11 @@ mutex_plain_unlock_slow(struct mutex *mutex)
sleepq = sleepq_acquire(mutex, false, &flags);
- if (sleepq != NULL) {
- sleepq_signal(sleepq);
- sleepq_release(sleepq, flags);
+ if (sleepq == NULL) {
+ return;
}
+
+ sleepq_signal(sleepq);
+
+ sleepq_release(sleepq, flags);
}
diff --git a/kern/mutex/mutex_plain_i.h b/kern/mutex/mutex_plain_i.h
index 4f112b8..58e565e 100644
--- a/kern/mutex/mutex_plain_i.h
+++ b/kern/mutex/mutex_plain_i.h
@@ -24,6 +24,7 @@
#endif
#include <assert.h>
+#include <stdint.h>
#include <kern/atomic.h>
#include <kern/error.h>
@@ -71,6 +72,7 @@ mutex_plain_unlock_fast(struct mutex *mutex)
}
void mutex_plain_lock_slow(struct mutex *mutex);
+int mutex_plain_timedlock_slow(struct mutex *mutex, uint64_t ticks);
void mutex_plain_unlock_slow(struct mutex *mutex);
/*
@@ -98,6 +100,20 @@ mutex_impl_lock(struct mutex *mutex)
}
}
+static inline int
+mutex_impl_timedlock(struct mutex *mutex, uint64_t ticks)
+{
+ int error;
+
+ error = mutex_plain_lock_fast(mutex);
+
+ if (unlikely(error)) {
+ error = mutex_plain_timedlock_slow(mutex, ticks);
+ }
+
+ return error;
+}
+
static inline void
mutex_impl_unlock(struct mutex *mutex)
{