iothread.c 3.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
/*
 * Event loop thread
 *
 * Copyright Red Hat Inc., 2013
 *
 * Authors:
 *  Stefan Hajnoczi   <stefanha@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_obj;

    QemuThread thread;
    AioContext *ctx;
S
Stefan Hajnoczi 已提交
29 30
    QemuMutex init_done_lock;
    QemuCond init_done_cond;    /* is thread initialization done? */
31
    bool stopping;
S
Stefan Hajnoczi 已提交
32
    int thread_id;
33 34 35 36 37 38 39 40 41 42 43
};

#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;

S
Stefan Hajnoczi 已提交
44 45 46 47 48
    qemu_mutex_lock(&iothread->init_done_lock);
    iothread->thread_id = qemu_get_thread_id();
    qemu_cond_signal(&iothread->init_done_cond);
    qemu_mutex_unlock(&iothread->init_done_lock);

49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
    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);
S
Stefan Hajnoczi 已提交
66 67
    qemu_cond_destroy(&iothread->init_done_cond);
    qemu_mutex_destroy(&iothread->init_done_lock);
68 69 70 71 72 73 74 75 76
    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();
S
Stefan Hajnoczi 已提交
77 78 79 80
    iothread->thread_id = -1;

    qemu_mutex_init(&iothread->init_done_lock);
    qemu_cond_init(&iothread->init_done_cond);
81 82 83 84 85 86

    /* This assumes we are called from a thread with useful CPU affinity for us
     * to inherit.
     */
    qemu_thread_create(&iothread->thread, "iothread", iothread_run,
                       iothread, QEMU_THREAD_JOINABLE);
S
Stefan Hajnoczi 已提交
87 88 89 90 91 92 93 94

    /* Wait for initialization to complete */
    qemu_mutex_lock(&iothread->init_done_lock);
    while (iothread->thread_id == -1) {
        qemu_cond_wait(&iothread->init_done_cond,
                       &iothread->init_done_lock);
    }
    qemu_mutex_unlock(&iothread->init_done_lock);
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
}

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)
{
    return object_get_canonical_path_component(OBJECT(iothread));
}

AioContext *iothread_get_aio_context(IOThread *iothread)
{
    return iothread->ctx;
}