hc
2023-12-08 01573e231f18eb2d99162747186f59511f56b64d
kernel/include/linux/rcuwait.h
....@@ -3,22 +3,18 @@
33 #define _LINUX_RCUWAIT_H_
44
55 #include <linux/rcupdate.h>
6
+#include <linux/sched/signal.h>
67
78 /*
89 * rcuwait provides a way of blocking and waking up a single
9
- * task in an rcu-safe manner; where it is forbidden to use
10
- * after exit_notify(). task_struct is not properly rcu protected,
11
- * unless dealing with rcu-aware lists, ie: find_task_by_*().
10
+ * task in an rcu-safe manner.
1211 *
13
- * Alternatively we have task_rcu_dereference(), but the return
14
- * semantics have different implications which would break the
15
- * wakeup side. The only time @task is non-nil is when a user is
16
- * blocked (or checking if it needs to) on a condition, and reset
17
- * as soon as we know that the condition has succeeded and are
18
- * awoken.
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.
1915 */
2016 struct rcuwait {
21
- struct task_struct *task;
17
+ struct task_struct __rcu *task;
2218 };
2319
2420 #define __RCUWAIT_INITIALIZER(name) \
....@@ -29,36 +25,56 @@
2925 w->task = NULL;
3026 }
3127
32
-extern void rcuwait_wake_up(struct rcuwait *w);
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
+{
34
+ return !!rcu_access_pointer(w->task);
35
+}
36
+
37
+extern int rcuwait_wake_up(struct rcuwait *w);
3338
3439 /*
3540 * The caller is responsible for locking around rcuwait_wait_event(),
36
- * such that writes to @task are properly serialized.
41
+ * and [prepare_to/finish]_rcuwait() such that writes to @task are
42
+ * properly serialized.
3743 */
38
-#define rcuwait_wait_event(w, condition) \
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
+
56
+#define rcuwait_wait_event(w, condition, state) \
3957 ({ \
40
- /* \
41
- * Complain if we are called after do_exit()/exit_notify(), \
42
- * as we cannot rely on the rcu critical region for the \
43
- * wakeup side. \
44
- */ \
45
- WARN_ON(current->exit_state); \
46
- \
47
- rcu_assign_pointer((w)->task, current); \
58
+ int __ret = 0; \
59
+ prepare_to_rcuwait(w); \
4860 for (;;) { \
4961 /* \
5062 * Implicit barrier (A) pairs with (B) in \
5163 * rcuwait_wake_up(). \
5264 */ \
53
- set_current_state(TASK_UNINTERRUPTIBLE); \
65
+ set_current_state(state); \
5466 if (condition) \
5567 break; \
5668 \
69
+ if (signal_pending_state(state, current)) { \
70
+ __ret = -EINTR; \
71
+ break; \
72
+ } \
73
+ \
5774 schedule(); \
5875 } \
59
- \
60
- WRITE_ONCE((w)->task, NULL); \
61
- __set_current_state(TASK_RUNNING); \
76
+ finish_rcuwait(w); \
77
+ __ret; \
6278 })
6379
6480 #endif /* _LINUX_RCUWAIT_H_ */