On 27 May 2022, at 12:05, Peng He wrote:
> Hi, Eelco, > > are you missing this one? Oops, no I forgot to hit send. The window was somewhere in the background ;) //Eelco > > Peng He <[email protected]> 于2022年5月26日周四 10:47写道: > >> ovsrcu_barrier will block the current thread until all the postponed >> rcu job has been finished. it's like a OVS version of the Linux >> kernel rcu_barrier(). >> >> Signed-off-by: Peng He <[email protected]> >> Co-authored-by: Eelco Chaudron <[email protected]> >> Signed-off-by: Eelco Chaudron <[email protected]> >> Reviewed-by: David Marchand <[email protected]> >> --- >> lib/ovs-rcu.c | 37 +++++++++++++++++++++++++++++++++++++ >> lib/ovs-rcu.h | 15 +++++++++++++++ >> tests/library.at | 2 +- >> tests/test-rcu.c | 29 +++++++++++++++++++++++++++-- >> 4 files changed, 80 insertions(+), 3 deletions(-) >> >> diff --git a/lib/ovs-rcu.c b/lib/ovs-rcu.c >> index 1866bd308..946aa04d1 100644 >> --- a/lib/ovs-rcu.c >> +++ b/lib/ovs-rcu.c >> @@ -444,3 +444,40 @@ 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 return immediately if there are no outstanding RCU callbacks, >> + * this API will at least wait for a grace period. >> + * >> + * Another issue the caller might need to know is that the barrier is just >> + * for "one-shot", i.e. if inside some RCU callbacks, another RCU >> callback is >> + * registered, this API only guarantees the first round of RCU callbacks >> have >> + * been executed after it returns. >> + */ >> +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..8b397b7fb 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 resources however >> + * these resources are referenced in the outstanding RCU callbacks. >> + * >> + * void rcu_cb(void *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 */ >> diff --git a/tests/library.at b/tests/library.at >> index db4997d8f..6489be2c1 100644 >> --- a/tests/library.at >> +++ b/tests/library.at >> @@ -252,7 +252,7 @@ AT_CHECK([ovstest test-barrier], [0], []) >> AT_CLEANUP >> >> AT_SETUP([rcu]) >> -AT_CHECK([ovstest test-rcu-quiesce], [0], []) >> +AT_CHECK([ovstest test-rcu], [0], []) >> AT_CLEANUP >> >> AT_SETUP([stopwatch module]) >> diff --git a/tests/test-rcu.c b/tests/test-rcu.c >> index 965f3c49f..bb17092bf 100644 >> --- a/tests/test-rcu.c >> +++ b/tests/test-rcu.c >> @@ -35,7 +35,7 @@ quiescer_main(void *aux OVS_UNUSED) >> } >> >> static void >> -test_rcu_quiesce(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) >> +test_rcu_quiesce(void) >> { >> pthread_t quiescer; >> >> @@ -48,4 +48,29 @@ test_rcu_quiesce(int argc OVS_UNUSED, char *argv[] >> OVS_UNUSED) >> xpthread_join(quiescer, NULL); >> } >> >> -OVSTEST_REGISTER("test-rcu-quiesce", test_rcu_quiesce); >> +static void >> +add_count(void *_count) >> +{ >> + unsigned *count = (unsigned *)_count; >> + (*count) ++; >> +} >> + >> +static void >> +test_rcu_barrier(void) >> +{ >> + unsigned count = 0; >> + for (int i = 0; i < 10; i ++) { >> + ovsrcu_postpone(add_count, &count); >> + } >> + >> + ovsrcu_barrier(); >> + ovs_assert(count == 10); >> +} >> + >> +static void >> +test_rcu(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) { >> + test_rcu_quiesce(); >> + test_rcu_barrier(); >> +} >> + >> +OVSTEST_REGISTER("test-rcu", test_rcu); >> -- >> 2.25.1 >> >> > > -- > hepeng _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
