qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/3] rcu: missing thread registration
@ 2015-07-13 11:31 Paolo Bonzini
  2015-07-13 11:31 ` [Qemu-devel] [PATCH 1/3] rcu: automatically unregister threads when they exit Paolo Bonzini
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Paolo Bonzini @ 2015-07-13 11:31 UTC (permalink / raw)
  To: qemu-devel

Patch 2 fixes the problem, whereby threads were not being registered
but still happily used RCU.  Patch 1 simplifies the registration by
making rcu_unregister_thread automatic.  Patch 3 avoids having the
same bug in the future.

Paolo

Paolo Bonzini (3):
  rcu: automatically unregister threads when they exit
  rcu: actually register threads that have RCU read-side critical
    sections
  rcu: detect missing rcu_register_thread()

 cpus.c                |  6 ++++++
 include/qemu/rcu.h    |  4 +++-
 iothread.c            |  3 +++
 migration/migration.c |  3 +++
 tests/rcutorture.c    | 10 ----------
 tests/test-rcu-list.c |  2 ++
 util/rcu.c            | 30 ++++++++++++++++++++++++++++--
 7 files changed, 45 insertions(+), 13 deletions(-)

-- 
2.4.3

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [Qemu-devel] [PATCH 1/3] rcu: automatically unregister threads when they exit
  2015-07-13 11:31 [Qemu-devel] [PATCH 0/3] rcu: missing thread registration Paolo Bonzini
@ 2015-07-13 11:31 ` Paolo Bonzini
  2015-07-13 11:31 ` [Qemu-devel] [PATCH 2/3] rcu: actually register threads that have RCU read-side critical sections Paolo Bonzini
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Paolo Bonzini @ 2015-07-13 11:31 UTC (permalink / raw)
  To: qemu-devel

This simplifies management within the threads themselves.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/rcutorture.c | 10 ----------
 util/rcu.c         | 12 ++++++++++++
 2 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/tests/rcutorture.c b/tests/rcutorture.c
index d6b304d..000b216 100644
--- a/tests/rcutorture.c
+++ b/tests/rcutorture.c
@@ -134,8 +134,6 @@ static void *rcu_read_perf_test(void *arg)
     qemu_mutex_lock(&counts_mutex);
     n_reads += n_reads_local;
     qemu_mutex_unlock(&counts_mutex);
-
-    rcu_unregister_thread();
     return NULL;
 }
 
@@ -157,8 +155,6 @@ static void *rcu_update_perf_test(void *arg)
     qemu_mutex_lock(&counts_mutex);
     n_updates += n_updates_local;
     qemu_mutex_unlock(&counts_mutex);
-
-    rcu_unregister_thread();
     return NULL;
 }
 
@@ -283,8 +279,6 @@ static void *rcu_read_stress_test(void *arg)
         rcu_stress_count[i] += rcu_stress_local[i];
     }
     qemu_mutex_unlock(&counts_mutex);
-
-    rcu_unregister_thread();
     return NULL;
 }
 
@@ -319,8 +313,6 @@ static void *rcu_update_stress_test(void *arg)
         synchronize_rcu();
         n_updates++;
     }
-
-    rcu_unregister_thread();
     return NULL;
 }
 
@@ -336,8 +328,6 @@ static void *rcu_fake_update_stress_test(void *arg)
         synchronize_rcu();
         g_usleep(1000);
     }
-
-    rcu_unregister_thread();
     return NULL;
 }
 
diff --git a/util/rcu.c b/util/rcu.c
index 7270151..8830295 100644
--- a/util/rcu.c
+++ b/util/rcu.c
@@ -268,12 +268,22 @@ void call_rcu1(struct rcu_head *node, void (*func)(struct rcu_head *node))
     qemu_event_set(&rcu_call_ready_event);
 }
 
+static __thread Notifier unregister_thread_notifier;
+
+static void rcu_unregister_thread_notify(Notifier *n, void *data)
+{
+    rcu_unregister_thread();
+}
+
 void rcu_register_thread(void)
 {
     assert(rcu_reader.ctr == 0);
     qemu_mutex_lock(&rcu_gp_lock);
     QLIST_INSERT_HEAD(&registry, &rcu_reader, node);
     qemu_mutex_unlock(&rcu_gp_lock);
+
+    unregister_thread_notifier.notify = rcu_unregister_thread_notify;
+    qemu_thread_atexit_add(&unregister_thread_notifier);
 }
 
 void rcu_unregister_thread(void)
@@ -281,6 +291,8 @@ void rcu_unregister_thread(void)
     qemu_mutex_lock(&rcu_gp_lock);
     QLIST_REMOVE(&rcu_reader, node);
     qemu_mutex_unlock(&rcu_gp_lock);
+
+    qemu_thread_atexit_remove(&unregister_thread_notifier);
 }
 
 static void rcu_init_complete(void)
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [Qemu-devel] [PATCH 2/3] rcu: actually register threads that have RCU read-side critical sections
  2015-07-13 11:31 [Qemu-devel] [PATCH 0/3] rcu: missing thread registration Paolo Bonzini
  2015-07-13 11:31 ` [Qemu-devel] [PATCH 1/3] rcu: automatically unregister threads when they exit Paolo Bonzini
