summaryrefslogtreecommitdiff
path: root/kern/spinlock_i.h
diff options
context:
space:
mode:
Diffstat (limited to 'kern/spinlock_i.h')
-rw-r--r--kern/spinlock_i.h65
1 files changed, 46 insertions, 19 deletions
diff --git a/kern/spinlock_i.h b/kern/spinlock_i.h
index 88cb89e4..69de0b01 100644
--- a/kern/spinlock_i.h
+++ b/kern/spinlock_i.h
@@ -18,49 +18,76 @@
#ifndef _KERN_SPINLOCK_I_H
#define _KERN_SPINLOCK_I_H
-#include <kern/assert.h>
+#include <stddef.h>
+#include <stdint.h>
+
#include <kern/error.h>
#include <kern/spinlock_types.h>
#include <machine/atomic.h>
#include <machine/cpu.h>
+/*
+ * Non-contended lock values.
+ *
+ * Any other lock value implies a contended lock.
+ */
+#define SPINLOCK_UNLOCKED 0
+#define SPINLOCK_LOCKED 1
+
static inline int
-spinlock_tryacquire(struct spinlock *lock)
+spinlock_lock_fast(struct spinlock *lock)
{
- unsigned int state;
+ unsigned int prev;
- state = atomic_swap_uint(&lock->locked, 1);
+ prev = atomic_cas_uint(&lock->value, SPINLOCK_UNLOCKED, SPINLOCK_LOCKED);
- if (state == 0) {
- return 0;
+ if (prev != SPINLOCK_UNLOCKED) {
+ return ERROR_BUSY;
}
- return ERROR_BUSY;
+ return 0;
}
+static inline int
+spinlock_unlock_fast(struct spinlock *lock)
+{
+ unsigned int prev;
+
+ prev = atomic_cas_uint(&lock->value, SPINLOCK_LOCKED, SPINLOCK_UNLOCKED);
+
+ if (prev != SPINLOCK_LOCKED) {
+ return ERROR_BUSY;
+ }
+
+ return 0;
+}
+
+void spinlock_lock_slow(struct spinlock *lock);
+
+void spinlock_unlock_slow(struct spinlock *lock);
+
static inline void
-spinlock_acquire(struct spinlock *lock)
+spinlock_lock_common(struct spinlock *lock)
{
int error;
- for (;;) {
- error = spinlock_tryacquire(lock);
+ error = spinlock_lock_fast(lock);
- if (!error) {
- break;
- }
-
- cpu_pause();
+ if (error) {
+ spinlock_lock_slow(lock);
}
}
static inline void
-spinlock_release(struct spinlock *lock)
+spinlock_unlock_common(struct spinlock *lock)
{
- unsigned int locked;
+ int error;
- locked = atomic_swap_uint(&lock->locked, 0);
- assert(locked);
+ error = spinlock_unlock_fast(lock);
+
+ if (error) {
+ spinlock_unlock_slow(lock);
+ }
}
#endif /* _KERN_SPINLOCK_I_H */