Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/external/bsd/common/linux linux: Fix rcu_barrier so it a...
details: https://anonhg.NetBSD.org/src/rev/dd44e21a5bdd
branches: trunk
changeset: 1028995:dd44e21a5bdd
user: riastradh <riastradh%NetBSD.org@localhost>
date: Sun Dec 19 12:40:11 2021 +0000
description:
linux: Fix rcu_barrier so it actually waits for everything.
diffstat:
sys/external/bsd/common/linux/linux_rcu.c | 37 ++++++++++++++++++++++++------
1 files changed, 29 insertions(+), 8 deletions(-)
diffs (81 lines):
diff -r bdc11ca7f077 -r dd44e21a5bdd sys/external/bsd/common/linux/linux_rcu.c
--- a/sys/external/bsd/common/linux/linux_rcu.c Sun Dec 19 12:40:03 2021 +0000
+++ b/sys/external/bsd/common/linux/linux_rcu.c Sun Dec 19 12:40:11 2021 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: linux_rcu.c,v 1.6 2021/12/19 12:40:03 riastradh Exp $ */
+/* $NetBSD: linux_rcu.c,v 1.7 2021/12/19 12:40:11 riastradh Exp $ */
/*-
* Copyright (c) 2018 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: linux_rcu.c,v 1.6 2021/12/19 12:40:03 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: linux_rcu.c,v 1.7 2021/12/19 12:40:11 riastradh Exp $");
#include <sys/param.h>
#include <sys/types.h>
@@ -71,6 +71,7 @@
struct rcu_head *first_kfree;
struct lwp *lwp;
uint64_t gen;
+ bool running;
bool dying;
} gc __cacheline_aligned;
@@ -152,13 +153,28 @@
{
uint64_t gen;
+ /*
+ * If the GC isn't running anything yet, then all callbacks of
+ * interest are queued, and it suffices to wait for the GC to
+ * advance one generation number.
+ *
+ * If the GC is already running, however, and there are any
+ * callbacks of interest queued but not in the GC's current
+ * batch of work, then when the advances the generation number
+ * it will not have completed the queued callbacks. So we have
+ * to wait for one more generation -- or until the GC has
+ * stopped running because there's no work left.
+ */
+
SDT_PROBE0(sdt, linux, rcu, barrier__start);
mutex_enter(&gc.lock);
- if (gc.first_callback != NULL || gc.first_kfree != NULL) {
- gen = gc.gen;
- do {
- cv_wait(&gc.cv, &gc.lock);
- } while (gc.gen == gen);
+ gen = gc.gen;
+ if (gc.running)
+ gen++;
+ while (gc.running || gc.first_callback || gc.first_kfree) {
+ cv_wait(&gc.cv, &gc.lock);
+ if (gc.gen > gen)
+ break;
}
mutex_exit(&gc.lock);
SDT_PROBE0(sdt, linux, rcu, barrier__done);
@@ -238,7 +254,11 @@
continue;
}
- /* We have work to do. Drop the lock to do it. */
+ /*
+ * We have work to do. Drop the lock to do it, and
+ * notify rcu_barrier that we're still doing it.
+ */
+ gc.running = true;
mutex_exit(&gc.lock);
/* Wait for activity on all CPUs. */
@@ -275,6 +295,7 @@
/* Finished a batch of work. Notify rcu_barrier. */
gc.gen++;
+ gc.running = false;
cv_broadcast(&gc.cv);
/*
Home |
Main Index |
Thread Index |
Old Index