mirror of
https://github.com/openvswitch/ovs
synced 2025-08-22 01:51:26 +00:00
ovs-rcu: Add ovsrcu_barrier.
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 <hepeng.0320@bytedance.com> Co-authored-by: Eelco Chaudron <echaudro@redhat.com> Signed-off-by: Eelco Chaudron <echaudro@redhat.com> Reviewed-by: David Marchand <david.marchand@redhat.com> Acked-by: Eelco Chaudron <echaudro@redhat.com> Acked-by: Aaron Conole <aconole@redhat.com> Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
This commit is contained in:
parent
ba462b3589
commit
c67941e974
@ -444,3 +444,40 @@ ovsrcu_init_module(void)
|
|||||||
ovsthread_once_done(&once);
|
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);
|
||||||
|
}
|
||||||
|
@ -155,6 +155,19 @@
|
|||||||
* port_delete(id);
|
* 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"
|
#include "compiler.h"
|
||||||
@ -310,4 +323,6 @@ void ovsrcu_synchronize(void);
|
|||||||
|
|
||||||
void ovsrcu_exit(void);
|
void ovsrcu_exit(void);
|
||||||
|
|
||||||
|
void ovsrcu_barrier(void);
|
||||||
|
|
||||||
#endif /* ovs-rcu.h */
|
#endif /* ovs-rcu.h */
|
||||||
|
@ -252,7 +252,7 @@ AT_CHECK([ovstest test-barrier], [0], [])
|
|||||||
AT_CLEANUP
|
AT_CLEANUP
|
||||||
|
|
||||||
AT_SETUP([rcu])
|
AT_SETUP([rcu])
|
||||||
AT_CHECK([ovstest test-rcu-quiesce], [0], [])
|
AT_CHECK([ovstest test-rcu], [0], [])
|
||||||
AT_CLEANUP
|
AT_CLEANUP
|
||||||
|
|
||||||
AT_SETUP([stopwatch module])
|
AT_SETUP([stopwatch module])
|
||||||
|
@ -35,7 +35,7 @@ quiescer_main(void *aux OVS_UNUSED)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_rcu_quiesce(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
|
test_rcu_quiesce(void)
|
||||||
{
|
{
|
||||||
pthread_t quiescer;
|
pthread_t quiescer;
|
||||||
|
|
||||||
@ -48,4 +48,29 @@ test_rcu_quiesce(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
|
|||||||
xpthread_join(quiescer, NULL);
|
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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user