On Fri, 21 Feb 2014 15:46:55 +0100 Stefan Hajnoczi <stefa...@redhat.com> wrote:
> 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 | 30 +++++++++++ > iothread.c | 123 > ++++++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 154 insertions(+) > create mode 100644 include/sysemu/iothread.h > create mode 100644 iothread.c > > diff --git a/Makefile.objs b/Makefile.objs > index ac1d0e1..e24b89c 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 += qdev-monitor.o device-hotplug.o > common-obj-$(CONFIG_WIN32) += os-win32.o > diff --git a/include/sysemu/iothread.h b/include/sysemu/iothread.h > new file mode 100644 > index 0000000..a32214a > --- /dev/null > +++ b/include/sysemu/iothread.h > @@ -0,0 +1,30 @@ > +/* > + * 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" > + > +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 0000000..033de7f > --- /dev/null > +++ b/iothread.c > @@ -0,0 +1,123 @@ > +/* > + * 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 "qom/object_interfaces.h" > +#include "qemu/module.h" > +#include "qemu/thread.h" > +#include "block/aio.h" > +#include "sysemu/iothread.h" > + > +#define IOTHREADS_PATH "/objects" > + > +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; > + > + 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); > + } > + return NULL; > +} > + > +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 void iothread_complete(UserCreatable *obj, Error **errp) > +{ > + IOThread *iothread = IOTHREAD(obj); > + > + iothread->stopping = false; > + iothread->ctx = aio_context_new(); > + > + /* This assumes we are 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_class_init(ObjectClass *klass, void *class_data) > +{ > + UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass); > + ucc->complete = iothread_complete; > +} > + > +static const TypeInfo iothread_info = { > + .name = TYPE_IOTHREAD, > + .parent = TYPE_OBJECT, > + .class_init = iothread_class_init, > + .instance_size = sizeof(IOThread), > + .instance_finalize = iothread_instance_finalize, > + .interfaces = (InterfaceInfo[]) { > + {TYPE_USER_CREATABLE}, > + {} > + }, > +}; > + > +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 *)object_dynamic_cast(child, TYPE_IOTHREAD); > +} > + > +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; > +} it seems to be a more generic issue, i.e. QOM object wanting to know its name. I've did something similar for memory_backend except of cutting of parent's path. Could we make and use a more generic accessor for object name? > +AioContext *iothread_get_aio_context(IOThread *iothread) > +{ > + return iothread->ctx; > +}