Whamcloud - gitweb
LU-12362 ptlrpc: use wait_woken() in ptlrpcd()
[fs/lustre-release.git] / libcfs / libcfs / linux / linux-wait.c
index 5843d80..33117c2 100644 (file)
@@ -113,3 +113,62 @@ void __init wait_bit_init(void)
                init_waitqueue_head(bit_wait_table + i);
 }
 #endif /* ! HAVE_WAIT_VAR_EVENT */
+
+#ifndef HAVE_WAIT_WOKEN
+/*
+ * DEFINE_WAIT_FUNC(wait, woken_wake_func);
+ *
+ * add_wait_queue(&wq_head, &wait);
+ * for (;;) {
+ *     if (condition)
+ *         break;
+ *
+ *     // 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 int mode,
+               long timeout)
+{
+       /*
+        * 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))
+               timeout = schedule_timeout(timeout);
+       __set_current_state(TASK_RUNNING);
+
+       /*
+        * 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 */
+
+       return timeout;
+}
+EXPORT_SYMBOL(wait_woken);
+
+int woken_wake_function(struct wait_queue_entry *wq_entry, unsigned int mode,
+                       int sync, void *key)
+{
+       /* 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);
+}
+EXPORT_SYMBOL(woken_wake_function);
+#endif /* HAVE_WAIT_WOKEN */