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