closures: Add closure_wait_event_timeout()
authorKent Overstreet <kent.overstreet@linux.dev>
Mon, 7 Oct 2024 20:54:11 +0000 (16:54 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Wed, 9 Oct 2024 20:57:57 +0000 (16:57 -0400)
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 <colyli@suse.de>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
include/linux/closure.h

index 2af44427107de9d7a9102f577e8d343e8b1afcfe..880fe85e35e99998fc535e54d6786d59bceaebf8 100644 (file)
@@ -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 */