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