1 /* SPDX-License-Identifier: GPL-2.0 */ 2 #ifndef _LINUX_RCUWAIT_H_ 3 #define _LINUX_RCUWAIT_H_ 4 5 #include <linux/rcupdate.h> 6 #include <linux/sched/signal.h> 7 8 /* 9 * rcuwait provides a way of blocking and waking up a single 10 * task in an rcu-safe manner. 11 * 12 * The only time @task is non-nil is when a user is blocked (or 13 * checking if it needs to) on a condition, and reset as soon as we 14 * know that the condition has succeeded and are awoken. 15 */ 16 struct rcuwait { 17 struct task_struct __rcu *task; 18 }; 19 20 #define __RCUWAIT_INITIALIZER(name) \ 21 { .task = NULL, } 22 23 static inline void rcuwait_init(struct rcuwait *w) 24 { 25 w->task = NULL; 26 } 27 28 extern void rcuwait_wake_up(struct rcuwait *w); 29 30 /* 31 * The caller is responsible for locking around rcuwait_wait_event(), 32 * such that writes to @task are properly serialized. 33 */ 34 #define rcuwait_wait_event(w, condition, state) \ 35 ({ \ 36 int __ret = 0; \ 37 rcu_assign_pointer((w)->task, current); \ 38 for (;;) { \ 39 /* \ 40 * Implicit barrier (A) pairs with (B) in \ 41 * rcuwait_wake_up(). \ 42 */ \ 43 set_current_state(state); \ 44 if (condition) \ 45 break; \ 46 \ 47 if (signal_pending_state(state, current)) { \ 48 __ret = -EINTR; \ 49 break; \ 50 } \ 51 \ 52 schedule(); \ 53 } \ 54 \ 55 WRITE_ONCE((w)->task, NULL); \ 56 __set_current_state(TASK_RUNNING); \ 57 __ret; \ 58 }) 59 60 #endif /* _LINUX_RCUWAIT_H_ */ 61