Commit | Line | Data |
---|---|---|
b2441318 | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
8f95c90c DB |
2 | #ifndef _LINUX_RCUWAIT_H_ |
3 | #define _LINUX_RCUWAIT_H_ | |
4 | ||
5 | #include <linux/rcupdate.h> | |
80fbaf1c | 6 | #include <linux/sched/signal.h> |
8f95c90c DB |
7 | |
8 | /* | |
9 | * rcuwait provides a way of blocking and waking up a single | |
154abafc | 10 | * task in an rcu-safe manner. |
8f95c90c | 11 | * |
154abafc EB |
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. | |
8f95c90c DB |
15 | */ |
16 | struct rcuwait { | |
03f4b48e | 17 | struct task_struct __rcu *task; |
8f95c90c DB |
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 | ||
191a43be DB |
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 | */ | |
32 | static inline int rcuwait_active(struct rcuwait *w) | |
33 | { | |
febd668d | 34 | return !!rcu_access_pointer(w->task); |
191a43be DB |
35 | } |
36 | ||
9d9a6ebf | 37 | extern int rcuwait_wake_up(struct rcuwait *w); |
8f95c90c DB |
38 | |
39 | /* | |
40 | * The caller is responsible for locking around rcuwait_wait_event(), | |
5c21f7b3 DB |
41 | * and [prepare_to/finish]_rcuwait() such that writes to @task are |
42 | * properly serialized. | |
8f95c90c | 43 | */ |
5c21f7b3 DB |
44 | |
45 | static inline void prepare_to_rcuwait(struct rcuwait *w) | |
46 | { | |
47 | rcu_assign_pointer(w->task, current); | |
48 | } | |
49 | ||
58d4292b | 50 | extern void finish_rcuwait(struct rcuwait *w); |
5c21f7b3 | 51 | |
80fbaf1c | 52 | #define rcuwait_wait_event(w, condition, state) \ |
8f95c90c | 53 | ({ \ |
80fbaf1c | 54 | int __ret = 0; \ |
5c21f7b3 | 55 | prepare_to_rcuwait(w); \ |
8f95c90c DB |
56 | for (;;) { \ |
57 | /* \ | |
58 | * Implicit barrier (A) pairs with (B) in \ | |
7e1f9467 | 59 | * rcuwait_wake_up(). \ |
8f95c90c | 60 | */ \ |
80fbaf1c | 61 | set_current_state(state); \ |
8f95c90c DB |
62 | if (condition) \ |
63 | break; \ | |
64 | \ | |
80fbaf1c PZI |
65 | if (signal_pending_state(state, current)) { \ |
66 | __ret = -EINTR; \ | |
67 | break; \ | |
68 | } \ | |
69 | \ | |
8f95c90c DB |
70 | schedule(); \ |
71 | } \ | |
5c21f7b3 | 72 | finish_rcuwait(w); \ |
80fbaf1c | 73 | __ret; \ |
8f95c90c DB |
74 | }) |
75 | ||
76 | #endif /* _LINUX_RCUWAIT_H_ */ |