Re: [Qemu-devel] [RFC 3/7] iothread: add I/O thread object
On Thu, Dec 12, 2013 at 12:00:12PM -0600, Michael Roth wrote: Quoting Stefan Hajnoczi (2013-12-12 07:19:40) +static void *iothread_run(void *opaque) +{ +IOThread *iothread = opaque; + +for (;;) { +/* TODO can we optimize away acquire/release to only happen when + * aio_notify() was called? + */ Perhaps have the AioContext's notifier callback set a flag that can be checked for afterward to determine whether we should release/re-acquire? Calls to aio_context_acquire() could reset it upon acquistion, so we could maybe do something like: while(!iothread-stopping) { aio_context_acquire(iothread-ctx); while (!iothread-ctx-notified) { aio_poll(iothread-ctx, true); } aio_context_release(iothread-ctx); } When aio_notify() kicks aio_poll() it returns false. So I was thinking of: while (!iothread-stopping) { aio_context_acquire(iothread-ctx); while (!iothread-stopping aio_poll(iothread-ctx, true)) { /* Progress was made, keep going */ } aio_context_release(iothread-ctx); } I'll try it in the next version. Just didn't want to get too fancy yet. +aio_context_acquire(iothread-ctx); +if (iothread-stopping) { +aio_context_release(iothread-ctx); +break; +} +aio_poll(iothread-ctx, true); +aio_context_release(iothread-ctx); +} +return NULL; +} + +static void iothread_instance_init(Object *obj) +{ +IOThread *iothread = IOTHREAD(obj); + +iothread-stopping = false; +iothread-ctx = aio_context_new(); + +/* This assumes .instance_init() is called from a thread with useful CPU + * affinity for us to inherit. + */ Is this assumption necessary/controllable? Couldn't we just expose the thread id via QOM or some other interface so users/management can set the affinity later? This assumption holds since the monitor and command-line run in the main thread. The fix has traditionally been to create the thread from a BH scheduled in the main loop. That way it inherits the main thread's affinity. We definitely need to expose tids via QOM/QMP. That's something I'm looking at QContext for. Did you already implement an interface? Stefan
[Qemu-devel] [RFC 3/7] iothread: add I/O thread object
This is a stand-in for Michael Roth's QContext. I expect this to be replaced once QContext is completed. The IOThread object is an AioContext event loop thread. This patch adds the concept of multiple event loop threads, allowing users to define them. When SMP guests run on SMP hosts it makes sense to instantiate multiple IOThreads. This spreads event loop processing across multiple cores. Note that additional patches are required to actually bind a device to an IOThread. Signed-off-by: Stefan Hajnoczi stefa...@redhat.com --- Makefile.objs | 1 + include/sysemu/iothread.h | 31 + iothread.c| 115 ++ 3 files changed, 147 insertions(+) create mode 100644 include/sysemu/iothread.h create mode 100644 iothread.c diff --git a/Makefile.objs b/Makefile.objs index 2b6c1fe..a1102a5 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -42,6 +42,7 @@ libcacard-y += libcacard/vcardt.o ifeq ($(CONFIG_SOFTMMU),y) common-obj-y = $(block-obj-y) blockdev.o blockdev-nbd.o block/ +common-obj-y += iothread.o common-obj-y += net/ common-obj-y += readline.o common-obj-y += qdev-monitor.o device-hotplug.o diff --git a/include/sysemu/iothread.h b/include/sysemu/iothread.h new file mode 100644 index 000..8c49bd6 --- /dev/null +++ b/include/sysemu/iothread.h @@ -0,0 +1,31 @@ +/* + * Event loop thread + * + * Copyright Red Hat Inc., 2013 + * + * Authors: + * Stefan Hajnoczi stefa...@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. + * + */ + +#ifndef IOTHREAD_H +#define IOTHREAD_H + +#include block/aio.h + +#define TYPE_IOTHREAD iothread +#define IOTHREADS_PATH /backends/iothreads + +typedef struct IOThread IOThread; + +#define IOTHREAD(obj) \ + OBJECT_CHECK(IOThread, obj, TYPE_IOTHREAD) + +IOThread *iothread_find(const char *id); +char *iothread_get_id(IOThread *iothread); +AioContext *iothread_get_aio_context(IOThread *iothread); + +#endif /* IOTHREAD_H */ diff --git a/iothread.c b/iothread.c new file mode 100644 index 000..dbc6047 --- /dev/null +++ b/iothread.c @@ -0,0 +1,115 @@ +/* + * Event loop thread + * + * Copyright Red Hat Inc., 2013 + * + * Authors: + * Stefan Hajnoczi stefa...@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 qom/object.h +#include qemu/module.h +#include qemu/thread.h +#include block/aio.h +#include sysemu/iothread.h + +typedef ObjectClass IOThreadClass; +struct IOThread { +Object parent; +QemuThread thread; +AioContext *ctx; +bool stopping; +}; + +#define IOTHREAD_GET_CLASS(obj) \ + OBJECT_GET_CLASS(IOThreadClass, obj, TYPE_IOTHREAD) +#define IOTHREAD_CLASS(klass) \ + OBJECT_CLASS_CHECK(IOThreadClass, klass, TYPE_IOTHREAD) + +static void *iothread_run(void *opaque) +{ +IOThread *iothread = opaque; + +for (;;) { +/* TODO can we optimize away acquire/release to only happen when + * aio_notify() was called? + */ +aio_context_acquire(iothread-ctx); +if (iothread-stopping) { +aio_context_release(iothread-ctx); +break; +} +aio_poll(iothread-ctx, true); +aio_context_release(iothread-ctx); +} +return NULL; +} + +static void iothread_instance_init(Object *obj) +{ +IOThread *iothread = IOTHREAD(obj); + +iothread-stopping = false; +iothread-ctx = aio_context_new(); + +/* This assumes .instance_init() is called from a thread with useful CPU + * affinity for us to inherit. + */ +qemu_thread_create(iothread-thread, iothread_run, + iothread, QEMU_THREAD_JOINABLE); +} + +static void iothread_instance_finalize(Object *obj) +{ +IOThread *iothread = IOTHREAD(obj); + +iothread-stopping = true; +aio_notify(iothread-ctx); +qemu_thread_join(iothread-thread); +aio_context_unref(iothread-ctx); +} + +static const TypeInfo iothread_info = { +.name = TYPE_IOTHREAD, +.parent = TYPE_OBJECT, +.instance_size = sizeof(IOThread), +.instance_init = iothread_instance_init, +.instance_finalize = iothread_instance_finalize, +}; + +static void iothread_register_types(void) +{ +type_register_static(iothread_info); +} + +type_init(iothread_register_types) + +IOThread *iothread_find(const char *id) +{ +Object *container = container_get(object_get_root(), IOTHREADS_PATH); +Object *child; + +child = object_property_get_link(container, id, NULL); +if (!child) { +return NULL; +} +return IOTHREAD(child); +} + +char *iothread_get_id(IOThread *iothread) +{ +/* The last path component is the identifier */ +char *path = object_get_canonical_path(OBJECT(iothread)); +char *id = g_strdup(path[sizeof(IOTHREADS_PATH)]); +g_free(path); +return id; +} + +AioContext
Re: [Qemu-devel] [RFC 3/7] iothread: add I/O thread object
Quoting Stefan Hajnoczi (2013-12-12 07:19:40) This is a stand-in for Michael Roth's QContext. I expect this to be replaced once QContext is completed. The IOThread object is an AioContext event loop thread. This patch adds the concept of multiple event loop threads, allowing users to define them. When SMP guests run on SMP hosts it makes sense to instantiate multiple IOThreads. This spreads event loop processing across multiple cores. Note that additional patches are required to actually bind a device to an IOThread. Signed-off-by: Stefan Hajnoczi stefa...@redhat.com --- Makefile.objs | 1 + include/sysemu/iothread.h | 31 + iothread.c| 115 ++ 3 files changed, 147 insertions(+) create mode 100644 include/sysemu/iothread.h create mode 100644 iothread.c diff --git a/Makefile.objs b/Makefile.objs index 2b6c1fe..a1102a5 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -42,6 +42,7 @@ libcacard-y += libcacard/vcardt.o ifeq ($(CONFIG_SOFTMMU),y) common-obj-y = $(block-obj-y) blockdev.o blockdev-nbd.o block/ +common-obj-y += iothread.o common-obj-y += net/ common-obj-y += readline.o common-obj-y += qdev-monitor.o device-hotplug.o diff --git a/include/sysemu/iothread.h b/include/sysemu/iothread.h new file mode 100644 index 000..8c49bd6 --- /dev/null +++ b/include/sysemu/iothread.h @@ -0,0 +1,31 @@ +/* + * Event loop thread + * + * Copyright Red Hat Inc., 2013 + * + * Authors: + * Stefan Hajnoczi stefa...@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. + * + */ + +#ifndef IOTHREAD_H +#define IOTHREAD_H + +#include block/aio.h + +#define TYPE_IOTHREAD iothread +#define IOTHREADS_PATH /backends/iothreads + +typedef struct IOThread IOThread; + +#define IOTHREAD(obj) \ + OBJECT_CHECK(IOThread, obj, TYPE_IOTHREAD) + +IOThread *iothread_find(const char *id); +char *iothread_get_id(IOThread *iothread); +AioContext *iothread_get_aio_context(IOThread *iothread); + +#endif /* IOTHREAD_H */ diff --git a/iothread.c b/iothread.c new file mode 100644 index 000..dbc6047 --- /dev/null +++ b/iothread.c @@ -0,0 +1,115 @@ +/* + * Event loop thread + * + * Copyright Red Hat Inc., 2013 + * + * Authors: + * Stefan Hajnoczi stefa...@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 qom/object.h +#include qemu/module.h +#include qemu/thread.h +#include block/aio.h +#include sysemu/iothread.h + +typedef ObjectClass IOThreadClass; +struct IOThread { +Object parent; +QemuThread thread; +AioContext *ctx; +bool stopping; +}; + +#define IOTHREAD_GET_CLASS(obj) \ + OBJECT_GET_CLASS(IOThreadClass, obj, TYPE_IOTHREAD) +#define IOTHREAD_CLASS(klass) \ + OBJECT_CLASS_CHECK(IOThreadClass, klass, TYPE_IOTHREAD) + +static void *iothread_run(void *opaque) +{ +IOThread *iothread = opaque; + +for (;;) { +/* TODO can we optimize away acquire/release to only happen when + * aio_notify() was called? + */ Perhaps have the AioContext's notifier callback set a flag that can be checked for afterward to determine whether we should release/re-acquire? Calls to aio_context_acquire() could reset it upon acquistion, so we could maybe do something like: while(!iothread-stopping) { aio_context_acquire(iothread-ctx); while (!iothread-ctx-notified) { aio_poll(iothread-ctx, true); } aio_context_release(iothread-ctx); } +aio_context_acquire(iothread-ctx); +if (iothread-stopping) { +aio_context_release(iothread-ctx); +break; +} +aio_poll(iothread-ctx, true); +aio_context_release(iothread-ctx); +} +return NULL; +} + +static void iothread_instance_init(Object *obj) +{ +IOThread *iothread = IOTHREAD(obj); + +iothread-stopping = false; +iothread-ctx = aio_context_new(); + +/* This assumes .instance_init() is called from a thread with useful CPU + * affinity for us to inherit. + */ Is this assumption necessary/controllable? Couldn't we just expose the thread id via QOM or some other interface so users/management can set the affinity later? +qemu_thread_create(iothread-thread, iothread_run, + iothread, QEMU_THREAD_JOINABLE); +} + +static void iothread_instance_finalize(Object *obj) +{ +IOThread *iothread = IOTHREAD(obj); + +iothread-stopping = true; +aio_notify(iothread-ctx); +qemu_thread_join(iothread-thread); +aio_context_unref(iothread-ctx); +} + +static const TypeInfo iothread_info = { +.name = TYPE_IOTHREAD, +.parent = TYPE_OBJECT, +.instance_size =