summaryrefslogtreecommitdiffstats
path: root/tests/unit/iothread.c
diff options
context:
space:
mode:
authorThomas Huth2021-03-10 07:33:14 +0100
committerThomas Huth2021-03-12 15:46:30 +0100
commitda668aa15b99150a8595c491aee00d5d2426aaf9 (patch)
tree0463b0a303e807bdab46460f6c702be611bd7179 /tests/unit/iothread.c
parentMerge remote-tracking branch 'remotes/legoater/tags/pull-aspeed-20210309' int... (diff)
downloadqemu-da668aa15b99150a8595c491aee00d5d2426aaf9.tar.gz
qemu-da668aa15b99150a8595c491aee00d5d2426aaf9.tar.xz
qemu-da668aa15b99150a8595c491aee00d5d2426aaf9.zip
tests: Move unit tests into a separate directory
The main tests directory still looks very crowded, and it's not clear which files are part of a unit tests and which belong to a different test subsystem. Let's clean up the mess and move the unit tests to a separate directory. Message-Id: <20210310063314.1049838-1-thuth@redhat.com> Acked-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Thomas Huth <thuth@redhat.com>
Diffstat (limited to 'tests/unit/iothread.c')
-rw-r--r--tests/unit/iothread.c127
1 files changed, 127 insertions, 0 deletions
diff --git a/tests/unit/iothread.c b/tests/unit/iothread.c
new file mode 100644
index 0000000000..afde12b4ef
--- /dev/null
+++ b/tests/unit/iothread.c
@@ -0,0 +1,127 @@
+/*
+ * Event loop thread implementation for unit tests
+ *
+ * Copyright Red Hat Inc., 2013, 2016
+ *
+ * Authors:
+ * Stefan Hajnoczi <stefanha@redhat.com>
+ * Paolo Bonzini <pbonzini@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "block/aio.h"
+#include "qemu/main-loop.h"
+#include "qemu/rcu.h"
+#include "iothread.h"
+
+struct IOThread {
+ AioContext *ctx;
+ GMainContext *worker_context;
+ GMainLoop *main_loop;
+
+ QemuThread thread;
+ QemuMutex init_done_lock;
+ QemuCond init_done_cond; /* is thread initialization done? */
+ bool stopping;
+};
+
+static __thread IOThread *my_iothread;
+
+AioContext *qemu_get_current_aio_context(void)
+{
+ return my_iothread ? my_iothread->ctx : qemu_get_aio_context();
+}
+
+static void iothread_init_gcontext(IOThread *iothread)
+{
+ GSource *source;
+
+ iothread->worker_context = g_main_context_new();
+ source = aio_get_g_source(iothread_get_aio_context(iothread));
+ g_source_attach(source, iothread->worker_context);
+ g_source_unref(source);
+ iothread->main_loop = g_main_loop_new(iothread->worker_context, TRUE);
+}
+
+static void *iothread_run(void *opaque)
+{
+ IOThread *iothread = opaque;
+
+ rcu_register_thread();
+
+ my_iothread = iothread;
+ qemu_mutex_lock(&iothread->init_done_lock);
+ iothread->ctx = aio_context_new(&error_abort);
+
+ /*
+ * We must connect the ctx to a GMainContext, because in older versions
+ * of glib the g_source_ref()/unref() functions are not threadsafe
+ * on sources without a context.
+ */
+ iothread_init_gcontext(iothread);
+
+ /*
+ * g_main_context_push_thread_default() must be called before anything
+ * in this new thread uses glib.
+ */
+ g_main_context_push_thread_default(iothread->worker_context);
+
+ qemu_cond_signal(&iothread->init_done_cond);
+ qemu_mutex_unlock(&iothread->init_done_lock);
+
+ while (!qatomic_read(&iothread->stopping)) {
+ aio_poll(iothread->ctx, true);
+ }
+
+ g_main_context_pop_thread_default(iothread->worker_context);
+ rcu_unregister_thread();
+ return NULL;
+}
+
+static void iothread_stop_bh(void *opaque)
+{
+ IOThread *iothread = opaque;
+
+ iothread->stopping = true;
+}
+
+void iothread_join(IOThread *iothread)
+{
+ aio_bh_schedule_oneshot(iothread->ctx, iothread_stop_bh, iothread);
+ qemu_thread_join(&iothread->thread);
+ g_main_context_unref(iothread->worker_context);
+ g_main_loop_unref(iothread->main_loop);
+ qemu_cond_destroy(&iothread->init_done_cond);
+ qemu_mutex_destroy(&iothread->init_done_lock);
+ aio_context_unref(iothread->ctx);
+ g_free(iothread);
+}
+
+IOThread *iothread_new(void)
+{
+ IOThread *iothread = g_new0(IOThread, 1);
+
+ qemu_mutex_init(&iothread->init_done_lock);
+ qemu_cond_init(&iothread->init_done_cond);
+ qemu_thread_create(&iothread->thread, NULL, iothread_run,
+ iothread, QEMU_THREAD_JOINABLE);
+
+ /* Wait for initialization to complete */
+ qemu_mutex_lock(&iothread->init_done_lock);
+ while (iothread->ctx == NULL) {
+ qemu_cond_wait(&iothread->init_done_cond,
+ &iothread->init_done_lock);
+ }
+ qemu_mutex_unlock(&iothread->init_done_lock);
+ return iothread;
+}
+
+AioContext *iothread_get_aio_context(IOThread *iothread)
+{
+ return iothread->ctx;
+}