Add a closure version of wait_event_timeout(), with the same semantics.

The closure version is useful because unlike wait_event(), it allows
blocking code to run in the conditional expression.

Cc: Coly Li <[email protected]>
Signed-off-by: Kent Overstreet <[email protected]>
---
 include/linux/closure.h | 35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/include/linux/closure.h b/include/linux/closure.h
index 2af44427107d..880fe85e35e9 100644
--- a/include/linux/closure.h
+++ b/include/linux/closure.h
@@ -454,4 +454,39 @@ do {                                                       
                \
                __closure_wait_event(waitlist, _cond);                  \
 } while (0)
 
+#define __closure_wait_event_timeout(waitlist, _cond, _until)          \
+({                                                                     \
+       struct closure cl;                                              \
+       long _t;                                                        \
+                                                                       \
+       closure_init_stack(&cl);                                        \
+                                                                       \
+       while (1) {                                                     \
+               closure_wait(waitlist, &cl);                            \
+               if (_cond) {                                            \
+                       _t = max_t(long, 1L, _until - jiffies);         \
+                       break;                                          \
+               }                                                       \
+               _t = max_t(long, 0L, _until - jiffies);                 \
+               if (!_t)                                                \
+                       break;                                          \
+               closure_sync_timeout(&cl, _t);                          \
+       }                                                               \
+       closure_wake_up(waitlist);                                      \
+       closure_sync(&cl);                                              \
+       _t;                                                             \
+})
+
+/*
+ * Returns 0 if timeout expired, remaining time in jiffies (at least 1) if
+ * condition became true
+ */
+#define closure_wait_event_timeout(waitlist, _cond, _timeout)          \
+({                                                                     \
+       unsigned long _until = jiffies + _timeout;                      \
+       (_cond)                                                         \
+               ? max_t(long, 1L, _until - jiffies)                     \
+               : __closure_wait_event_timeout(waitlist, _cond, _until);\
+})
+
 #endif /* _LINUX_CLOSURE_H */
-- 
2.45.2


Reply via email to