Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002 #ifndef _LINUX_RCUWAIT_H_
0003 #define _LINUX_RCUWAIT_H_
0004 
0005 #include <linux/rcupdate.h>
0006 #include <linux/sched/signal.h>
0007 
0008 /*
0009  * rcuwait provides a way of blocking and waking up a single
0010  * task in an rcu-safe manner.
0011  *
0012  * The only time @task is non-nil is when a user is blocked (or
0013  * checking if it needs to) on a condition, and reset as soon as we
0014  * know that the condition has succeeded and are awoken.
0015  */
0016 struct rcuwait {
0017     struct task_struct __rcu *task;
0018 };
0019 
0020 #define __RCUWAIT_INITIALIZER(name)     \
0021     { .task = NULL, }
0022 
0023 static inline void rcuwait_init(struct rcuwait *w)
0024 {
0025     w->task = NULL;
0026 }
0027 
0028 /*
0029  * Note: this provides no serialization and, just as with waitqueues,
0030  * requires care to estimate as to whether or not the wait is active.
0031  */
0032 static inline int rcuwait_active(struct rcuwait *w)
0033 {
0034     return !!rcu_access_pointer(w->task);
0035 }
0036 
0037 extern int rcuwait_wake_up(struct rcuwait *w);
0038 
0039 /*
0040  * The caller is responsible for locking around rcuwait_wait_event(),
0041  * and [prepare_to/finish]_rcuwait() such that writes to @task are
0042  * properly serialized.
0043  */
0044 
0045 static inline void prepare_to_rcuwait(struct rcuwait *w)
0046 {
0047     rcu_assign_pointer(w->task, current);
0048 }
0049 
0050 extern void finish_rcuwait(struct rcuwait *w);
0051 
0052 #define rcuwait_wait_event(w, condition, state)             \
0053 ({                                  \
0054     int __ret = 0;                          \
0055     prepare_to_rcuwait(w);                      \
0056     for (;;) {                          \
0057         /*                          \
0058          * Implicit barrier (A) pairs with (B) in       \
0059          * rcuwait_wake_up().                   \
0060          */                         \
0061         set_current_state(state);               \
0062         if (condition)                      \
0063             break;                      \
0064                                     \
0065         if (signal_pending_state(state, current)) {     \
0066             __ret = -EINTR;                 \
0067             break;                      \
0068         }                           \
0069                                     \
0070         schedule();                     \
0071     }                               \
0072     finish_rcuwait(w);                      \
0073     __ret;                              \
0074 })
0075 
0076 #endif /* _LINUX_RCUWAIT_H_ */