sched/wait: Reimplement wait_event_freezable()
authorPeter Zijlstra <peterz@infradead.org>
Wed, 29 Oct 2014 11:21:57 +0000 (12:21 +0100)
committerIngo Molnar <mingo@kernel.org>
Tue, 4 Nov 2014 06:17:45 +0000 (07:17 +0100)
Provide better implementations of wait_event_freezable() APIs.

The problem is with freezer_do_not_count(), it hides the thread from
the freezer, even though this thread might not actually freeze/sleep
at all.

Cc: oleg@redhat.com
Cc: Rafael Wysocki <rjw@rjwysocki.net>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Len Brown <len.brown@intel.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Pavel Machek <pavel@ucw.cz>
Cc: Rafael J. Wysocki <rjw@rjwysocki.net>
Cc: linux-pm@vger.kernel.org
Link: http://lkml.kernel.org/n/tip-d86fz1jmso9wjxa8jfpinp8o@git.kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
include/linux/freezer.h
include/linux/wait.h

index 7fd81b8..e203665 100644 (file)
@@ -265,35 +265,6 @@ static inline int freezable_schedule_hrtimeout_range(ktime_t *expires,
        __retval;                                                       \
 })
 
-#define wait_event_freezable(wq, condition)                            \
-({                                                                     \
-       int __retval;                                                   \
-       freezer_do_not_count();                                         \
-       __retval = wait_event_interruptible(wq, (condition));           \
-       freezer_count();                                                \
-       __retval;                                                       \
-})
-
-#define wait_event_freezable_timeout(wq, condition, timeout)           \
-({                                                                     \
-       long __retval = timeout;                                        \
-       freezer_do_not_count();                                         \
-       __retval = wait_event_interruptible_timeout(wq, (condition),    \
-                               __retval);                              \
-       freezer_count();                                                \
-       __retval;                                                       \
-})
-
-#define wait_event_freezable_exclusive(wq, condition)                  \
-({                                                                     \
-       int __retval;                                                   \
-       freezer_do_not_count();                                         \
-       __retval = wait_event_interruptible_exclusive(wq, condition);   \
-       freezer_count();                                                \
-       __retval;                                                       \
-})
-
-
 #else /* !CONFIG_FREEZER */
 static inline bool frozen(struct task_struct *p) { return false; }
 static inline bool freezing(struct task_struct *p) { return false; }
@@ -331,15 +302,6 @@ static inline void set_freezable(void) {}
 #define freezable_schedule_hrtimeout_range(expires, delta, mode)       \
        schedule_hrtimeout_range(expires, delta, mode)
 
-#define wait_event_freezable(wq, condition)                            \
-               wait_event_interruptible(wq, condition)
-
-#define wait_event_freezable_timeout(wq, condition, timeout)           \
-               wait_event_interruptible_timeout(wq, condition, timeout)
-
-#define wait_event_freezable_exclusive(wq, condition)                  \
-               wait_event_interruptible_exclusive(wq, condition)
-
 #define wait_event_freezekillable(wq, condition)               \
                wait_event_killable(wq, condition)
 
index 0421775..2232ed1 100644 (file)
@@ -267,6 +267,31 @@ do {                                                                       \
        __wait_event(wq, condition);                                    \
 } while (0)
 
+#define __wait_event_freezable(wq, condition)                          \
+       ___wait_event(wq, condition, TASK_INTERRUPTIBLE, 0, 0,          \
+                           schedule(); try_to_freeze())
+
+/**
+ * wait_event - sleep (or freeze) until a condition gets true
+ * @wq: the waitqueue to wait on
+ * @condition: a C expression for the event to wait for
+ *
+ * The process is put to sleep (TASK_INTERRUPTIBLE -- so as not to contribute
+ * to system load) until the @condition evaluates to true. The
+ * @condition is checked each time the waitqueue @wq is woken up.
+ *
+ * wake_up() has to be called after changing any variable that could
+ * change the result of the wait condition.
+ */
+#define wait_event_freezable(wq, condition)                            \
+({                                                                     \
+       int __ret = 0;                                                  \
+       might_sleep();                                                  \
+       if (!(condition))                                               \
+               __ret = __wait_event_freezable(wq, condition);          \
+       __ret;                                                          \
+})
+
 #define __wait_event_timeout(wq, condition, timeout)                   \
        ___wait_event(wq, ___wait_cond_timeout(condition),              \
                      TASK_UNINTERRUPTIBLE, 0, timeout,                 \
@@ -300,6 +325,24 @@ do {                                                                       \
        __ret;                                                          \
 })
 
+#define __wait_event_freezable_timeout(wq, condition, timeout)         \
+       ___wait_event(wq, ___wait_cond_timeout(condition),              \
+                     TASK_INTERRUPTIBLE, 0, timeout,                   \
+                     __ret = schedule_timeout(__ret); try_to_freeze())
+
+/*
+ * like wait_event_timeout() -- except it uses TASK_INTERRUPTIBLE to avoid
+ * increasing load and is freezable.
+ */
+#define wait_event_freezable_timeout(wq, condition, timeout)           \
+({                                                                     \
+       long __ret = timeout;                                           \
+       might_sleep();                                                  \
+       if (!___wait_cond_timeout(condition))                           \
+               __ret = __wait_event_freezable_timeout(wq, condition, timeout); \
+       __ret;                                                          \
+})
+
 #define __wait_event_cmd(wq, condition, cmd1, cmd2)                    \
        (void)___wait_event(wq, condition, TASK_UNINTERRUPTIBLE, 0, 0,  \
                            cmd1; schedule(); cmd2)
@@ -480,6 +523,20 @@ do {                                                                       \
 })
 
 
+#define __wait_event_freezable_exclusive(wq, condition)                        \
+       ___wait_event(wq, condition, TASK_INTERRUPTIBLE, 1, 0,          \
+                       schedule(); try_to_freeze())
+
+#define wait_event_freezable_exclusive(wq, condition)                  \
+({                                                                     \
+       int __ret = 0;                                                  \
+       might_sleep();                                                  \
+       if (!(condition))                                               \
+               __ret = __wait_event_freezable_exclusive(wq, condition);\
+       __ret;                                                          \
+})
+
+
 #define __wait_event_interruptible_locked(wq, condition, exclusive, irq) \
 ({                                                                     \
        int __ret = 0;                                                  \