diff options
author | Waiman Long <Waiman.Long@hp.com> | 2015-04-24 14:56:33 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2015-05-08 06:36:41 -0400 |
commit | 6403bd7d0ea1878a487296114eccf78658d7dd7a (patch) | |
tree | e3684baad2226394d4a5b73022aeaa61827d4b76 /kernel/locking | |
parent | c1fb159db9f2e50e0f4025bed92a67a6a7bfa7b7 (diff) |
locking/qspinlock: Extract out code snippets for the next patch
This is a preparatory patch that extracts out the following 2 code
snippets to prepare for the next performance optimization patch.
1) the logic for the exchange of new and previous tail code words
into a new xchg_tail() function.
2) the logic for clearing the pending bit and setting the locked bit
into a new clear_pending_set_locked() function.
This patch also simplifies the trylock operation before queuing by
calling queued_spin_trylock() directly.
Signed-off-by: Waiman Long <Waiman.Long@hp.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Daniel J Blueman <daniel@numascale.com>
Cc: David Vrabel <david.vrabel@citrix.com>
Cc: Douglas Hatch <doug.hatch@hp.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Paolo Bonzini <paolo.bonzini@gmail.com>
Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Raghavendra K T <raghavendra.kt@linux.vnet.ibm.com>
Cc: Rik van Riel <riel@redhat.com>
Cc: Scott J Norton <scott.norton@hp.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: virtualization@lists.linux-foundation.org
Cc: xen-devel@lists.xenproject.org
Link: http://lkml.kernel.org/r/1429901803-29771-5-git-send-email-Waiman.Long@hp.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'kernel/locking')
-rw-r--r-- | kernel/locking/qspinlock.c | 79 |
1 files changed, 48 insertions, 31 deletions
diff --git a/kernel/locking/qspinlock.c b/kernel/locking/qspinlock.c index af9c2ef6e930..82bb4a9e9009 100644 --- a/kernel/locking/qspinlock.c +++ b/kernel/locking/qspinlock.c | |||
@@ -97,6 +97,42 @@ static inline struct mcs_spinlock *decode_tail(u32 tail) | |||
97 | #define _Q_LOCKED_PENDING_MASK (_Q_LOCKED_MASK | _Q_PENDING_MASK) | 97 | #define _Q_LOCKED_PENDING_MASK (_Q_LOCKED_MASK | _Q_PENDING_MASK) |
98 | 98 | ||
99 | /** | 99 | /** |
100 | * clear_pending_set_locked - take ownership and clear the pending bit. | ||
101 | * @lock: Pointer to queued spinlock structure | ||
102 | * | ||
103 | * *,1,0 -> *,0,1 | ||
104 | */ | ||
105 | static __always_inline void clear_pending_set_locked(struct qspinlock *lock) | ||
106 | { | ||
107 | atomic_add(-_Q_PENDING_VAL + _Q_LOCKED_VAL, &lock->val); | ||
108 | } | ||
109 | |||
110 | /** | ||
111 | * xchg_tail - Put in the new queue tail code word & retrieve previous one | ||
112 | * @lock : Pointer to queued spinlock structure | ||
113 | * @tail : The new queue tail code word | ||
114 | * Return: The previous queue tail code word | ||
115 | * | ||
116 | * xchg(lock, tail) | ||
117 | * | ||
118 | * p,*,* -> n,*,* ; prev = xchg(lock, node) | ||
119 | */ | ||
120 | static __always_inline u32 xchg_tail(struct qspinlock *lock, u32 tail) | ||
121 | { | ||
122 | u32 old, new, val = atomic_read(&lock->val); | ||
123 | |||
124 | for (;;) { | ||
125 | new = (val & _Q_LOCKED_PENDING_MASK) | tail; | ||
126 | old = atomic_cmpxchg(&lock->val, val, new); | ||
127 | if (old == val) | ||
128 | break; | ||
129 | |||
130 | val = old; | ||
131 | } | ||
132 | return old; | ||
133 | } | ||
134 | |||
135 | /** | ||
100 | * queued_spin_lock_slowpath - acquire the queued spinlock | 136 | * queued_spin_lock_slowpath - acquire the queued spinlock |
101 | * @lock: Pointer to queued spinlock structure | 137 | * @lock: Pointer to queued spinlock structure |
102 | * @val: Current value of the queued spinlock 32-bit word | 138 | * @val: Current value of the queued spinlock 32-bit word |
@@ -178,15 +214,7 @@ void queued_spin_lock_slowpath(struct qspinlock *lock, u32 val) | |||
178 | * | 214 | * |
179 | * *,1,0 -> *,0,1 | 215 | * *,1,0 -> *,0,1 |
180 | */ | 216 | */ |
181 | for (;;) { | 217 | clear_pending_set_locked(lock); |
182 | new = (val & ~_Q_PENDING_MASK) | _Q_LOCKED_VAL; | ||
183 | |||
184 | old = atomic_cmpxchg(&lock->val, val, new); | ||
185 | if (old == val) | ||
186 | break; | ||
187 | |||
188 | val = old; | ||
189 | } | ||
190 | return; | 218 | return; |
191 | 219 | ||
192 | /* | 220 | /* |
@@ -203,37 +231,26 @@ queue: | |||
203 | node->next = NULL; | 231 | node->next = NULL; |
204 | 232 | ||
205 | /* | 233 | /* |
206 | * We have already touched the queueing cacheline; don't bother with | 234 | * We touched a (possibly) cold cacheline in the per-cpu queue node; |
207 | * pending stuff. | 235 | * attempt the trylock once more in the hope someone let go while we |
208 | * | 236 | * weren't watching. |
209 | * trylock || xchg(lock, node) | ||
210 | * | ||
211 | * 0,0,0 -> 0,0,1 ; no tail, not locked -> no tail, locked. | ||
212 | * p,y,x -> n,y,x ; tail was p -> tail is n; preserving locked. | ||
213 | */ | 237 | */ |
214 | for (;;) { | 238 | if (queued_spin_trylock(lock)) |
215 | new = _Q_LOCKED_VAL; | 239 | goto release; |
216 | if (val) | ||
217 | new = tail | (val & _Q_LOCKED_PENDING_MASK); | ||
218 | |||
219 | old = atomic_cmpxchg(&lock->val, val, new); | ||
220 | if (old == val) | ||
221 | break; | ||
222 | |||
223 | val = old; | ||
224 | } | ||
225 | 240 | ||
226 | /* | 241 | /* |
227 | * we won the trylock; forget about queueing. | 242 | * We have already touched the queueing cacheline; don't bother with |
243 | * pending stuff. | ||
244 | * | ||
245 | * p,*,* -> n,*,* | ||
228 | */ | 246 | */ |
229 | if (new == _Q_LOCKED_VAL) | 247 | old = xchg_tail(lock, tail); |
230 | goto release; | ||
231 | 248 | ||
232 | /* | 249 | /* |
233 | * if there was a previous node; link it and wait until reaching the | 250 | * if there was a previous node; link it and wait until reaching the |
234 | * head of the waitqueue. | 251 | * head of the waitqueue. |
235 | */ | 252 | */ |
236 | if (old & ~_Q_LOCKED_PENDING_MASK) { | 253 | if (old & _Q_TAIL_MASK) { |
237 | prev = decode_tail(old); | 254 | prev = decode_tail(old); |
238 | WRITE_ONCE(prev->next, node); | 255 | WRITE_ONCE(prev->next, node); |
239 | 256 | ||