[PATCH memory-model 12/14] doc: Update wake_up() & co. memory-barrier guarantees

2018-07-16 Thread Paul E. McKenney
From: Andrea Parri 

Both the implementation and the users' expectation [1] for the various
wakeup primitives have evolved over time, but the documentation has not
kept up with these changes: brings it into 2018.

[1] 
http://lkml.kernel.org/r/20180424091510.gb4...@hirez.programming.kicks-ass.net

Suggested-by: Peter Zijlstra 
Signed-off-by: Andrea Parri 
[ aparri: Apply feedback from Alan Stern. ]
Cc: Alan Stern 
Cc: Will Deacon 
Cc: Boqun Feng 
Cc: Nicholas Piggin 
Cc: David Howells 
Cc: Jade Alglave 
Cc: Luc Maranget 
Cc: Akira Yokosawa 
Cc: Daniel Lustig 
Cc: Jonathan Corbet 
Cc: Ingo Molnar 
Acked-by: Peter Zijlstra (Intel) 
Signed-off-by: Paul E. McKenney 
---
 Documentation/memory-barriers.txt | 43 +++
 include/linux/sched.h |  4 +--
 kernel/sched/completion.c |  8 +++---
 kernel/sched/core.c   | 30 +
 kernel/sched/wait.c   |  8 +++---
 5 files changed, 49 insertions(+), 44 deletions(-)

diff --git a/Documentation/memory-barriers.txt 
b/Documentation/memory-barriers.txt
index a02d6bbfc9d0..0d8d7ef131e9 100644
--- a/Documentation/memory-barriers.txt
+++ b/Documentation/memory-barriers.txt
@@ -2179,32 +2179,41 @@ or:
event_indicated = 1;
wake_up_process(event_daemon);
 
-A write memory barrier is implied by wake_up() and co.  if and only if they
-wake something up.  The barrier occurs before the task state is cleared, and so
-sits between the STORE to indicate the event and the STORE to set TASK_RUNNING:
+A general memory barrier is executed by wake_up() if it wakes something up.
+If it doesn't wake anything up then a memory barrier may or may not be
+executed; you must not rely on it.  The barrier occurs before the task state
+is accessed, in particular, it sits between the STORE to indicate the event
+and the STORE to set TASK_RUNNING:
 
-   CPU 1   CPU 2
+   CPU 1 (Sleeper) CPU 2 (Waker)
=== ===
set_current_state();STORE event_indicated
  smp_store_mb();   wake_up();
-   STORE current->state  
-STORE current->state
-   LOAD event_indicated
+   STORE current->state  ...
+
+   LOAD event_indicated  if ((LOAD task->state) & TASK_NORMAL)
+   STORE task->state
 
-To repeat, this write memory barrier is present if and only if something
-is actually awakened.  To see this, consider the following sequence of
-events, where X and Y are both initially zero:
+where "task" is the thread being woken up and it equals CPU 1's "current".
+
+To repeat, a general memory barrier is guaranteed to be executed by wake_up()
+if something is actually awakened, but otherwise there is no such guarantee.
+To see this, consider the following sequence of events, where X and Y are both
+initially zero:
 
CPU 1   CPU 2
=== ===
-   X = 1;  STORE event_indicated
+   X = 1;  Y = 1;
smp_mb();   wake_up();
-   Y = 1;  wait_event(wq, Y == 1);
-   wake_up();load from Y sees 1, no memory barrier
-   load from X might see 0
+   LOAD Y  LOAD X
+
+If a wakeup does occur, one (at least) of the two loads must see 1.  If, on
+the other hand, a wakeup does not occur, both loads might see 0.
 
-In contrast, if a wakeup does occur, CPU 2's load from X would be guaranteed
-to see 1.
+wake_up_process() always executes a general memory barrier.  The barrier again
+occurs before the task state is accessed.  In particular, if the wake_up() in
+the previous snippet were replaced by a call to wake_up_process() then one of
+the two loads would be guaranteed to see 1.
 
 The available waker functions include:
 
@@ -2224,6 +2233,8 @@ The available waker functions include:
wake_up_poll();
wake_up_process();
 
+In terms of memory ordering, these functions all provide the same guarantees of
+a wake_up() (or stronger).
 
 [!] Note that the memory barriers implied by the sleeper and the waker do _not_
 order multiple stores before the wake-up with respect to loads of those stored
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 87bf02d93a27..ddfdeb632f74 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -167,8 +167,8 @@ struct task_group;
  *   need_sleep = false;
  *   wake_up_state(p, TASK_UNINTERRUPTIBLE);
  *
- * Where wake_up_state() (and all other wakeup primitives) imply enough
- * barriers to order the store of the variable against wakeup.
+ * where wake_up_state() executes a full memory barrier before accessing the
+ 

