diff options
author | Richard Braun <rbraun@sceen.net> | 2018-02-22 00:43:40 +0100 |
---|---|---|
committer | Richard Braun <rbraun@sceen.net> | 2018-02-22 00:43:40 +0100 |
commit | e8265363384bc3f8e6bb31466a3590ce27811efa (patch) | |
tree | b26cc2a341751deba5f801b6c16685a0d5f98fc0 | |
parent | 3dab066560158cde19ec8c7df3515a01bb04b746 (diff) |
kern/spinlock: add ownership tracking as a debugging feature
-rw-r--r-- | kern/Kconfig | 6 | ||||
-rw-r--r-- | kern/spinlock.c | 5 | ||||
-rw-r--r-- | kern/spinlock.h | 15 | ||||
-rw-r--r-- | kern/spinlock_i.h | 30 | ||||
-rw-r--r-- | kern/spinlock_types.h | 6 | ||||
-rw-r--r-- | kern/thread.c | 2 |
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); } |