|
@@ -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);
|