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 "qemu/thread.h" 18 #include "block/aio.h" 19 #include "sysemu/iothread.h" 20 #include "qmp-commands.h" 21 22 #define IOTHREADS_PATH "/objects" 23 24 typedef ObjectClass IOThreadClass; 25 struct IOThread { 26 Object parent_obj; 27 28 QemuThread thread; 29 AioContext *ctx; 30 QemuMutex init_done_lock; 31 QemuCond init_done_cond; /* is thread initialization done? */ 32 bool stopping; 33 int thread_id; 34 }; 35 36 #define IOTHREAD_GET_CLASS(obj) \ 37 OBJECT_GET_CLASS(IOThreadClass, obj, TYPE_IOTHREAD) 38 #define IOTHREAD_CLASS(klass) \ 39 OBJECT_CLASS_CHECK(IOThreadClass, klass, TYPE_IOTHREAD) 40 41 static void *iothread_run(void *opaque) 42 { 43 IOThread *iothread = opaque; 44 45 qemu_mutex_lock(&iothread->init_done_lock); 46 iothread->thread_id = qemu_get_thread_id(); 47 qemu_cond_signal(&iothread->init_done_cond); 48 qemu_mutex_unlock(&iothread->init_done_lock); 49 50 while (!iothread->stopping) { 51 aio_context_acquire(iothread->ctx); 52 while (!iothread->stopping && aio_poll(iothread->ctx, true)) { 53 /* Progress was made, keep going */ 54 } 55 aio_context_release(iothread->ctx); 56 } 57 return NULL; 58 } 59 60 static void iothread_instance_finalize(Object *obj) 61 { 62 IOThread *iothread = IOTHREAD(obj); 63 64 iothread->stopping = true; 65 aio_notify(iothread->ctx); 66 qemu_thread_join(&iothread->thread); 67 qemu_cond_destroy(&iothread->init_done_cond); 68 qemu_mutex_destroy(&iothread->init_done_lock); 69 aio_context_unref(iothread->ctx); 70 } 71 72 static void iothread_complete(UserCreatable *obj, Error **errp) 73 { 74 IOThread *iothread = IOTHREAD(obj); 75 76 iothread->stopping = false; 77 iothread->ctx = aio_context_new(); 78 iothread->thread_id = -1; 79 80 qemu_mutex_init(&iothread->init_done_lock); 81 qemu_cond_init(&iothread->init_done_cond); 82 83 /* This assumes we are called from a thread with useful CPU affinity for us 84 * to inherit. 85 */ 86 qemu_thread_create(&iothread->thread, "iothread", iothread_run, 87 iothread, QEMU_THREAD_JOINABLE); 88 89 /* Wait for initialization to complete */ 90 qemu_mutex_lock(&iothread->init_done_lock); 91 while (iothread->thread_id == -1) { 92 qemu_cond_wait(&iothread->init_done_cond, 93 &iothread->init_done_lock); 94 } 95 qemu_mutex_unlock(&iothread->init_done_lock); 96 } 97 98 static void iothread_class_init(ObjectClass *klass, void *class_data) 99 { 100 UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass); 101 ucc->complete = iothread_complete; 102 } 103 104 static const TypeInfo iothread_info = { 105 .name = TYPE_IOTHREAD, 106 .parent = TYPE_OBJECT, 107 .class_init = iothread_class_init, 108 .instance_size = sizeof(IOThread), 109 .instance_finalize = iothread_instance_finalize, 110 .interfaces = (InterfaceInfo[]) { 111 {TYPE_USER_CREATABLE}, 112 {} 113 }, 114 }; 115 116 static void iothread_register_types(void) 117 { 118 type_register_static(&iothread_info); 119 } 120 121 type_init(iothread_register_types) 122 123 IOThread *iothread_find(const char *id) 124 { 125 Object *container = container_get(object_get_root(), IOTHREADS_PATH); 126 Object *child; 127 128 child = object_property_get_link(container, id, NULL); 129 if (!child) { 130 return NULL; 131 } 132 return (IOThread *)object_dynamic_cast(child, TYPE_IOTHREAD); 133 } 134 135 char *iothread_get_id(IOThread *iothread) 136 { 137 return object_get_canonical_path_component(OBJECT(iothread)); 138 } 139 140 AioContext *iothread_get_aio_context(IOThread *iothread) 141 { 142 return iothread->ctx; 143 } 144 145 static int query_one_iothread(Object *object, void *opaque) 146 { 147 IOThreadInfoList ***prev = opaque; 148 IOThreadInfoList *elem; 149 IOThreadInfo *info; 150 IOThread *iothread; 151 152 iothread = (IOThread *)object_dynamic_cast(object, TYPE_IOTHREAD); 153 if (!iothread) { 154 return 0; 155 } 156 157 info = g_new0(IOThreadInfo, 1); 158 info->id = iothread_get_id(iothread); 159 info->thread_id = iothread->thread_id; 160 161 elem = g_new0(IOThreadInfoList, 1); 162 elem->value = info; 163 elem->next = NULL; 164 165 **prev = elem; 166 *prev = &elem->next; 167 return 0; 168 } 169 170 IOThreadInfoList *qmp_query_iothreads(Error **errp) 171 { 172 IOThreadInfoList *head = NULL; 173 IOThreadInfoList **prev = &head; 174 Object *container = container_get(object_get_root(), IOTHREADS_PATH); 175 176 object_child_foreach(container, query_one_iothread, &prev); 177 return head; 178 } 179