[PATCH memory-model 12/14] doc: Update wake_up() & co. memory-barrier guarantees

2018-07-16 Thread Paul E. McKenney
From: Andrea Parri 

Both the implementation and the users' expectation [1] for the various
wakeup primitives have evolved over time, but the documentation has not
kept up with these changes: brings it into 2018.

[1] 
http://lkml.kernel.org/r/20180424091510.gb4...@hirez.programming.kicks-ass.net

Suggested-by: Peter Zijlstra 
Signed-off-by: Andrea Parri 
[ aparri: Apply feedback from Alan Stern. ]
Cc: Alan Stern 
Cc: Will Deacon 
Cc: Boqun Feng 
Cc: Nicholas Piggin 
Cc: David Howells 
Cc: Jade Alglave 
Cc: Luc Maranget 
Cc: Akira Yokosawa 
Cc: Daniel Lustig 
Cc: Jonathan Corbet 
Cc: Ingo Molnar 
Acked-by: Peter Zijlstra (Intel) 
Signed-off-by: Paul E. McKenney 
---
 Documentation/memory-barriers.txt | 43 +++
 include/linux/sched.h |  4 +--
 kernel/sched/completion.c |  8 +++---
 kernel/sched/core.c   | 30 +
 kernel/sched/wait.c   |  8 +++---
 5 files changed, 49 insertions(+), 44 deletions(-)

diff --git a/Documentation/memory-barriers.txt 
b/Documentation/memory-barriers.txt
index a02d6bbfc9d0..0d8d7ef131e9 100644
--- a/Documentation/memory-barriers.txt
+++ b/Documentation/memory-barriers.txt
@@ -2179,32 +2179,41 @@ or:
event_indicated = 1;
wake_up_process(event_daemon);
 
-A write memory barrier is implied by wake_up() and co.  if and only if they
-wake something up.  The barrier occurs before the task state is cleared, and so
-sits between the STORE to indicate the event and the STORE to set TASK_RUNNING:
+A general memory barrier is executed by wake_up() if it wakes something up.
+If it doesn't wake anything up then a memory barrier may or may not be
+executed; you must not rely on it.  The barrier occurs before the task state
+is accessed, in particular, it sits between the STORE to indicate the event
+and the STORE to set TASK_RUNNING:
 
-   CPU 1   CPU 2
+   CPU 1 (Sleeper) CPU 2 (Waker)
=== ===
set_current_state();STORE event_indicated
  smp_store_mb();   wake_up();
-   STORE current->state  
-STORE current->state
-   LOAD event_indicated
+   STORE current->state  ...
+
+   LOAD event_indicated  if ((LOAD task->state) & TASK_NORMAL)
+   STORE task->state
 
-To repeat, this write memory barrier is present if and only if something
-is actually awakened.  To see this, consider the following sequence of
-events, where X and Y are both initially zero:
+where "task" is the thread being woken up and it equals CPU 1's "current".
+
+To repeat, a general memory barrier is guaranteed to be executed by wake_up()
+if something is actually awakened, but otherwise there is no such guarantee.
+To see this, consider the following sequence of events, where X and Y are both
+initially zero:
 
CPU 1   CPU 2
=== ===
-   X = 1;  STORE event_indicated
+   X = 1;  Y = 1;
smp_mb();   wake_up();
-   Y = 1;  wait_event(wq, Y == 1);
-   wake_up();load from Y sees 1, no memory barrier
-   load from X might see 0
+   LOAD Y  LOAD X
+
+If a wakeup does occur, one (at least) of the two loads must see 1.  If, on
+the other hand, a wakeup does not occur, both loads might see 0.
 
-In contrast, if a wakeup does occur, CPU 2's load from X would be guaranteed
-to see 1.
+wake_up_process() always executes a general memory barrier.  The barrier again
+occurs before the task state is accessed.  In particular, if the wake_up() in
+the previous snippet were replaced by a call to wake_up_process() then one of
+the two loads would be guaranteed to see 1.
 
 The available waker functions include:
 
@@ -2224,6 +2233,8 @@ The available waker functions include:
wake_up_poll();
wake_up_process();
 
+In terms of memory ordering, these functions all provide the same guarantees of
+a wake_up() (or stronger).
 
 [!] Note that the memory barriers implied by the sleeper and the waker do _not_
 order multiple stores before the wake-up with respect to loads of those stored
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 87bf02d93a27..ddfdeb632f74 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -167,8 +167,8 @@ struct task_group;
  *   need_sleep = false;
  *   wake_up_state(p, TASK_UNINTERRUPTIBLE);
  *
- * Where wake_up_state() (and all other wakeup primitives) imply enough
- * barriers to order the store of the variable against wakeup.
+ * where wake_up_state() executes a full memory barrier before accessing the
+