@ 2015-07-13 11:31 ` Paolo Bonzini
  2015-07-13 11:31 ` [Qemu-devel] [PATCH 3/3] rcu: detect missing rcu_register_thread() Paolo Bonzini
  2015-07-14  3:36 ` [Qemu-devel] [PATCH 0/3] rcu: missing thread registration Fam Zheng
  3 siblings, 0 replies; 5+ messages in thread
From: Paolo Bonzini @ 2015-07-13 11:31 UTC (permalink / raw)
  To: qemu-devel

Otherwise, grace periods are detected too early!

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 cpus.c                | 6 ++++++
 iothread.c            | 3 +++
 migration/migration.c | 3 +++
 tests/test-rcu-list.c | 2 ++
 4 files changed, 14 insertions(+)

diff --git a/cpus.c b/cpus.c
index f547aeb..36e93fa 100644
--- a/cpus.c
+++ b/cpus.c
@@ -954,6 +954,8 @@ static void *qemu_kvm_cpu_thread_fn(void *arg)
     CPUState *cpu = arg;
     int r;
 
+    rcu_register_thread();
+
     qemu_mutex_lock_iothread();
     qemu_thread_get_self(cpu->thread);
     cpu->thread_id = qemu_get_thread_id();
@@ -995,6 +997,8 @@ static void *qemu_dummy_cpu_thread_fn(void *arg)
     sigset_t waitset;
     int r;
 
+    rcu_register_thread();
+
     qemu_mutex_lock_iothread();
     qemu_thread_get_self(cpu->thread);
     cpu->thread_id = qemu_get_thread_id();
@@ -1034,6 +1038,8 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
 {
     CPUState *cpu = arg;
 
+    rcu_register_thread();
+
     qemu_mutex_lock_iothread();
     qemu_tcg_init_cpu_signals();
     qemu_thread_get_self(cpu->thread);
diff --git a/iothread.c b/iothread.c
index 6d2a33f..443d176 100644
--- a/iothread.c
+++ b/iothread.c
@@ -18,6 +18,7 @@
 #include "sysemu/iothread.h"
 #include "qmp-commands.h"
 #include "qemu/error-report.h"
+#include "qemu/rcu.h"
 
 typedef ObjectClass IOThreadClass;
 
@@ -31,6 +32,8 @@ static void *iothread_run(void *opaque)
     IOThread *iothread = opaque;
     bool blocking;
 
+    rcu_register_thread();
+
     qemu_mutex_lock(&iothread->init_done_lock);
     iothread->thread_id = qemu_get_thread_id();
     qemu_cond_signal(&iothread->init_done_cond);
diff --git a/migration/migration.c b/migration/migration.c
index 45719a0..7f1e05a 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -22,6 +22,7 @@
 #include "block/block.h"
 #include "qapi/qmp/qerror.h"
 #include "qemu/sockets.h"
+#include "qemu/rcu.h"
 #include "migration/block.h"
 #include "qemu/thread.h"
 #include "qmp-commands.h"
@@ -911,6 +912,8 @@ static void *migration_thread(void *opaque)
     int64_t start_time = initial_time;
     bool old_vm_running = false;
 
+    rcu_register_thread();
+
     qemu_savevm_state_header(s->file);
     qemu_savevm_state_begin(s->file, &s->params);
 
diff --git a/tests/test-rcu-list.c b/tests/test-rcu-list.c
index 4c5f62e..af98bdb 100644
--- a/tests/test-rcu-list.c
+++ b/tests/test-rcu-list.c
@@ -108,6 +108,8 @@ static void *rcu_q_reader(void *arg)
     long long n_reads_local = 0;
     struct list_element *el;
 
+    rcu_register_thread();
+
     *(struct rcu_reader_data **)arg = &rcu_reader;
     atomic_inc(&nthreadsrunning);
     while (goflag == GOFLAG_INIT) {
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [Qemu-devel] [PATCH 3/3] rcu: detect missing rcu_register_thread()
  2015-07-13 11:31 [Qemu-devel] [PATCH 0/3] rcu: missing thread registration Paolo Bonzini
  2015-07-13 11:31 ` [Qemu-devel] [PATCH 1/3] rcu: automatically unregister threads when they exit Paolo Bonzini
  2015-07-13 11:31 ` [Qemu-devel] [PATCH 2/3] rcu: actually register threads that have RCU read-side critical sections Paolo Bonzini
@ 2015-07-13 11:31 ` Paolo Bonzini
  2015-07-14  3:36 ` [Qemu-devel] [PATCH 0/3] rcu: missing thread registration Fam Zheng
  3 siblings, 0 replies; 5+ messages in thread
From: Paolo Bonzini @ 2015-07-13 11:31 UTC (permalink / raw)
  To: qemu-devel

Use an "impossible" value for the .depth field in order to quickly
detect threads that have not registered themselves with the RCU
subsystem.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 include/qemu/rcu.h |  4 +++-
 util/rcu.c         | 18 ++++++++++++++++--
 2 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/include/qemu/rcu.h b/include/qemu/rcu.h
index 7df1e86..4facb35 100644
--- a/include/qemu/rcu.h
+++ b/include/qemu/rcu.h
@@ -82,7 +82,9 @@ static inline void rcu_read_lock(void)
     struct rcu_reader_data *p_rcu_reader = &rcu_reader;
     unsigned ctr;
 
-    if (p_rcu_reader->depth++ > 0) {
+    p_rcu_reader->depth++;
+    assert(p_rcu_reader->depth >= 1);
+    if (p_rcu_reader->depth > 1) {
         return;
     }
 
diff --git a/util/rcu.c b/util/rcu.c
index 8830295..435cdbe 100644
--- a/util/rcu.c
+++ b/util/rcu.c
@@ -63,8 +63,11 @@ static inline int rcu_gp_ongoing(unsigned long *ctr)
 
 /* Written to only by each individual reader. Read by both the reader and the
  * writers.
+ *
+ * Initializing the depth to -1 causes an assertion failure on the first
+ * call to rcu_read_lock() if the thread does not call rcu_register_thread().
  */
-__thread struct rcu_reader_data rcu_reader;
+__thread struct rcu_reader_data rcu_reader = { .depth = -1 };
 
 /* Protected by rcu_gp_lock.  */
 typedef QLIST_HEAD(, rcu_reader_data) ThreadList;
@@ -277,7 +280,12 @@ static void rcu_unregister_thread_notify(Notifier *n, void *data)
 
 void rcu_register_thread(void)
 {
-    assert(rcu_reader.ctr == 0);
+    /* rcu_reader.depth is also used to detect whether the thread is
+     * registered.
+     */
+    assert(rcu_reader.depth == -1);
+    rcu_reader.depth = 0;
+
     qemu_mutex_lock(&rcu_gp_lock);
     QLIST_INSERT_HEAD(&registry, &rcu_reader, node);
     qemu_mutex_unlock(&rcu_gp_lock);
@@ -288,6 +296,12 @@ void rcu_register_thread(void)
 
 void rcu_unregister_thread(void)
 {
+    /* Resetting the depth to -1 causes an assertion failure on the next
+     * call to rcu_read_lock().
+     */
+    assert(rcu_reader.depth == 0);
+    rcu_reader.depth = -1;
+
     qemu_mutex_lock(&rcu_gp_lock);
     QLIST_REMOVE(&rcu_reader, node);
     qemu_mutex_unlock(&rcu_gp_lock);
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [Qemu-devel] [PATCH 0/3] rcu: missing thread registration
  2015-07-13 11:31 [Qemu-devel] [PATCH 0/3] rcu: missing thread registration Paolo Bonzini
                   ` (2 preceding siblings ...)
  2015-07-13 11:31 ` [Qemu-devel] [PATCH 3/3] rcu: detect missing rcu_register_thread() Paolo Bonzini
@ 2015-07-14  3:36 ` Fam Zheng
  3 siblings, 0 replies; 5+ messages in thread
