Skip to contentSkip to conversation

preemptive spin readlocks for 2.5

PATCH New Joe Korty 1 participant 1 message Jan 30, 2003

Subsystems (2)
lore
Share & tools
lore

Joe Korty

author
#0 lore raw

PATCH 1/1 preemptive spin readlocks for 2.5

Hi Andrew,
This patch adds read_lock() to the list of lock services that drop
preemption while spinning.

This patch is against 2.5.59, so it re-applies the spinlock repair work already in your trees but not yet pushed to Linus.

A 2.4 version of this patch has been running here on several test stands for nearly a week. The 2.5 version has been boot-tested.

Regards,
Joe

PS: I also have 2.4 versions of irq lock services that drop the irq while spinning. These have been running here since Monday. I can do a 2.5 port if you are interested in taking a look at them.

include/asm-i386/atomic.h +19 -0
diff -ur 2.5.59-orig/include/asm-i386/atomic.h 2.5.59-rdlcks/include/asm-i386/atomic.h
@@ -146,6 +146,25 @@
 }
 
 /**
+ * atomic_dec_positive - decrement and test if positive
+ * @v: pointer of type atomic_t
+ * 
+ * Atomically decrements @v by 1 and returns true if the
+ * result is greater than zero.  Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */ 
+static __inline__ int atomic_dec_positive(atomic_t *v)
+{
+	unsigned char c;
+
+	__asm__ __volatile__(
+		LOCK "decl %0; setg %1"
+		:"=m" (v->counter), "=qm" (c)
+		:"m" (v->counter) : "memory");
+	return c !=0;
+}
+
+/**
  * atomic_inc_and_test - increment and test 
  * @v: pointer of type atomic_t
  * 
include/asm-i386/spinlock.h +10 -0
diff -ur 2.5.59-orig/include/asm-i386/spinlock.h 2.5.59-rdlcks/include/asm-i386/spinlock.h
@@ -159,6 +159,7 @@
 #define rwlock_init(x)	do { *(x) = RW_LOCK_UNLOCKED; } while(0)
 
 #define rwlock_is_locked(x) ((x)->lock != RW_LOCK_BIAS)
+#define rwlock_is_wrlocked(x) ((x)->lock <= 0)
 
 /*
  * On x86, we implement read-write locks as a 32-bit counter
@@ -201,4 +202,13 @@
 	return 0;
 }
 
+static inline int _raw_read_trylock(rwlock_t *lock)
+{
+	atomic_t *count = (atomic_t *)lock;
+	if (atomic_dec_positive(count))
+		return 1;
+	atomic_inc(count);
+	return 0;
+}
+
 #endif /* __ASM_SPINLOCK_H */
include/linux/spinlock.h +11 -2
diff -ur 2.5.59-orig/include/linux/spinlock.h 2.5.59-rdlcks/include/linux/spinlock.h
@@ -91,11 +91,13 @@
 #define write_trylock(lock)	({preempt_disable();_raw_write_trylock(lock) ? \
 				1 : ({preempt_enable(); 0;});})
 
-/* Where's read_trylock? */
+#define read_trylock(lock)	({preempt_disable();_raw_read_trylock(lock) ? \
+				1 : ({preempt_enable(); 0;});})
 
 #if defined(CONFIG_SMP) && defined(CONFIG_PREEMPT)
 void __preempt_spin_lock(spinlock_t *lock);
 void __preempt_write_lock(rwlock_t *lock);
+void __preempt_read_lock(rwlock_t *lock);
 
 #define spin_lock(lock) \
 do { \
@@ -111,6 +113,13 @@
 		__preempt_write_lock(lock); \
 } while (0)
 
+#define read_lock(lock) \
+do { \
+	preempt_disable(); \
+	if (unlikely(!_raw_read_trylock(lock))) \
+		__preempt_read_lock(lock); \
+} while (0)
+
 #else
 #define spin_lock(lock)	\
 do { \
@@ -123,13 +132,13 @@
 	preempt_disable(); \
 	_raw_write_lock(lock); \
 } while(0)
-#endif
 
 #define read_lock(lock)	\
 do { \
 	preempt_disable(); \
 	_raw_read_lock(lock); \
 } while(0)
+#endif
 
 #define spin_unlock(lock) \
 do { \
kernel/ksyms.c +1 -0
diff -ur 2.5.59-orig/kernel/ksyms.c 2.5.59-rdlcks/kernel/ksyms.c
@@ -496,6 +496,7 @@
 #if defined(CONFIG_SMP) && defined(CONFIG_PREEMPT)
 EXPORT_SYMBOL(__preempt_spin_lock);
 EXPORT_SYMBOL(__preempt_write_lock);
+EXPORT_SYMBOL(__preempt_read_lock);
 #endif
 #if !defined(__ia64__)
 EXPORT_SYMBOL(loops_per_jiffy);
kernel/sched.c +26 -15

55 lines not on this page · raw message