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