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