rcu_barrier will block the current thread until all the postponed
rcu job has been finished. it's like the OVS's version of
the kernel rcu_barrier()

Signed-off-by: Peng He <hepeng.0...@bytedance.com>
Co-authored-by: Eelco Chaudron <echau...@redhat.com>
---
 lib/ovs-rcu.c | 38 ++++++++++++++++++++++++++++++++++++++
 lib/ovs-rcu.h | 15 +++++++++++++++
 2 files changed, 53 insertions(+)

diff --git a/lib/ovs-rcu.c b/lib/ovs-rcu.c
index 1866bd308..9fed53449 100644
--- a/lib/ovs-rcu.c
+++ b/lib/ovs-rcu.c
@@ -444,3 +444,41 @@ ovsrcu_init_module(void)
         ovsthread_once_done(&once);
     }
 }
+
+static void
+ovsrcu_barrier_func(void *seq_)
+{
+    struct seq *seq = (struct seq *) seq_;
+    seq_change(seq);
+}
+
+
+/* Similar to the kernel rcu_barrier, ovsrcu_barrier waits for all outstanding
+ * RCU callbacks to complete. However, unlike the kernel rcu_barrier, which
+ * might retrun immediately if no outstanding RCU callbacks are pending,
+ * this API will at least wait for a grace period.
+ *
+ * Another issue the caller might need to know it's that the barrier is just
+ * for "one shot", i.e. if inside some RCU callbacks, another RCU callback is
+ * registered, this API only guarantee the first round of RCU callbacks have
+ * been executed.
+ */
+void
+ovsrcu_barrier(void)
+{
+    struct seq *seq = seq_create();
+    /* First let all threads flush their cbsets */
+    ovsrcu_synchronize();
+
+    /* Then register a new cbset, ensure this cbset
+     * is at the tail of the global list. */
+    uint64_t seqno = seq_read(seq);
+    ovsrcu_postpone__(ovsrcu_barrier_func, (void *) seq);
+
+    do {
+        seq_wait(seq, seqno);
+        poll_block();
+    } while (seqno == seq_read(seq));
+
+    seq_destroy(seq);
+}
diff --git a/lib/ovs-rcu.h b/lib/ovs-rcu.h
index ecc4c9201..7bdfa540b 100644
--- a/lib/ovs-rcu.h
+++ b/lib/ovs-rcu.h
@@ -155,6 +155,19 @@
  *         port_delete(id);
  *     }
  *
+ * Use ovsrcu_barrier() to wait for all the outstanding RCU callbacks to
+ * finish. This is useful when you have to destroy some resoures however
+ * these resoures are referenced in the outstanding RCU callbacks.
+ *
+ * void rcu_cb(void *A) {
+ *     Use_A_do_something(A);
+ * }
+ *
+ * void destroy_A() {
+ *     ovsrcu_postpone(rcu_cb, A); // will use A later
+ *     ovsrcu_barrier(); // wait for rcu_cb done
+ *     do_destroy_A(); // free A
+ * }
  */
 
 #include "compiler.h"
@@ -310,4 +323,6 @@ void ovsrcu_synchronize(void);
 
 void ovsrcu_exit(void);
 
+void ovsrcu_barrier(void);
+
 #endif /* ovs-rcu.h */
-- 
2.25.1

_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to