sched/wait: Change timeout logic
authorPeter Zijlstra <peterz@infradead.org>
Wed, 2 Oct 2013 09:22:19 +0000 (11:22 +0200)
committerIngo Molnar <mingo@kernel.org>
Fri, 4 Oct 2013 08:14:44 +0000 (10:14 +0200)
Commit 4c663cf ("wait: fix false timeouts when using
wait_event_timeout()") introduced an additional condition check after
a timeout but there's a few issues;

 - it forgot one site
 - it put the check after the main loop; not at the actual timeout
   check.

Cure both; by wrapping the condition (as suggested by Oleg), this
avoids double evaluation of 'condition' which could be quite big.

Reviewed-by: Oleg Nesterov <oleg@redhat.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/20131002092528.028892896@infradead.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
include/linux/wait.h

index ccf0c529fd375a590b26047fa0b805a38421dd30..b2afd665e4ea288877e2315c8d9e3092ccd878f4 100644 (file)
@@ -179,6 +179,14 @@ wait_queue_head_t *bit_waitqueue(void *, int);
 #define wake_up_interruptible_sync_poll(x, m)                          \
        __wake_up_sync_key((x), TASK_INTERRUPTIBLE, 1, (void *) (m))
 
+#define ___wait_cond_timeout(condition, ret)                           \
+({                                                                     \
+       bool __cond = (condition);                                      \
+       if (__cond && !ret)                                             \
+               ret = 1;                                                \
+       __cond || !ret;                                                 \
+})
+
 #define __wait_event(wq, condition)                                    \
 do {                                                                   \
        DEFINE_WAIT(__wait);                                            \
@@ -217,14 +225,10 @@ do {                                                                      \
                                                                        \
        for (;;) {                                                      \
                prepare_to_wait(&wq, &__wait, TASK_UNINTERRUPTIBLE);    \
-               if (condition)                                          \
+               if (___wait_cond_timeout(condition, ret))               \
                        break;                                          \
                ret = schedule_timeout(ret);                            \
-               if (!ret)                                               \
-                       break;                                          \
        }                                                               \
-       if (!ret && (condition))                                        \
-               ret = 1;                                                \
        finish_wait(&wq, &__wait);                                      \
 } while (0)
 
@@ -299,18 +303,14 @@ do {                                                                      \
                                                                        \
        for (;;) {                                                      \
                prepare_to_wait(&wq, &__wait, TASK_INTERRUPTIBLE);      \
-               if (condition)                                          \
+               if (___wait_cond_timeout(condition, ret))               \
                        break;                                          \
                if (signal_pending(current)) {                          \
                        ret = -ERESTARTSYS;                             \
                        break;                                          \
                }                                                       \
                ret = schedule_timeout(ret);                            \
-               if (!ret)                                               \
-                       break;                                          \
        }                                                               \
-       if (!ret && (condition))                                        \
-               ret = 1;                                                \
        finish_wait(&wq, &__wait);                                      \
 } while (0)
 
@@ -815,7 +815,7 @@ do {                                                                        \
                                                                        \
        for (;;) {                                                      \
                prepare_to_wait(&wq, &__wait, TASK_INTERRUPTIBLE);      \
-               if (condition)                                          \
+               if (___wait_cond_timeout(condition, ret))               \
                        break;                                          \
                if (signal_pending(current)) {                          \
                        ret = -ERESTARTSYS;                             \
@@ -824,8 +824,6 @@ do {                                                                        \
                spin_unlock_irq(&lock);                                 \
                ret = schedule_timeout(ret);                            \
                spin_lock_irq(&lock);                                   \
-               if (!ret)                                               \
-                       break;                                          \
        }                                                               \
        finish_wait(&wq, &__wait);                                      \
 } while (0)