From: Tulio A M Mendes Date: Sun, 15 Feb 2026 07:48:49 +0000 (-0300) Subject: feat: spinlock debug infrastructure — name, CPU ID tracking, deadlock detection X-Git-Url: https://projects.tadryanom.me/?a=commitdiff_plain;h=1b95a7af02dbd9ee5b74021adcb604392ab53a06;p=AdrOS.git feat: spinlock debug infrastructure — name, CPU ID tracking, deadlock detection --- diff --git a/include/spinlock.h b/include/spinlock.h index c490d25..561cf4c 100644 --- a/include/spinlock.h +++ b/include/spinlock.h @@ -29,14 +29,50 @@ static inline void irq_restore(uintptr_t flags) { (void)flags; } /* Architecture-agnostic spinlock implementation */ /* ------------------------------------------------------------------ */ +#ifdef SPINLOCK_DEBUG + typedef struct { volatile uint32_t locked; + const char* name; + volatile int holder_cpu; + volatile uint32_t nest_count; } spinlock_t; +#define SPINLOCK_INIT(n) { .locked = 0, .name = (n), .holder_cpu = -1, .nest_count = 0 } + +static inline void spinlock_init(spinlock_t* l) { + l->locked = 0; + l->name = ""; + l->holder_cpu = -1; + l->nest_count = 0; +} + +static inline void spinlock_init_named(spinlock_t* l, const char* name) { + l->locked = 0; + l->name = name; + l->holder_cpu = -1; + l->nest_count = 0; +} + +#else /* !SPINLOCK_DEBUG */ + +typedef struct { + volatile uint32_t locked; +} spinlock_t; + +#define SPINLOCK_INIT(n) { .locked = 0 } + static inline void spinlock_init(spinlock_t* l) { l->locked = 0; } +static inline void spinlock_init_named(spinlock_t* l, const char* name) { + (void)name; + l->locked = 0; +} + +#endif /* SPINLOCK_DEBUG */ + static inline int spin_is_locked(spinlock_t* l) { return l->locked != 0; } @@ -61,33 +97,75 @@ static inline void spin_lock(spinlock_t* l) { } l->locked = 1; __sync_synchronize(); +#ifdef SPINLOCK_DEBUG + l->holder_cpu = 0; + l->nest_count = 1; +#endif } static inline int spin_trylock(spinlock_t* l) { if (l->locked) return 0; l->locked = 1; __sync_synchronize(); +#ifdef SPINLOCK_DEBUG + l->holder_cpu = 0; + l->nest_count = 1; +#endif return 1; } static inline void spin_unlock(spinlock_t* l) { +#ifdef SPINLOCK_DEBUG + l->holder_cpu = -1; + l->nest_count = 0; +#endif __sync_synchronize(); l->locked = 0; } #else static inline void spin_lock(spinlock_t* l) { +#ifdef SPINLOCK_DEBUG + uint32_t spins = 0; +#endif while (__sync_lock_test_and_set(&l->locked, 1)) { while (l->locked) { cpu_relax(); +#ifdef SPINLOCK_DEBUG + if (++spins > 10000000) { + extern void kprintf(const char* fmt, ...); + kprintf("[SPINLOCK] deadlock? lock '%s' held by cpu %d\n", + l->name ? l->name : "?", l->holder_cpu); + spins = 0; + } +#endif } } +#ifdef SPINLOCK_DEBUG + { + extern uint32_t lapic_get_id(void); + l->holder_cpu = (int)lapic_get_id(); + } + l->nest_count = 1; +#endif } static inline int spin_trylock(spinlock_t* l) { - return __sync_lock_test_and_set(&l->locked, 1) == 0; + if (__sync_lock_test_and_set(&l->locked, 1) != 0) return 0; +#ifdef SPINLOCK_DEBUG + { + extern uint32_t lapic_get_id(void); + l->holder_cpu = (int)lapic_get_id(); + } + l->nest_count = 1; +#endif + return 1; } static inline void spin_unlock(spinlock_t* l) { +#ifdef SPINLOCK_DEBUG + l->holder_cpu = -1; + l->nest_count = 0; +#endif __sync_synchronize(); __sync_lock_release(&l->locked); }