summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Braun <rbraun@sceen.net>2018-02-22 00:43:40 +0100
committerRichard Braun <rbraun@sceen.net>2018-02-22 00:43:40 +0100
commite8265363384bc3f8e6bb31466a3590ce27811efa (patch)
treeb26cc2a341751deba5f801b6c16685a0d5f98fc0
parent3dab066560158cde19ec8c7df3515a01bb04b746 (diff)
kern/spinlock: add ownership tracking as a debugging feature
-rw-r--r--kern/Kconfig6
-rw-r--r--kern/spinlock.c5
-rw-r--r--kern/spinlock.h15
-rw-r--r--kern/spinlock_i.h30
-rw-r--r--kern/spinlock_types.h6
-rw-r--r--kern/thread.c2
6 files changed, 64 insertions, 0 deletions
diff --git a/kern/Kconfig b/kern/Kconfig
index 21bfaa3..13cd39b 100644
--- a/kern/Kconfig
+++ b/kern/Kconfig
@@ -96,4 +96,10 @@ config MUTEX_DEBUG
---help---
Enable mutex debugging and instrumentation.
+config SPINLOCK_DEBUG
+ bool "Spinlock debugging"
+ default n
+ ---help---
+ Enable spinlock ownership tracking.
+
endmenu
diff --git a/kern/spinlock.c b/kern/spinlock.c
index a591c61..9857b38 100644
--- a/kern/spinlock.c
+++ b/kern/spinlock.c
@@ -139,6 +139,10 @@ void
spinlock_init(struct spinlock *lock)
{
lock->value = SPINLOCK_UNLOCKED;
+
+#ifdef SPINLOCK_TRACK_OWNER
+ lock->owner = NULL;
+#endif /* SPINLOCK_TRACK_OWNER */
}
static unsigned int
@@ -292,6 +296,7 @@ spinlock_lock_slow(struct spinlock *lock)
spinlock_store_first_qid(lock, SPINLOCK_QID_NULL);
}
+ spinlock_own(lock);
error = spinlock_try_downgrade(lock, qid);
if (!error) {
diff --git a/kern/spinlock.h b/kern/spinlock.h
index dd98cbf..30fc1e5 100644
--- a/kern/spinlock.h
+++ b/kern/spinlock.h
@@ -36,6 +36,21 @@ struct spinlock;
#define spinlock_assert_locked(lock) assert((lock)->value != SPINLOCK_UNLOCKED)
+#ifdef SPINLOCK_TRACK_OWNER
+
+static inline void
+spinlock_transfer_owner(struct spinlock *lock, struct thread *owner)
+{
+ assert(lock->owner == thread_self());
+ lock->owner = owner;
+}
+
+#else /* SPINLOCK_TRACK_OWNER */
+
+#define spinlock_transfer_owner(lock, owner)
+
+#endif /* SPINLOCK_TRACK_OWNER */
+
/*
* Initialize a spin lock.
*/
diff --git a/kern/spinlock_i.h b/kern/spinlock_i.h
index c9dcdd1..a9f5fce 100644
--- a/kern/spinlock_i.h
+++ b/kern/spinlock_i.h
@@ -26,6 +26,7 @@
#include <kern/error.h>
#include <kern/macros.h>
#include <kern/spinlock_types.h>
+#include <kern/thread.h>
#include <machine/cpu.h>
/*
@@ -36,6 +37,33 @@
#define SPINLOCK_UNLOCKED 0
#define SPINLOCK_LOCKED 1
+#ifdef CONFIG_SPINLOCK_DEBUG
+#define SPINLOCK_TRACK_OWNER
+#endif
+
+#ifdef SPINLOCK_TRACK_OWNER
+
+static inline void
+spinlock_own(struct spinlock *lock)
+{
+ assert(!lock->owner);
+ lock->owner = thread_self();
+}
+
+static inline void
+spinlock_disown(struct spinlock *lock)
+{
+ assert(lock->owner == thread_self());
+ lock->owner = NULL;
+}
+
+#else /* SPINLOCK_TRACK_OWNER */
+
+#define spinlock_own(lock)
+#define spinlock_disown(lock)
+
+#endif /* SPINLOCK_TRACK_OWNER */
+
static inline int
spinlock_lock_fast(struct spinlock *lock)
{
@@ -47,6 +75,7 @@ spinlock_lock_fast(struct spinlock *lock)
return ERROR_BUSY;
}
+ spinlock_own(lock);
return 0;
}
@@ -55,6 +84,7 @@ spinlock_unlock_fast(struct spinlock *lock)
{
unsigned int prev;
+ spinlock_disown(lock);
prev = atomic_cas_release(&lock->value, SPINLOCK_LOCKED, SPINLOCK_UNLOCKED);
if (unlikely(prev != SPINLOCK_LOCKED)) {
diff --git a/kern/spinlock_types.h b/kern/spinlock_types.h
index 7dbca37..93f85f7 100644
--- a/kern/spinlock_types.h
+++ b/kern/spinlock_types.h
@@ -21,8 +21,14 @@
#ifndef _KERN_SPINLOCK_TYPES_H
#define _KERN_SPINLOCK_TYPES_H
+struct thread;
+
struct spinlock {
unsigned int value;
+
+#ifdef CONFIG_SPINLOCK_DEBUG
+ struct thread *owner;
+#endif /* CONFIG_SPINLOCK_DEBUG */
};
#endif /* _KERN_SPINLOCK_TYPES_H */
diff --git a/kern/thread.c b/kern/thread.c
index 926ca74..5ba51b0 100644
--- a/kern/thread.c
+++ b/kern/thread.c
@@ -640,6 +640,7 @@ thread_runq_schedule(struct thread_runq *runq)
if (likely(prev != next)) {
rcu_report_context_switch(thread_rcu_reader(prev));
+ spinlock_transfer_owner(&runq->lock, next);
/*
* That's where the true context switch occurs. The next thread must
@@ -2619,6 +2620,7 @@ thread_run_scheduler(void)
spinlock_lock(&runq->lock);
thread = thread_runq_get_next(thread_runq_local());
+ spinlock_transfer_owner(&runq->lock, thread);
tcb_load(&thread->tcb);
}