xref: /linux-6.15/include/linux/rcuwait.h (revision 82d00a93)
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