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 */ 16struct rcuwait { 17 struct task_struct __rcu *task; 18}; 19 20#define __RCUWAIT_INITIALIZER(name) \ 21 { .task = NULL, } 22 23static inline void rcuwait_init(struct rcuwait *w) 24{ 25 w->task = NULL; 26} 27 28/* 29 * Note: this provides no serialization and, just as with waitqueues, 30 * requires care to estimate as to whether or not the wait is active. 31 */ 32static inline int rcuwait_active(struct rcuwait *w) 33{ 34 return !!rcu_access_pointer(w->task); 35} 36 37extern int rcuwait_wake_up(struct rcuwait *w); 38 39/* 40 * The caller is responsible for locking around rcuwait_wait_event(), 41 * and [prepare_to/finish]_rcuwait() such that writes to @task are 42 * properly serialized. 43 */ 44 45static inline void prepare_to_rcuwait(struct rcuwait *w) 46{ 47 rcu_assign_pointer(w->task, current); 48} 49 50static inline void finish_rcuwait(struct rcuwait *w) 51{ 52 rcu_assign_pointer(w->task, NULL); 53 __set_current_state(TASK_RUNNING); 54} 55 56#define rcuwait_wait_event(w, condition, state) \ 57({ \ 58 int __ret = 0; \ 59 prepare_to_rcuwait(w); \ 60 for (;;) { \ 61 /* \ 62 * Implicit barrier (A) pairs with (B) in \ 63 * rcuwait_wake_up(). \ 64 */ \ 65 set_current_state(state); \ 66 if (condition) \ 67 break; \ 68 \ 69 if (signal_pending_state(state, current)) { \ 70 __ret = -EINTR; \ 71 break; \ 72 } \ 73 \ 74 schedule(); \ 75 } \ 76 finish_rcuwait(w); \ 77 __ret; \ 78}) 79 80#endif /* _LINUX_RCUWAIT_H_ */ 81