Module Name:    src
Committed By:   riastradh
Date:           Sun Dec 19 01:19:45 UTC 2021

Modified Files:
        src/sys/external/bsd/drm2/include/linux: rcupdate.h
        src/sys/external/bsd/drm2/linux: linux_rcu.c

Log Message:
Implement rcu_barrier to wait for call_rcu callbacks.

gc.cv has multiple purposes now, so use cv_broadcast instead of
cv_signal.


To generate a diff of this commit:
cvs rdiff -u -r1.10 -r1.11 src/sys/external/bsd/drm2/include/linux/rcupdate.h
cvs rdiff -u -r1.5 -r1.6 src/sys/external/bsd/drm2/linux/linux_rcu.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/external/bsd/drm2/include/linux/rcupdate.h
diff -u src/sys/external/bsd/drm2/include/linux/rcupdate.h:1.10 src/sys/external/bsd/drm2/include/linux/rcupdate.h:1.11
--- src/sys/external/bsd/drm2/include/linux/rcupdate.h:1.10	Sun Dec 19 01:18:09 2021
+++ src/sys/external/bsd/drm2/include/linux/rcupdate.h	Sun Dec 19 01:19:45 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: rcupdate.h,v 1.10 2021/12/19 01:18:09 riastradh Exp $	*/
+/*	$NetBSD: rcupdate.h,v 1.11 2021/12/19 01:19:45 riastradh Exp $	*/
 
 /*-
  * Copyright (c) 2018 The NetBSD Foundation, Inc.
@@ -72,12 +72,14 @@ struct rcu_head {
 };
 
 #define	call_rcu		linux_call_rcu
+#define	rcu_barrier		linux_rcu_barrier
 #define	synchronize_rcu		linux_synchronize_rcu
 
 int	linux_rcu_gc_init(void);
 void	linux_rcu_gc_fini(void);
 
 void	call_rcu(struct rcu_head *, void (*)(struct rcu_head *));
+void	rcu_barrier(void);
 void	synchronize_rcu(void);
 
 static inline void

Index: src/sys/external/bsd/drm2/linux/linux_rcu.c
diff -u src/sys/external/bsd/drm2/linux/linux_rcu.c:1.5 src/sys/external/bsd/drm2/linux/linux_rcu.c:1.6
--- src/sys/external/bsd/drm2/linux/linux_rcu.c:1.5	Wed Jul 21 06:34:52 2021
+++ src/sys/external/bsd/drm2/linux/linux_rcu.c	Sun Dec 19 01:19:45 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: linux_rcu.c,v 1.5 2021/07/21 06:34:52 skrll Exp $	*/
+/*	$NetBSD: linux_rcu.c,v 1.6 2021/12/19 01:19:45 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.5 2021/07/21 06:34:52 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: linux_rcu.c,v 1.6 2021/12/19 01:19:45 riastradh Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -46,6 +46,8 @@ __KERNEL_RCSID(0, "$NetBSD: linux_rcu.c,
 SDT_PROBE_DEFINE0(sdt, linux, rcu, synchronize__start);
 SDT_PROBE_DEFINE1(sdt, linux, rcu, synchronize__cpu, "unsigned"/*cpu*/);
 SDT_PROBE_DEFINE0(sdt, linux, rcu, synchronize__done);
+SDT_PROBE_DEFINE0(sdt, linux, rcu, barrier__start);
+SDT_PROBE_DEFINE0(sdt, linux, rcu, barrier__done);
 SDT_PROBE_DEFINE2(sdt, linux, rcu, call__queue,
     "struct rcu_head *"/*head*/, "void (*)(struct rcu_head *)"/*callback*/);
 SDT_PROBE_DEFINE2(sdt, linux, rcu, call__run,
@@ -58,6 +60,7 @@ static struct {
 	kcondvar_t	cv;
 	struct rcu_head	*first;
 	struct lwp	*lwp;
+	uint64_t	gen;
 	bool		dying;
 } gc __cacheline_aligned;
 
@@ -68,6 +71,13 @@ synchronize_rcu_xc(void *a, void *b)
 	SDT_PROBE1(sdt, linux, rcu, synchronize__cpu,  cpu_index(curcpu()));
 }
 
+/*
+ * synchronize_rcu()
+ *
+ *	Wait for any pending RCU read section on every CPU to complete
+ *	by triggering on every CPU activity that is blocked by an RCU
+ *	read section.
+ */
 void
 synchronize_rcu(void)
 {
@@ -77,6 +87,36 @@ synchronize_rcu(void)
 	SDT_PROBE0(sdt, linux, rcu, synchronize__done);
 }
 
+/*
+ * rcu_barrier()
+ *
+ *	Wait for all pending RCU callbacks to complete.
+ *
+ *	Does not imply, and is not implied by, synchronize_rcu.
+ */
+void
+rcu_barrier(void)
+{
+	uint64_t gen;
+
+	SDT_PROBE0(sdt, linux, rcu, barrier__start);
+	mutex_enter(&gc.lock);
+	if (gc.first != NULL) {
+		gen = gc.gen;
+		do {
+			cv_wait(&gc.cv, &gc.lock);
+		} while (gc.gen == gen);
+	}
+	mutex_exit(&gc.lock);
+	SDT_PROBE0(sdt, linux, rcu, barrier__done);
+}
+
+/*
+ * call_rcu(head, callback)
+ *
+ *	Arrange to call callback(head) after any pending RCU read
+ *	sections on every CPU is complete.  Return immediately.
+ */
 void
 call_rcu(struct rcu_head *head, void (*callback)(struct rcu_head *))
 {
@@ -86,7 +126,7 @@ call_rcu(struct rcu_head *head, void (*c
 	mutex_enter(&gc.lock);
 	head->rcuh_next = gc.first;
 	gc.first = head;
-	cv_signal(&gc.cv);
+	cv_broadcast(&gc.cv);
 	SDT_PROBE2(sdt, linux, rcu, call__queue,  head, callback);
 	mutex_exit(&gc.lock);
 }
@@ -127,6 +167,8 @@ gc_thread(void *cookie)
 			}
 
 			mutex_enter(&gc.lock);
+			gc.gen++;		/* done running */
+			cv_broadcast(&gc.cv);	/* notify rcu_barrier */
 		}
 
 		/* If we're asked to close shop, do so.  */
@@ -146,6 +188,7 @@ linux_rcu_gc_init(void)
 	mutex_init(&gc.lock, MUTEX_DEFAULT, IPL_VM);
 	cv_init(&gc.cv, "lnxrcugc");
 	gc.first = NULL;
+	gc.gen = 0;
 	gc.dying = false;
 
 	error = kthread_create(PRI_NONE,
@@ -168,7 +211,7 @@ linux_rcu_gc_fini(void)
 
 	mutex_enter(&gc.lock);
 	gc.dying = true;
-	cv_signal(&gc.cv);
+	cv_broadcast(&gc.cv);
 	mutex_exit(&gc.lock);
 
 	kthread_join(gc.lwp);

Reply via email to