kernel -- Spinlock debugging.
authorVenkatesh Srinivas <me@endeavour.zapto.org>
Sun, 26 Dec 2010 00:57:07 +0000 (16:57 -0800)
committerVenkatesh Srinivas <me@endeavour.zapto.org>
Sun, 26 Dec 2010 00:57:07 +0000 (16:57 -0800)
* Track spinlocks held by a thread in a per-thread array; records the lock
  address and the EIP of the lock-taker.

* Panic in lockmgr() if we hold any spinlocks when trying to take a sleeping
  lockmgr lock.

sys/kern/kern_lock.c
sys/sys/spinlock2.h
sys/sys/thread.h

index b33a7af..c51c2c9 100644 (file)
@@ -184,6 +184,15 @@ debuglockmgr(struct lock *lkp, u_int flags,
 #endif
        }
 
+#ifdef DEBUG_LOCKS
+       if (mycpu->gd_spinlocks_wr &&
+           ((flags & LK_NOWAIT) == 0) 
+       ) {
+               panic("lockmgr %s from %s:%d: called with %d spinlocks held",
+                     lkp->lk_wmesg, file, line, mycpu->gd_spinlocks_wr);
+       }
+#endif
+
        /*
         * So sue me, I'm too tired.
         */
index a31556e..35cecd2 100644 (file)
@@ -81,6 +81,20 @@ spin_trylock(struct spinlock *mtx)
        ++gd->gd_spinlocks_wr;
        if ((value = atomic_swap_int(&mtx->lock, SPINLOCK_EXCLUSIVE)) != 0)
                return (spin_trylock_wr_contested2(gd));
+#ifdef SMP
+#ifdef DEBUG_LOCKS
+       int i;
+       for (i = 0; i < SPINLOCK_DEBUG_ARRAY_SIZE; i++) {
+               if (gd->gd_curthread->td_spinlock_stack_id[i] == 0) {
+                       gd->gd_curthread->td_spinlock_stack_id[i] = 1;
+                       gd->gd_curthread->td_spinlock_stack[i] = mtx;
+                       gd->gd_curthread->td_spinlock_caller_pc[i] =
+                                               __builtin_return_address(0);
+                       break;
+               }
+       }
+#endif
+#endif
        return (TRUE);
 }
 
@@ -115,6 +129,18 @@ spin_lock_quick(globaldata_t gd, struct spinlock *mtx)
 #ifdef SMP
        if ((value = atomic_swap_int(&mtx->lock, SPINLOCK_EXCLUSIVE)) != 0)
                spin_lock_wr_contested2(mtx);
+#ifdef DEBUG_LOCKS
+       int i;
+       for (i = 0; i < SPINLOCK_DEBUG_ARRAY_SIZE; i++) {
+               if (gd->gd_curthread->td_spinlock_stack_id[i] == 0) {
+                       gd->gd_curthread->td_spinlock_stack_id[i] = 1;
+                       gd->gd_curthread->td_spinlock_stack[i] = mtx;
+                       gd->gd_curthread->td_spinlock_caller_pc[i] =
+                               __builtin_return_address(0);
+                       break;
+               }
+       }
+#endif
 #endif
 }
 
@@ -133,6 +159,18 @@ static __inline void
 spin_unlock_quick(globaldata_t gd, struct spinlock *mtx)
 {
 #ifdef SMP
+#ifdef DEBUG_LOCKS
+       int i;
+       for (i = 0; i < SPINLOCK_DEBUG_ARRAY_SIZE; i++) {
+               if ((gd->gd_curthread->td_spinlock_stack_id[i] == 1) &&
+                   (gd->gd_curthread->td_spinlock_stack[i] == mtx)) {
+                       gd->gd_curthread->td_spinlock_stack_id[i] = 0;
+                       gd->gd_curthread->td_spinlock_stack[i] = NULL;
+                       gd->gd_curthread->td_spinlock_caller_pc[i] = NULL;
+                       break;
+               }
+       }
+#endif
        mtx->lock = 0;
 #endif
        KKASSERT(gd->gd_spinlocks_wr > 0);
index 8c4eb48..ebbb657 100644 (file)
@@ -302,6 +302,12 @@ struct thread {
     int                td_in_crit_report;      
 #endif
     struct md_thread td_mach;
+#ifdef DEBUG_LOCKS
+#define SPINLOCK_DEBUG_ARRAY_SIZE      32
+   int         td_spinlock_stack_id[SPINLOCK_DEBUG_ARRAY_SIZE];
+   struct spinlock *td_spinlock_stack[SPINLOCK_DEBUG_ARRAY_SIZE];
+   void        *td_spinlock_caller_pc[SPINLOCK_DEBUG_ARRAY_SIZE];
+#endif
 };
 
 #define td_toks_base           td_toks_array[0]