From: Paolo Bonzini <pbonz...@redhat.com> Signed-off-by: Paolo Bonzini <pbonz...@redhat.com> Reviewed-by: Mike Day <ncm...@ncultra.org> --- docs/rcu.txt | 5 +++++ include/qemu/rcu.h | 21 +++++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-)
diff --git a/docs/rcu.txt b/docs/rcu.txt index d7c4f0b..4e7cde3 100644 --- a/docs/rcu.txt +++ b/docs/rcu.txt @@ -187,6 +187,11 @@ Marking quiescent states is done with the following three APIs: thread. +rcu_thread_offline() and rcu_thread_online() can be nested. The end of +the extended quiescent state will coincide with the outermost call to +rcu_thread_online(). + + The following APIs can be used to use RCU in a thread that is not created with qemu_thread_create(): diff --git a/include/qemu/rcu.h b/include/qemu/rcu.h index e43b912..3a55045 100644 --- a/include/qemu/rcu.h +++ b/include/qemu/rcu.h @@ -77,6 +77,9 @@ struct rcu_reader_data { unsigned long ctr; bool waiting; + /* Data used by reader only */ + unsigned offline; + /* Data used for registry, protected by rcu_gp_lock */ QLIST_ENTRY(rcu_reader_data) node; }; @@ -127,9 +130,14 @@ static inline void rcu_read_unlock(void) static inline void rcu_quiescent_state(void) { struct rcu_reader_data *p_rcu_reader = get_rcu_reader(); + unsigned ctr; + + if (p_rcu_reader->offline > 0) { + return; + } /* Reuses smp_rmb() in the last rcu_read_unlock(). */ - 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); @@ -141,6 +149,10 @@ static inline void rcu_thread_offline(void) { struct rcu_reader_data *p_rcu_reader = get_rcu_reader(); + if (p_rcu_reader->offline++ > 0) { + return; + } + atomic_xchg(&p_rcu_reader->ctr, 0); if (atomic_read(&p_rcu_reader->waiting)) { atomic_set(&p_rcu_reader->waiting, false); @@ -150,7 +162,12 @@ static inline void rcu_thread_offline(void) static inline void rcu_thread_online(void) { - rcu_quiescent_state(); + struct rcu_reader_data *p_rcu_reader = get_rcu_reader(); + + assert(p_rcu_reader->offline != 0); + if (--p_rcu_reader->offline == 0) { + rcu_quiescent_state(); + } } extern void synchronize_rcu(void); -- 1.8.3.1