|
@@ -297,6 +297,67 @@ int autoremove_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(autoremove_wake_function);
|
|
EXPORT_SYMBOL(autoremove_wake_function);
|
|
|
|
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * DEFINE_WAIT_FUNC(wait, woken_wake_func);
|
|
|
|
+ *
|
|
|
|
+ * add_wait_queue(&wq, &wait);
|
|
|
|
+ * for (;;) {
|
|
|
|
+ * if (condition)
|
|
|
|
+ * break;
|
|
|
|
+ *
|
|
|
|
+ * p->state = mode; condition = true;
|
|
|
|
+ * smp_mb(); // A smp_wmb(); // C
|
|
|
|
+ * if (!wait->flags & WQ_FLAG_WOKEN) wait->flags |= WQ_FLAG_WOKEN;
|
|
|
|
+ * schedule() try_to_wake_up();
|
|
|
|
+ * p->state = TASK_RUNNING; ~~~~~~~~~~~~~~~~~~
|
|
|
|
+ * wait->flags &= ~WQ_FLAG_WOKEN; condition = true;
|
|
|
|
+ * smp_mb() // B smp_wmb(); // C
|
|
|
|
+ * wait->flags |= WQ_FLAG_WOKEN;
|
|
|
|
+ * }
|
|
|
|
+ * remove_wait_queue(&wq, &wait);
|
|
|
|
+ *
|
|
|
|
+ */
|
|
|
|
+long wait_woken(wait_queue_t *wait, 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.
|
|
|
|
+ */
|
|
|
|
+ if (!(wait->flags & WQ_FLAG_WOKEN))
|
|
|
|
+ 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.
|
|
|
|
+ */
|
|
|
|
+ set_mb(wait->flags, wait->flags & ~WQ_FLAG_WOKEN); /* B */
|
|
|
|
+
|
|
|
|
+ return timeout;
|
|
|
|
+}
|
|
|
|
+EXPORT_SYMBOL(wait_woken);
|
|
|
|
+
|
|
|
|
+int woken_wake_function(wait_queue_t *wait, 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 set_mb() in wait_woken().
|
|
|
|
+ */
|
|
|
|
+ smp_wmb(); /* C */
|
|
|
|
+ wait->flags |= WQ_FLAG_WOKEN;
|
|
|
|
+
|
|
|
|
+ return default_wake_function(wait, mode, sync, key);
|
|
|
|
+}
|
|
|
|
+EXPORT_SYMBOL(woken_wake_function);
|
|
|
|
+
|
|
int wake_bit_function(wait_queue_t *wait, unsigned mode, int sync, void *arg)
|
|
int wake_bit_function(wait_queue_t *wait, unsigned mode, int sync, void *arg)
|
|
{
|
|
{
|
|
struct wait_bit_key *key = arg;
|
|
struct wait_bit_key *key = arg;
|