diff mbox

[03/15] rcu: allow nesting of rcu_read_lock/rcu_read_unlock

Message ID 1421938053-10318-4-git-send-email-pbonzini@redhat.com
State New
Headers show

Commit Message

Paolo Bonzini Jan. 22, 2015, 2:47 p.m. UTC
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 include/qemu/rcu.h | 15 ++++++++++++++-
 tests/rcutorture.c |  2 ++
 2 files changed, 16 insertions(+), 1 deletion(-)

Comments

Fam Zheng Jan. 26, 2015, 3:32 a.m. UTC | #1
On Thu, 01/22 15:47, Paolo Bonzini wrote:
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  include/qemu/rcu.h | 15 ++++++++++++++-
>  tests/rcutorture.c |  2 ++
>  2 files changed, 16 insertions(+), 1 deletion(-)
> 
> diff --git a/include/qemu/rcu.h b/include/qemu/rcu.h
> index cfef36e..da043f2 100644
> --- a/include/qemu/rcu.h
> +++ b/include/qemu/rcu.h
> @@ -68,6 +68,9 @@ struct rcu_reader_data {
>      unsigned long ctr;
>      bool waiting;
>  
> +    /* Data used by reader only */
> +    unsigned depth;
> +
>      /* Data used for registry, protected by rcu_gp_lock */
>      QLIST_ENTRY(rcu_reader_data) node;
>  };
> @@ -77,8 +80,13 @@ extern __thread struct rcu_reader_data rcu_reader;
>  static inline void rcu_read_lock(void)
>  {
>      struct rcu_reader_data *p_rcu_reader = &rcu_reader;
> +    unsigned ctr;
> +
> +    if (p_rcu_reader->depth++ > 0) {
> +        return;
> +    }
>  
> -    unsigned ctr = atomic_read(&rcu_gp_ctr);
> +    ctr = atomic_read(&rcu_gp_ctr);
>      atomic_xchg(&p_rcu_reader->ctr, ctr);
>      if (atomic_read(&p_rcu_reader->waiting)) {
>          atomic_set(&p_rcu_reader->waiting, false);
> @@ -90,6 +98,11 @@ static inline void rcu_read_unlock(void)
>  {
>      struct rcu_reader_data *p_rcu_reader = &rcu_reader;
>  
> +    assert(p_rcu_reader->depth != 0);
> +    if (--p_rcu_reader->depth > 0) {
> +        return;
> +    }
> +
>      atomic_xchg(&p_rcu_reader->ctr, 0);
>      if (atomic_read(&p_rcu_reader->waiting)) {
>          atomic_set(&p_rcu_reader->waiting, false);
> diff --git a/tests/rcutorture.c b/tests/rcutorture.c
> index 214985f..31461c3 100644
> --- a/tests/rcutorture.c
> +++ b/tests/rcutorture.c
> @@ -257,9 +257,11 @@ static void *rcu_read_stress_test(void *arg)
>          if (p->mbtest == 0) {
>              n_mberror++;
>          }
> +        rcu_read_lock();
>          for (i = 0; i < 100; i++) {
>              garbage++;
>          }
> +        rcu_read_unlock();
>          pc = p->pipe_count;
>          rcu_read_unlock();
>          if ((pc > RCU_STRESS_PIPE_LEN) || (pc < 0)) {
> -- 
> 1.8.3.1
> 
> 

Reviewed-by: Fam Zheng <famz@redhat.com>
diff mbox

Patch

diff --git a/include/qemu/rcu.h b/include/qemu/rcu.h
index cfef36e..da043f2 100644
--- a/include/qemu/rcu.h
+++ b/include/qemu/rcu.h
@@ -68,6 +68,9 @@  struct rcu_reader_data {
     unsigned long ctr;
     bool waiting;
 
+    /* Data used by reader only */
+    unsigned depth;
+
     /* Data used for registry, protected by rcu_gp_lock */
     QLIST_ENTRY(rcu_reader_data) node;
 };
@@ -77,8 +80,13 @@  extern __thread struct rcu_reader_data rcu_reader;
 static inline void rcu_read_lock(void)
 {
     struct rcu_reader_data *p_rcu_reader = &rcu_reader;
+    unsigned ctr;
+
+    if (p_rcu_reader->depth++ > 0) {
+        return;
+    }
 
-    unsigned ctr = atomic_read(&rcu_gp_ctr);
+    ctr = atomic_read(&rcu_gp_ctr);
     atomic_xchg(&p_rcu_reader->ctr, ctr);
     if (atomic_read(&p_rcu_reader->waiting)) {
         atomic_set(&p_rcu_reader->waiting, false);
@@ -90,6 +98,11 @@  static inline void rcu_read_unlock(void)
 {
     struct rcu_reader_data *p_rcu_reader = &rcu_reader;
 
+    assert(p_rcu_reader->depth != 0);
+    if (--p_rcu_reader->depth > 0) {
+        return;
+    }
+
     atomic_xchg(&p_rcu_reader->ctr, 0);
     if (atomic_read(&p_rcu_reader->waiting)) {
         atomic_set(&p_rcu_reader->waiting, false);
diff --git a/tests/rcutorture.c b/tests/rcutorture.c
index 214985f..31461c3 100644
--- a/tests/rcutorture.c
+++ b/tests/rcutorture.c
@@ -257,9 +257,11 @@  static void *rcu_read_stress_test(void *arg)
         if (p->mbtest == 0) {
             n_mberror++;
         }
+        rcu_read_lock();
         for (i = 0; i < 100; i++) {
             garbage++;
         }
+        rcu_read_unlock();
         pc = p->pipe_count;
         rcu_read_unlock();
         if ((pc > RCU_STRESS_PIPE_LEN) || (pc < 0)) {