Reapply "rcu: Unify force quiescent state"
This reverts commit ddb4d9d1748681cfde824d765af6cda4334fcce3. The commit says: > This reverts commit 55d98e3edeeb17dd8445db27605d2b34f4c3ba85. > > The commit introduced a regression in the replay functional test > on alpha (tests/functional/alpha/test_replay.py), that causes CI > failures regularly. Thus revert this change until someone has > figured out what is going wrong here. Reapply the change as alpha is fixed. Signed-off-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp> Link: https://lore.kernel.org/r/20260217-alpha-v1-2-0dcc708c9db3@rsg.ci.i.u-tokyo.ac.jp Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Akihiko Odaki committed
Feb 17, 2026 at 15:34 UTC
649a78aa324dd339fe9396bbb35d1f333329fa43
1 file changed
+51
-28
util/rcu.c
+51
-28
@@ -43,10 +43,14 @@
43
#define RCU_GP_LOCKED (1UL << 0)
44
#define RCU_GP_CTR (1UL << 1)
45
46
+
47
+#define RCU_CALL_MIN_SIZE 30
48
+
49
unsigned long rcu_gp_ctr = RCU_GP_LOCKED;
50
51
QemuEvent rcu_gp_event;
52
static int in_drain_call_rcu;
53
+static int rcu_call_count;
54
static QemuMutex rcu_registry_lock;
55
static QemuMutex rcu_sync_lock;
56
@@ -76,15 +80,29 @@ static void wait_for_readers(void)
80
{
81
ThreadList qsreaders = QLIST_HEAD_INITIALIZER(qsreaders);
82
struct rcu_reader_data *index, *tmp;
83
+ int sleeps = 0;
84
+ bool forced = false;
85
86
for (;;) {
81
- /* We want to be notified of changes made to rcu_gp_ongoing
82
- * while we walk the list.
87
+ /*
88
+ * Force the grace period to end and wait for it if any of the
89
+ * following heuristical conditions are satisfied:
90
+ * - A decent number of callbacks piled up.
91
+ * - It timed out.
92
+ * - It is in a drain_call_rcu() call.
93
+ *
94
+ * Otherwise, periodically poll the grace period, hoping it ends
95
+ * promptly.
96
*/
84
- qemu_event_reset(&rcu_gp_event);
97
+ if (!forced &&
98
+ (qatomic_read(&rcu_call_count) >= RCU_CALL_MIN_SIZE ||
99
+ sleeps >= 5 || qatomic_read(&in_drain_call_rcu))) {
100
+ forced = true;
101
86
- QLIST_FOREACH(index, ®istry, node) {
87
- qatomic_set(&index->waiting, true);
102
+ QLIST_FOREACH(index, ®istry, node) {
103
+ notifier_list_notify(&index->force_rcu, NULL);
104
+ qatomic_set(&index->waiting, true);
105
+ }
106
}
107
108
/* Here, order the stores to index->waiting before the loads of
@@ -106,8 +124,6 @@ static void wait_for_readers(void)
124
* get some extra futex wakeups.
125
*/
126
qatomic_set(&index->waiting, false);
109
- } else if (qatomic_read(&in_drain_call_rcu)) {
110
- notifier_list_notify(&index->force_rcu, NULL);
127
}
128
}
129
@@ -115,7 +131,8 @@ static void wait_for_readers(void)
131
break;
132
}
133
118
- /* Wait for one thread to report a quiescent state and try again.
134
+ /*
135
+ * Sleep for a while and try again.
136
* Release rcu_registry_lock, so rcu_(un)register_thread() doesn't
137
* wait too much time.
138
*
@@ -133,7 +150,20 @@ static void wait_for_readers(void)
150
* rcu_registry_lock is released.
151
*/
152
qemu_mutex_unlock(&rcu_registry_lock);
136
- qemu_event_wait(&rcu_gp_event);
153
+
154
+ if (forced) {
155
+ qemu_event_wait(&rcu_gp_event);
156
+
157
+ /*
158
+ * We want to be notified of changes made to rcu_gp_ongoing
159
+ * while we walk the list.
160
+ */
161
+ qemu_event_reset(&rcu_gp_event);
162
+ } else {
163
+ g_usleep(10000);
164
+ sleeps++;
165
+ }
166
+
167
qemu_mutex_lock(&rcu_registry_lock);
168
}
169
@@ -173,15 +203,11 @@ void synchronize_rcu(void)
203
}
204
}
205
176
-
177
-#define RCU_CALL_MIN_SIZE 30
178
-
206
/* Multi-producer, single-consumer queue based on urcu/static/wfqueue.h
207
* from liburcu. Note that head is only used by the consumer.
208
*/
209
static struct rcu_head dummy;
210
static struct rcu_head *head = &dummy, **tail = &dummy.next;
184
-static int rcu_call_count;
211
static QemuEvent rcu_call_ready_event;
212
213
static void enqueue(struct rcu_head *node)
@@ -259,30 +285,27 @@ static void *call_rcu_thread(void *opaque)
285
rcu_register_thread();
286
287
for (;;) {
262
- int tries = 0;
263
- int n = qatomic_read(&rcu_call_count);
288
+ int n;
289
265
- /* Heuristically wait for a decent number of callbacks to pile up.
290
+ /*
291
* Fetch rcu_call_count now, we only must process elements that were
292
* added before synchronize_rcu() starts.
293
*/
269
- while (n == 0 || (n < RCU_CALL_MIN_SIZE && ++tries <= 5)) {
270
- g_usleep(10000);
271
- if (n == 0) {
272
- qemu_event_reset(&rcu_call_ready_event);
273
- n = qatomic_read(&rcu_call_count);
274
- if (n == 0) {
294
+ for (;;) {
295
+ qemu_event_reset(&rcu_call_ready_event);
296
+ n = qatomic_read(&rcu_call_count);
297
+ if (n) {
298
+ break;
299
+ }
300
+
301
#if defined(CONFIG_MALLOC_TRIM)
276
- malloc_trim(4 * 1024 * 1024);
302
+ malloc_trim(4 * 1024 * 1024);
303
#endif
278
- qemu_event_wait(&rcu_call_ready_event);
279
- }
280
- }
281
- n = qatomic_read(&rcu_call_count);
304
+ qemu_event_wait(&rcu_call_ready_event);
305
}
306
284
- qatomic_sub(&rcu_call_count, n);
307
synchronize_rcu();
308
+ qatomic_sub(&rcu_call_count, n);
309
bql_lock();
310
while (n > 0) {
311
node = try_dequeue();