From: Fam Zheng @ 2015-07-14  3:36 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: qemu-devel

On Mon, 07/13 13:31, Paolo Bonzini wrote:
> Patch 2 fixes the problem, whereby threads were not being registered
> but still happily used RCU.  Patch 1 simplifies the registration by
> making rcu_unregister_thread automatic.  Patch 3 avoids having the
> same bug in the future.

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

> 
> Paolo
> 
> Paolo Bonzini (3):
>   rcu: automatically unregister threads when they exit
>   rcu: actually register threads that have RCU read-side critical
>     sections
>   rcu: detect missing rcu_register_thread()
> 
>  cpus.c                |  6 ++++++
>  include/qemu/rcu.h    |  4 +++-
>  iothread.c            |  3 +++
>  migration/migration.c |  3 +++
>  tests/rcutorture.c    | 10 ----------
>  tests/test-rcu-list.c |  2 ++
>  util/rcu.c            | 30 ++++++++++++++++++++++++++++--
>  7 files changed, 45 insertions(+), 13 deletions(-)
> 
> -- 
> 2.4.3
> 
> 

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2015-07-14  3:36 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-07-13 11:31 [Qemu-devel] [PATCH 0/3] rcu: missing thread registration Paolo Bonzini
2015-07-13 11:31 ` [Qemu-devel] [PATCH 1/3] rcu: automatically unregister threads when they exit Paolo Bonzini
2015-07-13 11:31 ` [Qemu-devel] [PATCH 2/3] rcu: actually register threads that have RCU read-side critical sections Paolo Bonzini
2015-07-13 11:31 ` [Qemu-devel] [PATCH 3/3] rcu: detect missing rcu_register_thread() Paolo Bonzini
2015-07-14  3:36 ` [Qemu-devel] [PATCH 0/3] rcu: missing thread registration Fam Zheng

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).