Re: interrupt checks for spinlocks

From: William Lee Irwin III (wli@holomorphy.com)
Date: Sun Nov 03 2002 - 22:22:15 EST


On Sun, Nov 03, 2002 at 10:01:24PM -0500, Robert Love wrote:
> You can do #1, but you need to figure out if your interrupt is the only
> interrupt using the lock or not (possibly hard).
> In other words, a lock unique to your interrupt handler does not need to
> disable interrupts (since only that handler can grab the lock and it is
> disabled).
> If other handlers can grab the lock, interrupts need to be disabled.
> So a test of irqs_disabled() would show a false-positive in the first
> case. No easy way to tell..
> Robert Love

Attempt #1:

===== include/linux/spinlock.h 1.18 vs edited =====
--- 1.18/include/linux/spinlock.h Sun Aug 25 10:25:45 2002
+++ edited/include/linux/spinlock.h Sun Nov 3 19:21:44 2002
@@ -38,6 +38,44 @@
 #include <asm/spinlock.h>
 
 /*
+ * if a lock is ever taken in interrupt context, it must always be
+ * taken with interrupts disabled. If a locking call is made that
+ * unconditionally disables and then re-enables interrupts, it must
+ * be made with interrupts enabled.
+ */
+#ifndef irq_tainted_lock
+#define irq_tainted_lock(lock) 0
+#endif
+
+#ifndef irq_taint_lock
+#define irq_taint_lock(lock) do { } while (0)
+#define
+
+#ifndef CONFIG_DEBUG_SPINLOCK
+#define check_spinlock_irq(lock) do { } while (0)
+#define check_spinlock_irqs_disabled(lock) do { } while (0)
+#else
+#define check_spinlock_irq(lock) \
+ do { \
+ if (irqs_disabled()) { \
+ printk("spinlock taken unconditionally " \
+ "re-enabling interrupts\n"); \
+ dump_stack(); \
+ } \
+ } while (0)
+#define check_spinlock_irqs_disabled(lock) \
+ do { \
+ if (in_interrupt()) \
+ irq_taint_lock(lock); \
+ else if (irq_tainted_lock(lock)) { \
+ printk("spinlock taken in process context " \
+ "without disabling interrupts\n"); \
+ dump_stack(); \
+ } \
+ } while (0)
+#endif
+
+/*
  * !CONFIG_SMP and spin_lock_init not previously defined
  * (e.g. by including include/asm/spinlock.h)
  */
@@ -87,6 +125,7 @@
  */
 #define spin_lock(lock) \
 do { \
+ check_spinlock_irqs_disabled(lock); \
         preempt_disable(); \
         _raw_spin_lock(lock); \
 } while(0)
@@ -102,6 +141,7 @@
 
 #define read_lock(lock) \
 do { \
+ check_spinlock_irqs_disabled(lock); \
         preempt_disable(); \
         _raw_read_lock(lock); \
 } while(0)
@@ -114,6 +154,7 @@
 
 #define write_lock(lock) \
 do { \
+ check_spinlock_irqs_disabled(lock); \
         preempt_disable(); \
         _raw_write_lock(lock); \
 } while(0)
@@ -136,6 +177,7 @@
 
 #define spin_lock_irq(lock) \
 do { \
+ check_spinlock_irq(lock); \
         local_irq_disable(); \
         preempt_disable(); \
         _raw_spin_lock(lock); \
@@ -157,6 +199,7 @@
 
 #define read_lock_irq(lock) \
 do { \
+ check_spinlock_irq(lock); \
         local_irq_disable(); \
         preempt_disable(); \
         _raw_read_lock(lock); \
@@ -178,6 +221,7 @@
 
 #define write_lock_irq(lock) \
 do { \
+ check_spinlock_irq(lock); \
         local_irq_disable(); \
         preempt_disable(); \
         _raw_write_lock(lock); \
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Thu Nov 07 2002 - 22:00:31 EST