diff options
author | Richard Braun <rbraun@sceen.net> | 2017-08-27 16:48:54 +0200 |
---|---|---|
committer | Richard Braun <rbraun@sceen.net> | 2017-08-27 16:48:54 +0200 |
commit | c32a06eae07bd0bc0b4017ea5286b91d6518ec7f (patch) | |
tree | 73bfb9b6ba05e4b7ea6d30ba83e7089095cec217 /kern/mutex | |
parent | 791a6563cd955f59e04084f1fc20aadbbc6ae25f (diff) |
kern/mutex/mutex_plain: implement timed waits
Diffstat (limited to 'kern/mutex')
-rw-r--r-- | kern/mutex/mutex_plain.c | 55 | ||||
-rw-r--r-- | kern/mutex/mutex_plain_i.h | 16 |
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) { |