OSDN Git Service

rcuwait: Support timeouts
authorDavidlohr Bueso <dave@stgolabs.net>
Tue, 23 May 2023 17:09:24 +0000 (10:09 -0700)
committerDan Williams <dan.j.williams@intel.com>
Tue, 23 May 2023 19:55:12 +0000 (12:55 -0700)
The rcuwait utility provides an efficient and safe single
wait/wake mechanism. It is used in situations where queued
wait is the wrong semantics, and often too bulky. For example,
cases where the wait is already done under a lock.

In the past, rcuwait has been extended to support beyond only
uninterruptible sleep, and similarly, there are users that can
benefit for the addition of timeouts.

As such, tntroduce rcuwait_wait_event_timeout(), with semantics
equivalent to calls for queued wait counterparts.

Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Davidlohr Bueso <dave@stgolabs.net>
Link: https://lore.kernel.org/r/20230523170927.20685-2-dave@stgolabs.net
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
include/linux/rcuwait.h

index 8052d34..2734342 100644 (file)
@@ -49,9 +49,9 @@ static inline void prepare_to_rcuwait(struct rcuwait *w)
 
 extern void finish_rcuwait(struct rcuwait *w);
 
-#define rcuwait_wait_event(w, condition, state)                                \
+#define ___rcuwait_wait_event(w, condition, state, ret, cmd)           \
 ({                                                                     \
-       int __ret = 0;                                                  \
+       long __ret = ret;                                               \
        prepare_to_rcuwait(w);                                          \
        for (;;) {                                                      \
                /*                                                      \
@@ -67,10 +67,27 @@ extern void finish_rcuwait(struct rcuwait *w);
                        break;                                          \
                }                                                       \
                                                                        \
-               schedule();                                             \
+               cmd;                                                    \
        }                                                               \
        finish_rcuwait(w);                                              \
        __ret;                                                          \
 })
 
+#define rcuwait_wait_event(w, condition, state)                                \
+       ___rcuwait_wait_event(w, condition, state, 0, schedule())
+
+#define __rcuwait_wait_event_timeout(w, condition, state, timeout)     \
+       ___rcuwait_wait_event(w, ___wait_cond_timeout(condition),       \
+                             state, timeout,                           \
+                             __ret = schedule_timeout(__ret))
+
+#define rcuwait_wait_event_timeout(w, condition, state, timeout)       \
+({                                                                     \
+       long __ret = timeout;                                           \
+       if (!___wait_cond_timeout(condition))                           \
+               __ret = __rcuwait_wait_event_timeout(w, condition,      \
+                                                    state, timeout);   \
+       __ret;                                                          \
+})
+
 #endif /* _LINUX_RCUWAIT_H_ */