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 "block/aio.h" 18be8d8537SStefan Hajnoczi #include "sysemu/iothread.h" 19dc3dd0d2SStefan Hajnoczi #include "qmp-commands.h" 202f78e491SChrysostomos Nanakos #include "qemu/error-report.h" 21ab28bd23SPaolo Bonzini #include "qemu/rcu.h" 22be8d8537SStefan Hajnoczi 23be8d8537SStefan Hajnoczi typedef ObjectClass IOThreadClass; 24be8d8537SStefan Hajnoczi 25be8d8537SStefan Hajnoczi #define IOTHREAD_GET_CLASS(obj) \ 26be8d8537SStefan Hajnoczi OBJECT_GET_CLASS(IOThreadClass, obj, TYPE_IOTHREAD) 27be8d8537SStefan Hajnoczi #define IOTHREAD_CLASS(klass) \ 28be8d8537SStefan Hajnoczi OBJECT_CLASS_CHECK(IOThreadClass, klass, TYPE_IOTHREAD) 29be8d8537SStefan Hajnoczi 30be8d8537SStefan Hajnoczi static void *iothread_run(void *opaque) 31be8d8537SStefan Hajnoczi { 32be8d8537SStefan Hajnoczi IOThread *iothread = opaque; 33da5e1de9SStefan Hajnoczi bool blocking; 34be8d8537SStefan Hajnoczi 35ab28bd23SPaolo Bonzini rcu_register_thread(); 36ab28bd23SPaolo Bonzini 3788eb7c29SStefan Hajnoczi qemu_mutex_lock(&iothread->init_done_lock); 3888eb7c29SStefan Hajnoczi iothread->thread_id = qemu_get_thread_id(); 3988eb7c29SStefan Hajnoczi qemu_cond_signal(&iothread->init_done_cond); 4088eb7c29SStefan Hajnoczi qemu_mutex_unlock(&iothread->init_done_lock); 4188eb7c29SStefan Hajnoczi 42da5e1de9SStefan Hajnoczi while (!iothread->stopping) { 43da5e1de9SStefan Hajnoczi aio_context_acquire(iothread->ctx); 44da5e1de9SStefan Hajnoczi blocking = true; 45da5e1de9SStefan Hajnoczi while (!iothread->stopping && aio_poll(iothread->ctx, blocking)) { 46da5e1de9SStefan Hajnoczi /* Progress was made, keep going */ 47da5e1de9SStefan Hajnoczi blocking = false; 48da5e1de9SStefan Hajnoczi } 49da5e1de9SStefan Hajnoczi aio_context_release(iothread->ctx); 50be8d8537SStefan Hajnoczi } 51ab28bd23SPaolo Bonzini 52ab28bd23SPaolo Bonzini rcu_unregister_thread(); 53be8d8537SStefan Hajnoczi return NULL; 54be8d8537SStefan Hajnoczi } 55be8d8537SStefan Hajnoczi 56be8d8537SStefan Hajnoczi static void iothread_instance_finalize(Object *obj) 57be8d8537SStefan Hajnoczi { 58be8d8537SStefan Hajnoczi IOThread *iothread = IOTHREAD(obj); 59be8d8537SStefan Hajnoczi 602f78e491SChrysostomos Nanakos if (!iothread->ctx) { 612f78e491SChrysostomos Nanakos return; 622f78e491SChrysostomos Nanakos } 63be8d8537SStefan Hajnoczi iothread->stopping = true; 64be8d8537SStefan Hajnoczi aio_notify(iothread->ctx); 65be8d8537SStefan Hajnoczi qemu_thread_join(&iothread->thread); 6688eb7c29SStefan Hajnoczi qemu_cond_destroy(&iothread->init_done_cond); 6788eb7c29SStefan 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 { 732f78e491SChrysostomos Nanakos Error *local_error = NULL; 74be8d8537SStefan Hajnoczi IOThread *iothread = IOTHREAD(obj); 75*d21e8776SPaolo Bonzini char *name, *thread_name; 76be8d8537SStefan Hajnoczi 77be8d8537SStefan Hajnoczi iothread->stopping = false; 7888eb7c29SStefan Hajnoczi iothread->thread_id = -1; 792f78e491SChrysostomos Nanakos iothread->ctx = aio_context_new(&local_error); 802f78e491SChrysostomos Nanakos if (!iothread->ctx) { 812f78e491SChrysostomos Nanakos error_propagate(errp, local_error); 822f78e491SChrysostomos Nanakos return; 832f78e491SChrysostomos Nanakos } 8488eb7c29SStefan Hajnoczi 8588eb7c29SStefan Hajnoczi qemu_mutex_init(&iothread->init_done_lock); 8688eb7c29SStefan Hajnoczi qemu_cond_init(&iothread->init_done_cond); 87be8d8537SStefan Hajnoczi 88be8d8537SStefan Hajnoczi /* This assumes we are called from a thread with useful CPU affinity for us 89be8d8537SStefan Hajnoczi * to inherit. 90be8d8537SStefan Hajnoczi */ 91*d21e8776SPaolo Bonzini name = object_get_canonical_path_component(OBJECT(obj)); 92*d21e8776SPaolo Bonzini thread_name = g_strdup_printf("IO %s", name); 93*d21e8776SPaolo Bonzini qemu_thread_create(&iothread->thread, thread_name, iothread_run, 94be8d8537SStefan Hajnoczi iothread, QEMU_THREAD_JOINABLE); 95*d21e8776SPaolo Bonzini g_free(thread_name); 96*d21e8776SPaolo Bonzini g_free(name); 9788eb7c29SStefan Hajnoczi 9888eb7c29SStefan Hajnoczi /* Wait for initialization to complete */ 9988eb7c29SStefan Hajnoczi qemu_mutex_lock(&iothread->init_done_lock); 10088eb7c29SStefan Hajnoczi while (iothread->thread_id == -1) { 10188eb7c29SStefan Hajnoczi qemu_cond_wait(&iothread->init_done_cond, 10288eb7c29SStefan Hajnoczi &iothread->init_done_lock); 10388eb7c29SStefan Hajnoczi } 10488eb7c29SStefan Hajnoczi qemu_mutex_unlock(&iothread->init_done_lock); 105be8d8537SStefan Hajnoczi } 106be8d8537SStefan Hajnoczi 107be8d8537SStefan Hajnoczi static void iothread_class_init(ObjectClass *klass, void *class_data) 108be8d8537SStefan Hajnoczi { 109be8d8537SStefan Hajnoczi UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass); 110be8d8537SStefan Hajnoczi ucc->complete = iothread_complete; 111be8d8537SStefan Hajnoczi } 112be8d8537SStefan Hajnoczi 113be8d8537SStefan Hajnoczi static const TypeInfo iothread_info = { 114be8d8537SStefan Hajnoczi .name = TYPE_IOTHREAD, 115be8d8537SStefan Hajnoczi .parent = TYPE_OBJECT, 116be8d8537SStefan Hajnoczi .class_init = iothread_class_init, 117be8d8537SStefan Hajnoczi .instance_size = sizeof(IOThread), 118be8d8537SStefan Hajnoczi .instance_finalize = iothread_instance_finalize, 119be8d8537SStefan Hajnoczi .interfaces = (InterfaceInfo[]) { 120be8d8537SStefan Hajnoczi {TYPE_USER_CREATABLE}, 121be8d8537SStefan Hajnoczi {} 122be8d8537SStefan Hajnoczi }, 123be8d8537SStefan Hajnoczi }; 124be8d8537SStefan Hajnoczi 125be8d8537SStefan Hajnoczi static void iothread_register_types(void) 126be8d8537SStefan Hajnoczi { 127be8d8537SStefan Hajnoczi type_register_static(&iothread_info); 128be8d8537SStefan Hajnoczi } 129be8d8537SStefan Hajnoczi 130be8d8537SStefan Hajnoczi type_init(iothread_register_types) 131be8d8537SStefan Hajnoczi 132be8d8537SStefan Hajnoczi char *iothread_get_id(IOThread *iothread) 133be8d8537SStefan Hajnoczi { 134be8d8537SStefan Hajnoczi return object_get_canonical_path_component(OBJECT(iothread)); 135be8d8537SStefan Hajnoczi } 136be8d8537SStefan Hajnoczi 137be8d8537SStefan Hajnoczi AioContext *iothread_get_aio_context(IOThread *iothread) 138be8d8537SStefan Hajnoczi { 139be8d8537SStefan Hajnoczi return iothread->ctx; 140be8d8537SStefan Hajnoczi } 141dc3dd0d2SStefan Hajnoczi 142dc3dd0d2SStefan Hajnoczi static int query_one_iothread(Object *object, void *opaque) 143dc3dd0d2SStefan Hajnoczi { 144dc3dd0d2SStefan Hajnoczi IOThreadInfoList ***prev = opaque; 145dc3dd0d2SStefan Hajnoczi IOThreadInfoList *elem; 146dc3dd0d2SStefan Hajnoczi IOThreadInfo *info; 147dc3dd0d2SStefan Hajnoczi IOThread *iothread; 148dc3dd0d2SStefan Hajnoczi 149dc3dd0d2SStefan Hajnoczi iothread = (IOThread *)object_dynamic_cast(object, TYPE_IOTHREAD); 150dc3dd0d2SStefan Hajnoczi if (!iothread) { 151dc3dd0d2SStefan Hajnoczi return 0; 152dc3dd0d2SStefan Hajnoczi } 153dc3dd0d2SStefan Hajnoczi 154dc3dd0d2SStefan Hajnoczi info = g_new0(IOThreadInfo, 1); 155dc3dd0d2SStefan Hajnoczi info->id = iothread_get_id(iothread); 156dc3dd0d2SStefan Hajnoczi info->thread_id = iothread->thread_id; 157dc3dd0d2SStefan Hajnoczi 158dc3dd0d2SStefan Hajnoczi elem = g_new0(IOThreadInfoList, 1); 159dc3dd0d2SStefan Hajnoczi elem->value = info; 160dc3dd0d2SStefan Hajnoczi elem->next = NULL; 161dc3dd0d2SStefan Hajnoczi 162dc3dd0d2SStefan Hajnoczi **prev = elem; 163dc3dd0d2SStefan Hajnoczi *prev = &elem->next; 164dc3dd0d2SStefan Hajnoczi return 0; 165dc3dd0d2SStefan Hajnoczi } 166dc3dd0d2SStefan Hajnoczi 167dc3dd0d2SStefan Hajnoczi IOThreadInfoList *qmp_query_iothreads(Error **errp) 168dc3dd0d2SStefan Hajnoczi { 169dc3dd0d2SStefan Hajnoczi IOThreadInfoList *head = NULL; 170dc3dd0d2SStefan Hajnoczi IOThreadInfoList **prev = &head; 171bc2256c4SDaniel P. Berrange Object *container = object_get_objects_root(); 172dc3dd0d2SStefan Hajnoczi 173dc3dd0d2SStefan Hajnoczi object_child_foreach(container, query_one_iothread, &prev); 174dc3dd0d2SStefan Hajnoczi return head; 175dc3dd0d2SStefan Hajnoczi } 176