1#ifndef QEMU_RCU_H
2#define QEMU_RCU_H
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27#include "qemu/thread.h"
28#include "qemu/queue.h"
29#include "qemu/atomic.h"
30#include "qemu/notify.h"
31#include "qemu/sys_membarrier.h"
32#include "qemu/coroutine-tls.h"
33
34
35
36
37
38
39
40
41
42#ifdef DEBUG_RCU
43#define rcu_assert(args...) assert(args)
44#else
45#define rcu_assert(args...)
46#endif
47
48
49
50
51
52
53extern unsigned long rcu_gp_ctr;
54
55extern QemuEvent rcu_gp_event;
56
57struct rcu_reader_data {
58
59 unsigned long ctr;
60 bool waiting;
61
62
63 unsigned depth;
64
65
66 QLIST_ENTRY(rcu_reader_data) node;
67
68
69
70
71
72
73 NotifierList force_rcu;
74};
75
76QEMU_DECLARE_CO_TLS(struct rcu_reader_data, rcu_reader)
77
78static inline void rcu_read_lock(void)
79{
80 struct rcu_reader_data *p_rcu_reader = get_ptr_rcu_reader();
81 unsigned ctr;
82
83 if (p_rcu_reader->depth++ > 0) {
84 return;
85 }
86
87 ctr = qatomic_read(&rcu_gp_ctr);
88 qatomic_set(&p_rcu_reader->ctr, ctr);
89
90
91 smp_mb_placeholder();
92}
93
94static inline void rcu_read_unlock(void)
95{
96 struct rcu_reader_data *p_rcu_reader = get_ptr_rcu_reader();
97
98 assert(p_rcu_reader->depth != 0);
99 if (--p_rcu_reader->depth > 0) {
100 return;
101 }
102
103
104
105
106
107
108 qatomic_store_release(&p_rcu_reader->ctr, 0);
109
110
111 smp_mb_placeholder();
112 if (unlikely(qatomic_read(&p_rcu_reader->waiting))) {
113 qatomic_set(&p_rcu_reader->waiting, false);
114 qemu_event_set(&rcu_gp_event);
115 }
116}
117
118extern void synchronize_rcu(void);
119
120
121
122
123extern void rcu_register_thread(void);
124extern void rcu_unregister_thread(void);
125
126
127
128
129extern void rcu_enable_atfork(void);
130extern void rcu_disable_atfork(void);
131
132struct rcu_head;
133typedef void RCUCBFunc(struct rcu_head *head);
134
135struct rcu_head {
136 struct rcu_head *next;
137 RCUCBFunc *func;
138};
139
140extern void call_rcu1(struct rcu_head *head, RCUCBFunc *func);
141extern void drain_call_rcu(void);
142
143
144
145
146#define call_rcu(head, func, field) \
147 call_rcu1(({ \
148 char __attribute__((unused)) \
149 offset_must_be_zero[-offsetof(typeof(*(head)), field)], \
150 func_type_invalid = (func) - (void (*)(typeof(head)))(func); \
151 &(head)->field; \
152 }), \
153 (RCUCBFunc *)(func))
154
155#define g_free_rcu(obj, field) \
156 call_rcu1(({ \
157 char __attribute__((unused)) \
158 offset_must_be_zero[-offsetof(typeof(*(obj)), field)]; \
159 &(obj)->field; \
160 }), \
161 (RCUCBFunc *)g_free);
162
163typedef void RCUReadAuto;
164static inline RCUReadAuto *rcu_read_auto_lock(void)
165{
166 rcu_read_lock();
167
168 return (void *)(uintptr_t)0x1;
169}
170
171static inline void rcu_read_auto_unlock(RCUReadAuto *r)
172{
173 rcu_read_unlock();
174}
175
176G_DEFINE_AUTOPTR_CLEANUP_FUNC(RCUReadAuto, rcu_read_auto_unlock)
177
178#define WITH_RCU_READ_LOCK_GUARD() \
179 WITH_RCU_READ_LOCK_GUARD_(glue(_rcu_read_auto, __COUNTER__))
180
181#define WITH_RCU_READ_LOCK_GUARD_(var) \
182 for (g_autoptr(RCUReadAuto) var = rcu_read_auto_lock(); \
183 (var); rcu_read_auto_unlock(var), (var) = NULL)
184
185#define RCU_READ_LOCK_GUARD() \
186 g_autoptr(RCUReadAuto) _rcu_read_auto __attribute__((unused)) = rcu_read_auto_lock()
187
188
189
190
191
192void rcu_add_force_rcu_notifier(Notifier *n);
193void rcu_remove_force_rcu_notifier(Notifier *n);
194
195#endif
196