swait: Add idle variants which don't contribute to load average
authorLuis R. Rodriguez <mcgrof@kernel.org>
Tue, 20 Jun 2017 21:45:46 +0000 (14:45 -0700)
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>
Thu, 17 Aug 2017 14:26:07 +0000 (07:26 -0700)
There are cases where folks are using an interruptible swait when
using kthreads. This is rather confusing given you'd expect
interruptible waits to be -- interruptible, but kthreads are not
interruptible ! The reason for such practice though is to avoid
having these kthreads contribute to the system load average.

When systems are idle some kthreads may spend a lot of time blocking if
using swait_event_timeout(). This would contribute to the system load
average. On systems without preemption this would mean the load average
of an idle system is bumped to 2 instead of 0. On systems with PREEMPT=y
this would mean the load average of an idle system is bumped to 3
instead of 0.

This adds proper API using TASK_IDLE to make such goals explicit and
avoid confusion.

Suggested-by: "Eric W. Biederman" <ebiederm@xmission.com>
Acked-by: "Eric W. Biederman" <ebiederm@xmission.com>
Tested-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Signed-off-by: Luis R. Rodriguez <mcgrof@kernel.org>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
include/linux/swait.h

index c1f9c62a8a507d1b4bfde42c0201cefabdef7675..4a4e180d0a3572fbb0719677db50d644a40c8f63 100644 (file)
@@ -169,4 +169,59 @@ do {                                                                       \
        __ret;                                                          \
 })
 
+#define __swait_event_idle(wq, condition)                              \
+       (void)___swait_event(wq, condition, TASK_IDLE, 0, schedule())
+
+/**
+ * swait_event_idle - wait without system load contribution
+ * @wq: the waitqueue to wait on
+ * @condition: a C expression for the event to wait for
+ *
+ * The process is put to sleep (TASK_IDLE) until the @condition evaluates to
+ * true. The @condition is checked each time the waitqueue @wq is woken up.
+ *
+ * This function is mostly used when a kthread or workqueue waits for some
+ * condition and doesn't want to contribute to system load. Signals are
+ * ignored.
+ */
+#define swait_event_idle(wq, condition)                                        \
+do {                                                                   \
+       if (condition)                                                  \
+               break;                                                  \
+       __swait_event_idle(wq, condition);                              \
+} while (0)
+
+#define __swait_event_idle_timeout(wq, condition, timeout)             \
+       ___swait_event(wq, ___wait_cond_timeout(condition),             \
+                      TASK_IDLE, timeout,                              \
+                      __ret = schedule_timeout(__ret))
+
+/**
+ * swait_event_idle_timeout - wait up to timeout without load contribution
+ * @wq: the waitqueue to wait on
+ * @condition: a C expression for the event to wait for
+ * @timeout: timeout at which we'll give up in jiffies
+ *
+ * The process is put to sleep (TASK_IDLE) until the @condition evaluates to
+ * true. The @condition is checked each time the waitqueue @wq is woken up.
+ *
+ * This function is mostly used when a kthread or workqueue waits for some
+ * condition and doesn't want to contribute to system load. Signals are
+ * ignored.
+ *
+ * Returns:
+ * 0 if the @condition evaluated to %false after the @timeout elapsed,
+ * 1 if the @condition evaluated to %true after the @timeout elapsed,
+ * or the remaining jiffies (at least 1) if the @condition evaluated
+ * to %true before the @timeout elapsed.
+ */
+#define swait_event_idle_timeout(wq, condition, timeout)               \
+({                                                                     \
+       long __ret = timeout;                                           \
+       if (!___wait_cond_timeout(condition))                           \
+               __ret = __swait_event_idle_timeout(wq,                  \
+                                                  condition, timeout); \
+       __ret;                                                          \
+})
+
 #endif /* _LINUX_SWAIT_H */