aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorMichel Lespinasse <walken@google.com>2013-05-07 09:46:01 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-05-07 10:20:17 -0400
commita31a369b07cf306ae1de0b2d4a52c3821a570bf6 (patch)
tree935a847603f3079bb3fae78a544c6bbf79aedbef /arch/x86
parent25c39325968bbcebe6cd2a1991228c9dfb48d655 (diff)
x86 rwsem: avoid taking slow path when stealing write lock
modify __down_write[_nested] and __down_write_trylock to grab the write lock whenever the active count is 0, even if there are queued waiters (they must be writers pending wakeup, since the active count is 0). Note that this is an optimization only; architectures without this optimization will still work fine: - __down_write() would take the slow path which would take the wait_lock and then try stealing the lock (as in the spinlocked rwsem implementation) - __down_write_trylock() would fail, but callers must be ready to deal with that - since there are some writers pending wakeup, they could have raced with us and obtained the lock before we steal it. Signed-off-by: Michel Lespinasse <walken@google.com> Reviewed-by: Peter Hurley <peter@hurleysoftware.com> Acked-by: Davidlohr Bueso <davidlohr.bueso@hp.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/include/asm/rwsem.h28
1 files changed, 21 insertions, 7 deletions
diff --git a/arch/x86/include/asm/rwsem.h b/arch/x86/include/asm/rwsem.h
index 2dbe4a721ce5..cad82c9c2fde 100644
--- a/arch/x86/include/asm/rwsem.h
+++ b/arch/x86/include/asm/rwsem.h
@@ -105,8 +105,8 @@ static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
105 asm volatile("# beginning down_write\n\t" 105 asm volatile("# beginning down_write\n\t"
106 LOCK_PREFIX " xadd %1,(%2)\n\t" 106 LOCK_PREFIX " xadd %1,(%2)\n\t"
107 /* adds 0xffff0001, returns the old value */ 107 /* adds 0xffff0001, returns the old value */
108 " test %1,%1\n\t" 108 " test " __ASM_SEL(%w1,%k1) "," __ASM_SEL(%w1,%k1) "\n\t"
109 /* was the count 0 before? */ 109 /* was the active mask 0 before? */
110 " jz 1f\n" 110 " jz 1f\n"
111 " call call_rwsem_down_write_failed\n" 111 " call call_rwsem_down_write_failed\n"
112 "1:\n" 112 "1:\n"
@@ -126,11 +126,25 @@ static inline void __down_write(struct rw_semaphore *sem)
126 */ 126 */
127static inline int __down_write_trylock(struct rw_semaphore *sem) 127static inline int __down_write_trylock(struct rw_semaphore *sem)
128{ 128{
129 long ret = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE, 129 long result, tmp;
130 RWSEM_ACTIVE_WRITE_BIAS); 130 asm volatile("# beginning __down_write_trylock\n\t"
131 if (ret == RWSEM_UNLOCKED_VALUE) 131 " mov %0,%1\n\t"
132 return 1; 132 "1:\n\t"
133 return 0; 133 " test " __ASM_SEL(%w1,%k1) "," __ASM_SEL(%w1,%k1) "\n\t"
134 /* was the active mask 0 before? */
135 " jnz 2f\n\t"
136 " mov %1,%2\n\t"
137 " add %3,%2\n\t"
138 LOCK_PREFIX " cmpxchg %2,%0\n\t"
139 " jnz 1b\n\t"
140 "2:\n\t"
141 " sete %b1\n\t"
142 " movzbl %b1, %k1\n\t"
143 "# ending __down_write_trylock\n\t"
144 : "+m" (sem->count), "=&a" (result), "=&r" (tmp)
145 : "er" (RWSEM_ACTIVE_WRITE_BIAS)
146 : "memory", "cc");
147 return result;
134} 148}
135 149
136/* 150/*