qemu/iothread.c
<<
>>
Prefs
   1/*
   2 * Event loop thread
   3 *
   4 * Copyright Red Hat Inc., 2013
   5 *
   6 * Authors:
   7 *  Stefan Hajnoczi   <stefanha@redhat.com>
   8 *
   9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
  10 * See the COPYING file in the top-level directory.
  11 *
  12 */
  13
  14#include "qom/object.h"
  15#include "qom/object_interfaces.h"
  16#include "qemu/module.h"
  17#include "block/aio.h"
  18#include "sysemu/iothread.h"
  19#include "qmp-commands.h"
  20#include "qemu/error-report.h"
  21#include "qemu/rcu.h"
  22
  23typedef ObjectClass IOThreadClass;
  24
  25#define IOTHREAD_GET_CLASS(obj) \
  26   OBJECT_GET_CLASS(IOThreadClass, obj, TYPE_IOTHREAD)
  27#define IOTHREAD_CLASS(klass) \
  28   OBJECT_CLASS_CHECK(IOThreadClass, klass, TYPE_IOTHREAD)
  29
  30static void *iothread_run(void *opaque)
  31{
  32    IOThread *iothread = opaque;
  33    bool blocking;
  34
  35    rcu_register_thread();
  36
  37    qemu_mutex_lock(&iothread->init_done_lock);
  38    iothread->thread_id = qemu_get_thread_id();
  39    qemu_cond_signal(&iothread->init_done_cond);
  40    qemu_mutex_unlock(&iothread->init_done_lock);
  41
  42    while (!iothread->stopping) {
  43        aio_context_acquire(iothread->ctx);
  44        blocking = true;
  45        while (!iothread->stopping && aio_poll(iothread->ctx, blocking)) {
  46            /* Progress was made, keep going */
  47            blocking = false;
  48        }
  49        aio_context_release(iothread->ctx);
  50    }
  51
  52    rcu_unregister_thread();
  53    return NULL;
  54}
  55
  56static void iothread_instance_finalize(Object *obj)
  57{
  58    IOThread *iothread = IOTHREAD(obj);
  59
  60    if (!iothread->ctx) {
  61        return;
  62    }
  63    iothread->stopping = true;
  64    aio_notify(iothread->ctx);
  65    qemu_thread_join(&iothread->thread);
  66    qemu_cond_destroy(&iothread->init_done_cond);
  67    qemu_mutex_destroy(&iothread->init_done_lock);
  68    aio_context_unref(iothread->ctx);
  69}
  70
  71static void iothread_complete(UserCreatable *obj, Error **errp)
  72{
  73    Error *local_error = NULL;
  74    IOThread *iothread = IOTHREAD(obj);
  75
  76    iothread->stopping = false;
  77    iothread->thread_id = -1;
  78    iothread->ctx = aio_context_new(&local_error);
  79    if (!iothread->ctx) {
  80        error_propagate(errp, local_error);
  81        return;
  82    }
  83
  84    qemu_mutex_init(&iothread->init_done_lock);
  85    qemu_cond_init(&iothread->init_done_cond);
  86
  87    /* This assumes we are called from a thread with useful CPU affinity for us
  88     * to inherit.
  89     */
  90    qemu_thread_create(&iothread->thread, "iothread", iothread_run,
  91                       iothread, QEMU_THREAD_JOINABLE);
  92
  93    /* Wait for initialization to complete */
  94    qemu_mutex_lock(&iothread->init_done_lock);
  95    while (iothread->thread_id == -1) {
  96        qemu_cond_wait(&iothread->init_done_cond,
  97                       &iothread->init_done_lock);
  98    }
  99    qemu_mutex_unlock(&iothread->init_done_lock);
 100}
 101
 102static void iothread_class_init(ObjectClass *klass, void *class_data)
 103{
 104    UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass);
 105    ucc->complete = iothread_complete;
 106}
 107
 108static const TypeInfo iothread_info = {
 109    .name = TYPE_IOTHREAD,
 110    .parent = TYPE_OBJECT,
 111    .class_init = iothread_class_init,
 112    .instance_size = sizeof(IOThread),
 113    .instance_finalize = iothread_instance_finalize,
 114    .interfaces = (InterfaceInfo[]) {
 115        {TYPE_USER_CREATABLE},
 116        {}
 117    },
 118};
 119
 120static void iothread_register_types(void)
 121{
 122    type_register_static(&iothread_info);
 123}
 124
 125type_init(iothread_register_types)
 126
 127char *iothread_get_id(IOThread *iothread)
 128{
 129    return object_get_canonical_path_component(OBJECT(iothread));
 130}
 131
 132AioContext *iothread_get_aio_context(IOThread *iothread)
 133{
 134    return iothread->ctx;
 135}
 136
 137static int query_one_iothread(Object *object, void *opaque)
 138{
 139    IOThreadInfoList ***prev = opaque;
 140    IOThreadInfoList *elem;
 141    IOThreadInfo *info;
 142    IOThread *iothread;
 143
 144    iothread = (IOThread *)object_dynamic_cast(object, TYPE_IOTHREAD);
 145    if (!iothread) {
 146        return 0;
 147    }
 148
 149    info = g_new0(IOThreadInfo, 1);
 150    info->id = iothread_get_id(iothread);
 151    info->thread_id = iothread->thread_id;
 152
 153    elem = g_new0(IOThreadInfoList, 1);
 154    elem->value = info;
 155    elem->next = NULL;
 156
 157    **prev = elem;
 158    *prev = &elem->next;
 159    return 0;
 160}
 161
 162IOThreadInfoList *qmp_query_iothreads(Error **errp)
 163{
 164    IOThreadInfoList *head = NULL;
 165    IOThreadInfoList **prev = &head;
 166    Object *container = object_get_objects_root();
 167
 168    object_child_foreach(container, query_one_iothread, &prev);
 169    return head;
 170}
 171