@samitouri / QOSamiQemu / commits / 649a78aa32

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, &registry, node) {
87 - qatomic_set(&index->waiting, true);
102 + QLIST_FOREACH(index, &registry, 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();