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