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 "qemu/osdep.h"
  15#include "qom/object.h"
  16#include "qom/object_interfaces.h"
  17#include "qemu/module.h"
  18#include "block/aio.h"
  19#include "block/block.h"
  20#include "sysemu/iothread.h"
  21#include "qmp-commands.h"
  22#include "qemu/error-report.h"
  23#include "qemu/rcu.h"
  24#include "qemu/main-loop.h"
  25
  26typedef ObjectClass IOThreadClass;
  27
  28#define IOTHREAD_GET_CLASS(obj) \
  29   OBJECT_GET_CLASS(IOThreadClass, obj, TYPE_IOTHREAD)
  30#define IOTHREAD_CLASS(klass) \
  31   OBJECT_CLASS_CHECK(IOThreadClass, klass, TYPE_IOTHREAD)
  32
  33static __thread IOThread *my_iothread;
  34
  35AioContext *qemu_get_current_aio_context(void)
  36{
  37    return my_iothread ? my_iothread->ctx : qemu_get_aio_context();
  38}
  39
  40static void *iothread_run(void *opaque)
  41{
  42    IOThread *iothread = opaque;
  43
  44    rcu_register_thread();
  45
  46    my_iothread = iothread;
  47    qemu_mutex_lock(&iothread->init_done_lock);
  48    iothread->thread_id = qemu_get_thread_id();
  49    qemu_cond_signal(&iothread->init_done_cond);
  50    qemu_mutex_unlock(&iothread->init_done_lock);
  51
  52    while (!atomic_read(&iothread->stopping)) {
  53        aio_poll(iothread->ctx, true);
  54    }
  55
  56    rcu_unregister_thread();
  57    return NULL;
  58}
  59
  60static int iothread_stop(Object *object, void *opaque)
  61{
  62    IOThread *iothread;
  63
  64    iothread = (IOThread *)object_dynamic_cast(object, TYPE_IOTHREAD);
  65    if (!iothread || !iothread->ctx) {
  66        return 0;
  67    }
  68    iothread->stopping = true;
  69    aio_notify(iothread->ctx);
  70    qemu_thread_join(&iothread->thread);
  71    return 0;
  72}
  73
  74static void iothread_instance_finalize(Object *obj)
  75{
  76    IOThread *iothread = IOTHREAD(obj);
  77
  78    iothread_stop(obj, NULL);
  79    qemu_cond_destroy(&iothread->init_done_cond);
  80    qemu_mutex_destroy(&iothread->init_done_lock);
  81    if (!iothread->ctx) {
  82        return;
  83    }
  84    aio_context_unref(iothread->ctx);
  85}
  86
  87static void iothread_complete(UserCreatable *obj, Error **errp)
  88{
  89    Error *local_error = NULL;
  90    IOThread *iothread = IOTHREAD(obj);
  91    char *name, *thread_name;
  92
  93    iothread->stopping = false;
  94    iothread->thread_id = -1;
  95    iothread->ctx = aio_context_new(&local_error);
  96    if (!iothread->ctx) {
  97        error_propagate(errp, local_error);
  98        return;
  99    }
 100
 101    qemu_mutex_init(&iothread->init_done_lock);
 102    qemu_cond_init(&iothread->init_done_cond);
 103
 104    /* This assumes we are called from a thread with useful CPU affinity for us
 105     * to inherit.
 106     */
 107    name = object_get_canonical_path_component(OBJECT(obj));
 108    thread_name = g_strdup_printf("IO %s", name);
 109    qemu_thread_create(&iothread->thread, thread_name, iothread_run,
 110                       iothread, QEMU_THREAD_JOINABLE);
 111    g_free(thread_name);
 112    g_free(name);
 113
 114    /* Wait for initialization to complete */
 115    qemu_mutex_lock(&iothread->init_done_lock);
 116    while (iothread->thread_id == -1) {
 117        qemu_cond_wait(&iothread->init_done_cond,
 118                       &iothread->init_done_lock);
 119    }
 120    qemu_mutex_unlock(&iothread->init_done_lock);
 121}
 122
 123static void iothread_class_init(ObjectClass *klass, void *class_data)
 124{
 125    UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass);
 126    ucc->complete = iothread_complete;
 127}
 128
 129static const TypeInfo iothread_info = {
 130    .name = TYPE_IOTHREAD,
 131    .parent = TYPE_OBJECT,
 132    .class_init = iothread_class_init,
 133    .instance_size = sizeof(IOThread),
 134    .instance_finalize = iothread_instance_finalize,
 135    .interfaces = (InterfaceInfo[]) {
 136        {TYPE_USER_CREATABLE},
 137        {}
 138    },
 139};
 140
 141static void iothread_register_types(void)
 142{
 143    type_register_static(&iothread_info);
 144}
 145
 146type_init(iothread_register_types)
 147
 148char *iothread_get_id(IOThread *iothread)
 149{
 150    return object_get_canonical_path_component(OBJECT(iothread));
 151}
 152
 153AioContext *iothread_get_aio_context(IOThread *iothread)
 154{
 155    return iothread->ctx;
 156}
 157
 158static int query_one_iothread(Object *object, void *opaque)
 159{
 160    IOThreadInfoList ***prev = opaque;
 161    IOThreadInfoList *elem;
 162    IOThreadInfo *info;
 163    IOThread *iothread;
 164
 165    iothread = (IOThread *)object_dynamic_cast(object, TYPE_IOTHREAD);
 166    if (!iothread) {
 167        return 0;
 168    }
 169
 170    info = g_new0(IOThreadInfo, 1);
 171    info->id = iothread_get_id(iothread);
 172    info->thread_id = iothread->thread_id;
 173
 174    elem = g_new0(IOThreadInfoList, 1);
 175    elem->value = info;
 176    elem->next = NULL;
 177
 178    **prev = elem;
 179    *prev = &elem->next;
 180    return 0;
 181}
 182
 183IOThreadInfoList *qmp_query_iothreads(Error **errp)
 184{
 185    IOThreadInfoList *head = NULL;
 186    IOThreadInfoList **prev = &head;
 187    Object *container = object_get_objects_root();
 188
 189    object_child_foreach(container, query_one_iothread, &prev);
 190    return head;
 191}
 192
 193void iothread_stop_all(void)
 194{
 195    Object *container = object_get_objects_root();
 196    BlockDriverState *bs;
 197    BdrvNextIterator it;
 198
 199    for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
 200        AioContext *ctx = bdrv_get_aio_context(bs);
 201        if (ctx == qemu_get_aio_context()) {
 202            continue;
 203        }
 204        aio_context_acquire(ctx);
 205        bdrv_set_aio_context(bs, qemu_get_aio_context());
 206        aio_context_release(ctx);
 207    }
 208
 209    object_child_foreach(container, iothread_stop, NULL);
 210}
 211