]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
feat: spinlock debug infrastructure — name, CPU ID tracking, deadlock detection
authorTulio A M Mendes <[email protected]>
Sun, 15 Feb 2026 07:48:49 +0000 (04:48 -0300)
committerTulio A M Mendes <[email protected]>
Sun, 15 Feb 2026 07:48:49 +0000 (04:48 -0300)
include/spinlock.h

index c490d25fd20fcb0441e9a35539659dd79fa850fe..561cf4c1b9e0f34e8a96ccfef056a514dfd36565 100644 (file)
@@ -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 = "<unnamed>";
+    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);
 }