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 | ||
50 | static inline void finish_rcuwait(struct rcuwait *w) | |
51 | { | |
52 | rcu_assign_pointer(w->task, NULL); | |
53 | __set_current_state(TASK_RUNNING); | |
54 | } | |
55 | ||
80fbaf1c | 56 | #define rcuwait_wait_event(w, condition, state) \ |
8f95c90c | 57 | ({ \ |
80fbaf1c | 58 | int __ret = 0; \ |
5c21f7b3 | 59 | prepare_to_rcuwait(w); \ |
8f95c90c DB |
60 | for (;;) { \ |
61 | /* \ | |
62 | * Implicit barrier (A) pairs with (B) in \ | |
7e1f9467 | 63 | * rcuwait_wake_up(). \ |
8f95c90c | 64 | */ \ |
80fbaf1c | 65 | set_current_state(state); \ |
8f95c90c DB |
66 | if (condition) \ |
67 | break; \ | |
68 | \ | |
80fbaf1c PZI |
69 | if (signal_pending_state(state, current)) { \ |
70 | __ret = -EINTR; \ | |
71 | break; \ | |
72 | } \ | |
73 | \ | |
8f95c90c DB |
74 | schedule(); \ |
75 | } \ | |
5c21f7b3 | 76 | finish_rcuwait(w); \ |
80fbaf1c | 77 | __ret; \ |
8f95c90c DB |
78 | }) |
79 | ||
80 | #endif /* _LINUX_RCUWAIT_H_ */ |