bnx2x: fix typos in "configure"
[pandora-kernel.git] / kernel / sched / wait.c
index 15cab1a..852143a 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/mm.h>
 #include <linux/wait.h>
 #include <linux/hash.h>
+#include <linux/kthread.h>
 
 void __init_waitqueue_head(wait_queue_head_t *q, const char *name, struct lock_class_key *key)
 {
@@ -297,6 +298,71 @@ int autoremove_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *
 }
 EXPORT_SYMBOL(autoremove_wake_function);
 
+static inline bool is_kthread_should_stop(void)
+{
+       return (current->flags & PF_KTHREAD) && kthread_should_stop();
+}
+
+/*
+ * 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) && !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.
+        */
+       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)
 {
        struct wait_bit_key *key = arg;
@@ -343,6 +409,18 @@ int __sched out_of_line_wait_on_bit(void *word, int bit,
 }
 EXPORT_SYMBOL(out_of_line_wait_on_bit);
 
+int __sched out_of_line_wait_on_bit_timeout(
+       void *word, int bit, wait_bit_action_f *action,
+       unsigned mode, unsigned long timeout)
+{
+       wait_queue_head_t *wq = bit_waitqueue(word, bit);
+       DEFINE_WAIT_BIT(wait, word, bit);
+
+       wait.key.timeout = jiffies + timeout;
+       return __wait_on_bit(wq, &wait, action, mode);
+}
+EXPORT_SYMBOL_GPL(out_of_line_wait_on_bit_timeout);
+
 int __sched
 __wait_on_bit_lock(wait_queue_head_t *wq, struct wait_bit_queue *q,
                        wait_bit_action_f *action, unsigned mode)
@@ -520,3 +598,27 @@ __sched int bit_wait_io(struct wait_bit_key *word)
        return 0;
 }
 EXPORT_SYMBOL(bit_wait_io);
+
+__sched int bit_wait_timeout(struct wait_bit_key *word)
+{
+       unsigned long now = ACCESS_ONCE(jiffies);
+       if (signal_pending_state(current->state, current))
+               return 1;
+       if (time_after_eq(now, word->timeout))
+               return -EAGAIN;
+       schedule_timeout(word->timeout - now);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(bit_wait_timeout);
+
+__sched int bit_wait_io_timeout(struct wait_bit_key *word)
+{
+       unsigned long now = ACCESS_ONCE(jiffies);
+       if (signal_pending_state(current->state, current))
+               return 1;
+       if (time_after_eq(now, word->timeout))
+               return -EAGAIN;
+       io_schedule_timeout(word->timeout - now);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(bit_wait_io_timeout);