public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] preemptive spin readlocks for 2.5
@ 2003-01-30  0:49 Joe Korty
  0 siblings, 0 replies; only message in thread
From: Joe Korty @ 2003-01-30  0:49 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel

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.


diff -ur 2.5.59-orig/include/asm-i386/atomic.h 2.5.59-rdlcks/include/asm-i386/atomic.h
--- 2.5.59-orig/include/asm-i386/atomic.h	2003-01-22 06:02:30.000000000 -0500
+++ 2.5.59-rdlcks/include/asm-i386/atomic.h	2003-01-29 08:51:31.000000000 -0500
@@ -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
  * 
diff -ur 2.5.59-orig/include/asm-i386/spinlock.h 2.5.59-rdlcks/include/asm-i386/spinlock.h
--- 2.5.59-orig/include/asm-i386/spinlock.h	2003-01-22 06:02:29.000000000 -0500
+++ 2.5.59-rdlcks/include/asm-i386/spinlock.h	2003-01-29 18:03:21.000000000 -0500
@@ -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 */
diff -ur 2.5.59-orig/include/linux/spinlock.h 2.5.59-rdlcks/include/linux/spinlock.h
--- 2.5.59-orig/include/linux/spinlock.h	2003-01-22 06:02:37.000000000 -0500
+++ 2.5.59-rdlcks/include/linux/spinlock.h	2003-01-29 18:04:28.000000000 -0500
@@ -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 { \
diff -ur 2.5.59-orig/kernel/ksyms.c 2.5.59-rdlcks/kernel/ksyms.c
--- 2.5.59-orig/kernel/ksyms.c	2003-01-22 06:02:16.000000000 -0500
+++ 2.5.59-rdlcks/kernel/ksyms.c	2003-01-28 17:22:03.000000000 -0500
@@ -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);
diff -ur 2.5.59-orig/kernel/sched.c 2.5.59-rdlcks/kernel/sched.c
--- 2.5.59-orig/kernel/sched.c	2003-01-22 06:02:55.000000000 -0500
+++ 2.5.59-rdlcks/kernel/sched.c	2003-01-29 18:04:59.000000000 -0500
@@ -2465,15 +2465,13 @@
 		_raw_spin_lock(lock);
 		return;
 	}
-
-	while (!_raw_spin_trylock(lock)) {
-		if (need_resched()) {
-			preempt_enable_no_resched();
-			__cond_resched();
-			preempt_disable();
+	do {
+		preempt_enable();
+		while(spin_is_locked(lock)) {
+			cpu_relax();
 		}
-		cpu_relax();
-	}
+		preempt_disable();
+	} while (!_raw_spin_trylock(lock));
 }
 
 void __preempt_write_lock(rwlock_t *lock)
@@ -2482,14 +2480,27 @@
 		_raw_write_lock(lock);
 		return;
 	}
-
-	while (!_raw_write_trylock(lock)) {
-		if (need_resched()) {
-			preempt_enable_no_resched();
-			__cond_resched();
-			preempt_disable();
+	do {
+		preempt_enable();
+		while(rwlock_is_locked(lock)) {
+			cpu_relax();
 		}
-		cpu_relax();
+		preempt_disable();
+	} while (!_raw_write_trylock(lock));
+}
+
+void __preempt_read_lock(rwlock_t *lock)
+{
+	if (preempt_count() > 1) {
+		_raw_read_lock(lock);
+		return;
 	}
+	do {
+		preempt_enable();
+		while(rwlock_is_wrlocked(lock)) {
+			cpu_relax();
+		}
+		preempt_disable();
+	} while (!_raw_read_trylock(lock));
 }
 #endif

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2003-01-30  0:40 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2003-01-30  0:49 [PATCH] preemptive spin readlocks for 2.5 Joe Korty

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox