diff options
author | Peter Zijlstra <peterz@infradead.org> | 2015-06-17 08:29:24 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2015-06-18 18:09:56 -0400 |
commit | c4bfa3f5f906aee2e084c5b1fb15caf876338ef8 (patch) | |
tree | 0b6892c0cee030274dbb0b4998e1f854762a0fd5 | |
parent | a7c6f571ff51cc77d90dd54968f7c5c938c43998 (diff) |
seqcount: Introduce raw_write_seqcount_barrier()
Introduce raw_write_seqcount_barrier(), a new construct that can be
used to provide write barrier semantics in seqcount read loops instead
of the usual consistency guarantee.
raw_write_seqcount_barier() is equivalent to:
raw_write_seqcount_begin();
raw_write_seqcount_end();
But avoids issueing two back-to-back smp_wmb() instructions.
This construct works because the read side will 'stall' when observing
odd values. This means that -- referring to the example in the comment
below -- even though there is no (matching) read barrier between the
loads of X and Y, we cannot observe !x && !y, because:
- if we observe Y == false we must observe the first sequence
increment, which makes us loop, until
- we observe !(seq & 1) -- the second sequence increment -- at which
time we must also observe T == true.
Suggested-by: Oleg Nesterov <oleg@redhat.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: umgwanakikbuti@gmail.com
Cc: ktkhai@parallels.com
Cc: rostedt@goodmis.org
Cc: juri.lelli@gmail.com
Cc: pang.xunlei@linaro.org
Cc: oleg@redhat.com
Cc: wanpeng.li@linux.intel.com
Cc: Al Viro <viro@ZenIV.linux.org.uk>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Link: http://lkml.kernel.org/r/20150617122924.GP3644@twins.programming.kicks-ass.net
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r-- | include/linux/seqlock.h | 41 |
1 files changed, 41 insertions, 0 deletions
diff --git a/include/linux/seqlock.h b/include/linux/seqlock.h index c07e3a536099..486e685a226a 100644 --- a/include/linux/seqlock.h +++ b/include/linux/seqlock.h | |||
@@ -233,6 +233,47 @@ static inline void raw_write_seqcount_end(seqcount_t *s) | |||
233 | s->sequence++; | 233 | s->sequence++; |
234 | } | 234 | } |
235 | 235 | ||
236 | /** | ||
237 | * raw_write_seqcount_barrier - do a seq write barrier | ||
238 | * @s: pointer to seqcount_t | ||
239 | * | ||
240 | * This can be used to provide an ordering guarantee instead of the | ||
241 | * usual consistency guarantee. It is one wmb cheaper, because we can | ||
242 | * collapse the two back-to-back wmb()s. | ||
243 | * | ||
244 | * seqcount_t seq; | ||
245 | * bool X = true, Y = false; | ||
246 | * | ||
247 | * void read(void) | ||
248 | * { | ||
249 | * bool x, y; | ||
250 | * | ||
251 | * do { | ||
252 | * int s = read_seqcount_begin(&seq); | ||
253 | * | ||
254 | * x = X; y = Y; | ||
255 | * | ||
256 | * } while (read_seqcount_retry(&seq, s)); | ||
257 | * | ||
258 | * BUG_ON(!x && !y); | ||
259 | * } | ||
260 | * | ||
261 | * void write(void) | ||
262 | * { | ||
263 | * Y = true; | ||
264 | * | ||
265 | * raw_write_seqcount_barrier(seq); | ||
266 | * | ||
267 | * X = false; | ||
268 | * } | ||
269 | */ | ||
270 | static inline void raw_write_seqcount_barrier(seqcount_t *s) | ||
271 | { | ||
272 | s->sequence++; | ||
273 | smp_wmb(); | ||
274 | s->sequence++; | ||
275 | } | ||
276 | |||
236 | /* | 277 | /* |
237 | * raw_write_seqcount_latch - redirect readers to even/odd copy | 278 | * raw_write_seqcount_latch - redirect readers to even/odd copy |
238 | * @s: pointer to seqcount_t | 279 | * @s: pointer to seqcount_t |