Make it easy to find deadlocks and lock holders in atomic and non atomic contexts.
Signed-off-by: Liam Girdwood liam.r.girdwood@linux.intel.com --- src/include/reef/lock.h | 41 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-)
diff --git a/src/include/reef/lock.h b/src/include/reef/lock.h index 8b05ef2..eef2a3a 100644 --- a/src/include/reef/lock.h +++ b/src/include/reef/lock.h @@ -41,12 +41,42 @@ #include <reef/interrupt.h> #include <reef/trace.h>
+/* + * Lock debugging provides a simple interface to debug deadlocks. The rmbox + * trace output will show an output :- + * + * 0xd70 [41.306406] delta [0.359638] lock eal + * 0xd80 [41.306409] delta [0.000002] value 0x00000000000001b7 + * 0xd90 [41.306411] delta [0.000002] value 0x0000000000000001 + * 0xda0 [41.306413] delta [0.000002] value 0x0000000001000348 + * + * "eal" indicates we are holding a lock with interrupts OFF. The next value + * is the line number of where the lock was aquired. The second number is the + * number of other locks held whilst this lock is held and the subsequent + * numbers list each lock and the line number of it's holder. e.g. to find + * the locks :- + * + * grep -rn lock --include *.c | grep 840 (search for lock at line 0x348) + * src/drivers/dw-dma.c:840: spinlock_init(&dma->lock); + * + * grep -rn lock --include *.c | grep 439 + * src/lib/alloc.c:439: spin_lock_irq(&memmap.lock, flags); + * + * Every lock entry and exit shows LcE and LcX in trace alonside the lock + * line numbers in hex. e.g. + * + * 0xfd60 [11032.730567] delta [0.000004] lock LcE + * 0xfd70 [11032.730569] delta [0.000002] value 0x00000000000000ae + * + * Deadlock would be a LcE without a subsequent LcX. + * + */
#if DEBUG_LOCKS
#define DBG_LOCK_USERS 8
-#define trace_lock(__e) trace_event_atomic(TRACE_CLASS_LOCK, __e) +#define trace_lock(__e) trace_error_atomic(TRACE_CLASS_LOCK, __e) #define tracev_lock(__e) tracev_event_atomic(TRACE_CLASS_LOCK, __e) #define trace_lock_error(__e) trace_error_atomic(TRACE_CLASS_LOCK, __e) #define trace_lock_value(__e) _trace_error_atomic(__e) @@ -55,10 +85,12 @@ extern uint32_t lock_dbg_atomic; extern uint32_t lock_dbg_user[DBG_LOCK_USERS];
#define spin_lock_dbg() \ - trace_lock("LcE"); + trace_lock("LcE"); \ + trace_lock_value(__LINE__);
#define spin_unlock_dbg() \ - trace_lock("LcX"); + trace_lock("LcX"); \ + trace_lock_value(__LINE__); \
/* all SMP spinlocks need init, nothing todo on UP */ #define spinlock_init(lock) \ @@ -89,8 +121,9 @@ extern uint32_t lock_dbg_user[DBG_LOCK_USERS]; /* disables all IRQ sources and takes lock - enter atomic context */ #define spin_lock_irq(lock, flags) \ flags = interrupt_global_disable(); \ + lock_dbg_atomic++; \ spin_lock(lock); \ - if (++lock_dbg_atomic < DBG_LOCK_USERS) \ + if (lock_dbg_atomic < DBG_LOCK_USERS) \ lock_dbg_user[lock_dbg_atomic - 1] = (lock)->user;
/* re-enables current IRQ sources and releases lock - leave atomic context */