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