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

Reply via email to