xref: /linux-6.15/include/linux/rcuwait.h (revision 2c2bd11c)
1b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */
28f95c90cSDavidlohr Bueso #ifndef _LINUX_RCUWAIT_H_
38f95c90cSDavidlohr Bueso #define _LINUX_RCUWAIT_H_
48f95c90cSDavidlohr Bueso 
58f95c90cSDavidlohr Bueso #include <linux/rcupdate.h>
680fbaf1cSPeter Zijlstra (Intel) #include <linux/sched/signal.h>
7*2c2bd11cSSuren Baghdasaryan #include <linux/types.h>
88f95c90cSDavidlohr Bueso 
98f95c90cSDavidlohr Bueso #define __RCUWAIT_INITIALIZER(name)		\
108f95c90cSDavidlohr Bueso 	{ .task = NULL, }
118f95c90cSDavidlohr Bueso 
rcuwait_init(struct rcuwait * w)128f95c90cSDavidlohr Bueso static inline void rcuwait_init(struct rcuwait *w)
138f95c90cSDavidlohr Bueso {
148f95c90cSDavidlohr Bueso 	w->task = NULL;
158f95c90cSDavidlohr Bueso }
168f95c90cSDavidlohr Bueso 
17191a43beSDavidlohr Bueso /*
18191a43beSDavidlohr Bueso  * Note: this provides no serialization and, just as with waitqueues,
19191a43beSDavidlohr Bueso  * requires care to estimate as to whether or not the wait is active.
20191a43beSDavidlohr Bueso  */
rcuwait_active(struct rcuwait * w)21191a43beSDavidlohr Bueso static inline int rcuwait_active(struct rcuwait *w)
22191a43beSDavidlohr Bueso {
23febd668dSPaolo Bonzini 	return !!rcu_access_pointer(w->task);
24191a43beSDavidlohr Bueso }
25191a43beSDavidlohr Bueso 
269d9a6ebfSDavidlohr Bueso extern int rcuwait_wake_up(struct rcuwait *w);
278f95c90cSDavidlohr Bueso 
288f95c90cSDavidlohr Bueso /*
298f95c90cSDavidlohr Bueso  * The caller is responsible for locking around rcuwait_wait_event(),
305c21f7b3SDavidlohr Bueso  * and [prepare_to/finish]_rcuwait() such that writes to @task are
315c21f7b3SDavidlohr Bueso  * properly serialized.
328f95c90cSDavidlohr Bueso  */
335c21f7b3SDavidlohr Bueso 
prepare_to_rcuwait(struct rcuwait * w)345c21f7b3SDavidlohr Bueso static inline void prepare_to_rcuwait(struct rcuwait *w)
355c21f7b3SDavidlohr Bueso {
365c21f7b3SDavidlohr Bueso 	rcu_assign_pointer(w->task, current);
375c21f7b3SDavidlohr Bueso }
385c21f7b3SDavidlohr Bueso 
3958d4292bSIngo Molnar extern void finish_rcuwait(struct rcuwait *w);
405c21f7b3SDavidlohr Bueso 
41f6239d3fSDavidlohr Bueso #define ___rcuwait_wait_event(w, condition, state, ret, cmd)		\
428f95c90cSDavidlohr Bueso ({									\
43f6239d3fSDavidlohr Bueso 	long __ret = ret;						\
445c21f7b3SDavidlohr Bueso 	prepare_to_rcuwait(w);						\
458f95c90cSDavidlohr Bueso 	for (;;) {							\
468f95c90cSDavidlohr Bueso 		/*							\
478f95c90cSDavidlohr Bueso 		 * Implicit barrier (A) pairs with (B) in		\
487e1f9467SDavidlohr Bueso 		 * rcuwait_wake_up().					\
498f95c90cSDavidlohr Bueso 		 */							\
5080fbaf1cSPeter Zijlstra (Intel) 		set_current_state(state);				\
518f95c90cSDavidlohr Bueso 		if (condition)						\
528f95c90cSDavidlohr Bueso 			break;						\
538f95c90cSDavidlohr Bueso 									\
5480fbaf1cSPeter Zijlstra (Intel) 		if (signal_pending_state(state, current)) {		\
5580fbaf1cSPeter Zijlstra (Intel) 			__ret = -EINTR;					\
5680fbaf1cSPeter Zijlstra (Intel) 			break;						\
5780fbaf1cSPeter Zijlstra (Intel) 		}							\
5880fbaf1cSPeter Zijlstra (Intel) 									\
59f6239d3fSDavidlohr Bueso 		cmd;							\
608f95c90cSDavidlohr Bueso 	}								\
615c21f7b3SDavidlohr Bueso 	finish_rcuwait(w);						\
6280fbaf1cSPeter Zijlstra (Intel) 	__ret;								\
638f95c90cSDavidlohr Bueso })
648f95c90cSDavidlohr Bueso 
65f6239d3fSDavidlohr Bueso #define rcuwait_wait_event(w, condition, state)				\
66f6239d3fSDavidlohr Bueso 	___rcuwait_wait_event(w, condition, state, 0, schedule())
67f6239d3fSDavidlohr Bueso 
68f6239d3fSDavidlohr Bueso #define __rcuwait_wait_event_timeout(w, condition, state, timeout)	\
69f6239d3fSDavidlohr Bueso 	___rcuwait_wait_event(w, ___wait_cond_timeout(condition),	\
70f6239d3fSDavidlohr Bueso 			      state, timeout,				\
71f6239d3fSDavidlohr Bueso 			      __ret = schedule_timeout(__ret))
72f6239d3fSDavidlohr Bueso 
73f6239d3fSDavidlohr Bueso #define rcuwait_wait_event_timeout(w, condition, state, timeout)	\
74f6239d3fSDavidlohr Bueso ({									\
75f6239d3fSDavidlohr Bueso 	long __ret = timeout;						\
76f6239d3fSDavidlohr Bueso 	if (!___wait_cond_timeout(condition))				\
77f6239d3fSDavidlohr Bueso 		__ret = __rcuwait_wait_event_timeout(w, condition,	\
78f6239d3fSDavidlohr Bueso 						     state, timeout);	\
79f6239d3fSDavidlohr Bueso 	__ret;								\
80f6239d3fSDavidlohr Bueso })
81f6239d3fSDavidlohr Bueso 
828f95c90cSDavidlohr Bueso #endif /* _LINUX_RCUWAIT_H_ */
83