Merge tag 'locks-v4.19-1' of git://git.kernel.org/pub/scm/linux/kernel/git/jlayton...
[linux-2.6-microblaze.git] / kernel / sched / wait.c
index 928be52..870f97b 100644 (file)
@@ -134,8 +134,8 @@ static void __wake_up_common_lock(struct wait_queue_head *wq_head, unsigned int
  * @nr_exclusive: how many wake-one or wake-many threads to wake up
  * @key: is directly passed to the wakeup function
  *
- * It may be assumed that this function implies a write memory barrier before
- * changing the task state if and only if any tasks are woken up.
+ * If this function wakes up a task, it executes a full memory barrier before
+ * accessing the task state.
  */
 void __wake_up(struct wait_queue_head *wq_head, unsigned int mode,
                        int nr_exclusive, void *key)
@@ -180,8 +180,8 @@ EXPORT_SYMBOL_GPL(__wake_up_locked_key_bookmark);
  *
  * On UP it can prevent extra preemption.
  *
- * It may be assumed that this function implies a write memory barrier before
- * changing the task state if and only if any tasks are woken up.
+ * If this function wakes up a task, it executes a full memory barrier before
+ * accessing the task state.
  */
 void __wake_up_sync_key(struct wait_queue_head *wq_head, unsigned int mode,
                        int nr_exclusive, void *key)
@@ -392,35 +392,36 @@ static inline bool is_kthread_should_stop(void)
  *     if (condition)
  *         break;
  *
- *     p->state = mode;                                condition = true;
- *     smp_mb(); // A                          smp_wmb(); // C
- *     if (!wq_entry->flags & WQ_FLAG_WOKEN)   wq_entry->flags |= WQ_FLAG_WOKEN;
- *         schedule()                          try_to_wake_up();
- *     p->state = TASK_RUNNING;                    ~~~~~~~~~~~~~~~~~~
- *     wq_entry->flags &= ~WQ_FLAG_WOKEN;              condition = true;
- *     smp_mb() // B                           smp_wmb(); // C
- *                                             wq_entry->flags |= WQ_FLAG_WOKEN;
- * }
- * remove_wait_queue(&wq_head, &wait);
+ *     // in wait_woken()                      // in woken_wake_function()
  *
+ *     p->state = mode;                                wq_entry->flags |= WQ_FLAG_WOKEN;
+ *     smp_mb(); // A                          try_to_wake_up():
+ *     if (!(wq_entry->flags & WQ_FLAG_WOKEN))    <full barrier>
+ *         schedule()                             if (p->state & mode)
+ *     p->state = TASK_RUNNING;                              p->state = TASK_RUNNING;
+ *     wq_entry->flags &= ~WQ_FLAG_WOKEN;      ~~~~~~~~~~~~~~~~~~
+ *     smp_mb(); // B                          condition = true;
+ * }                                           smp_mb(); // C
+ * remove_wait_queue(&wq_head, &wait);         wq_entry->flags |= WQ_FLAG_WOKEN;
  */
 long wait_woken(struct wait_queue_entry *wq_entry, unsigned mode, long timeout)
 {
-       set_current_state(mode); /* A */
        /*
-        * The above implies an smp_mb(), which matches with the smp_wmb() from
-        * woken_wake_function() such that if we observe WQ_FLAG_WOKEN we must
-        * also observe all state before the wakeup.
+        * The below executes an smp_mb(), which matches with the full barrier
+        * executed by the try_to_wake_up() in woken_wake_function() such that
+        * either we see the store to wq_entry->flags in woken_wake_function()
+        * or woken_wake_function() sees our store to current->state.
         */
+       set_current_state(mode); /* A */
        if (!(wq_entry->flags & WQ_FLAG_WOKEN) && !is_kthread_should_stop())
                timeout = schedule_timeout(timeout);
        __set_current_state(TASK_RUNNING);
 
        /*
-        * The below implies an smp_mb(), it too pairs with the smp_wmb() from
-        * woken_wake_function() such that we must either observe the wait
-        * condition being true _OR_ WQ_FLAG_WOKEN such that we will not miss
-        * an event.
+        * The below executes an smp_mb(), which matches with the smp_mb() (C)
+        * in woken_wake_function() such that either we see the wait condition
+        * being true or the store to wq_entry->flags in woken_wake_function()
+        * follows ours in the coherence order.
         */
        smp_store_mb(wq_entry->flags, wq_entry->flags & ~WQ_FLAG_WOKEN); /* B */
 
@@ -430,14 +431,8 @@ EXPORT_SYMBOL(wait_woken);
 
 int woken_wake_function(struct wait_queue_entry *wq_entry, unsigned mode, int sync, void *key)
 {
-       /*
-        * Although this function is called under waitqueue lock, LOCK
-        * doesn't imply write barrier and the users expects write
-        * barrier semantics on wakeup functions.  The following
-        * smp_wmb() is equivalent to smp_wmb() in try_to_wake_up()
-        * and is paired with smp_store_mb() in wait_woken().
-        */
-       smp_wmb(); /* C */
+       /* Pairs with the smp_store_mb() in wait_woken(). */
+       smp_mb(); /* C */
        wq_entry->flags |= WQ_FLAG_WOKEN;
 
        return default_wake_function(wq_entry, mode, sync, key);