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 14d38ea87aSPeter Maydell #include "qemu/osdep.h" 15be8d8537SStefan Hajnoczi #include "qom/object.h" 16be8d8537SStefan Hajnoczi #include "qom/object_interfaces.h" 17be8d8537SStefan Hajnoczi #include "qemu/module.h" 18be8d8537SStefan Hajnoczi #include "block/aio.h" 19*d16341faSPaolo Bonzini #include "block/block.h" 20be8d8537SStefan Hajnoczi #include "sysemu/iothread.h" 21dc3dd0d2SStefan Hajnoczi #include "qmp-commands.h" 222f78e491SChrysostomos Nanakos #include "qemu/error-report.h" 23ab28bd23SPaolo Bonzini #include "qemu/rcu.h" 24e4370165SPaolo Bonzini #include "qemu/main-loop.h" 25be8d8537SStefan Hajnoczi 26be8d8537SStefan Hajnoczi typedef ObjectClass IOThreadClass; 27be8d8537SStefan Hajnoczi 28be8d8537SStefan Hajnoczi #define IOTHREAD_GET_CLASS(obj) \ 29be8d8537SStefan Hajnoczi OBJECT_GET_CLASS(IOThreadClass, obj, TYPE_IOTHREAD) 30be8d8537SStefan Hajnoczi #define IOTHREAD_CLASS(klass) \ 31be8d8537SStefan Hajnoczi OBJECT_CLASS_CHECK(IOThreadClass, klass, TYPE_IOTHREAD) 32be8d8537SStefan Hajnoczi 33e4370165SPaolo Bonzini static __thread IOThread *my_iothread; 34e4370165SPaolo Bonzini 35e4370165SPaolo Bonzini AioContext *qemu_get_current_aio_context(void) 36e4370165SPaolo Bonzini { 37e4370165SPaolo Bonzini return my_iothread ? my_iothread->ctx : qemu_get_aio_context(); 38e4370165SPaolo Bonzini } 39e4370165SPaolo Bonzini 40be8d8537SStefan Hajnoczi static void *iothread_run(void *opaque) 41be8d8537SStefan Hajnoczi { 42be8d8537SStefan Hajnoczi IOThread *iothread = opaque; 43da5e1de9SStefan Hajnoczi bool blocking; 44be8d8537SStefan Hajnoczi 45ab28bd23SPaolo Bonzini rcu_register_thread(); 46ab28bd23SPaolo Bonzini 47e4370165SPaolo Bonzini my_iothread = iothread; 4888eb7c29SStefan Hajnoczi qemu_mutex_lock(&iothread->init_done_lock); 4988eb7c29SStefan Hajnoczi iothread->thread_id = qemu_get_thread_id(); 5088eb7c29SStefan Hajnoczi qemu_cond_signal(&iothread->init_done_cond); 5188eb7c29SStefan Hajnoczi qemu_mutex_unlock(&iothread->init_done_lock); 5288eb7c29SStefan Hajnoczi 53da5e1de9SStefan Hajnoczi while (!iothread->stopping) { 54da5e1de9SStefan Hajnoczi aio_context_acquire(iothread->ctx); 55da5e1de9SStefan Hajnoczi blocking = true; 56da5e1de9SStefan Hajnoczi while (!iothread->stopping && aio_poll(iothread->ctx, blocking)) { 57da5e1de9SStefan Hajnoczi /* Progress was made, keep going */ 58da5e1de9SStefan Hajnoczi blocking = false; 59da5e1de9SStefan Hajnoczi } 60da5e1de9SStefan Hajnoczi aio_context_release(iothread->ctx); 61be8d8537SStefan Hajnoczi } 62ab28bd23SPaolo Bonzini 63ab28bd23SPaolo Bonzini rcu_unregister_thread(); 64be8d8537SStefan Hajnoczi return NULL; 65be8d8537SStefan Hajnoczi } 66be8d8537SStefan Hajnoczi 67dce8921bSFam Zheng static int iothread_stop(Object *object, void *opaque) 68be8d8537SStefan Hajnoczi { 69dce8921bSFam Zheng IOThread *iothread; 70be8d8537SStefan Hajnoczi 71dce8921bSFam Zheng iothread = (IOThread *)object_dynamic_cast(object, TYPE_IOTHREAD); 72dce8921bSFam Zheng if (!iothread || !iothread->ctx) { 73dce8921bSFam Zheng return 0; 742f78e491SChrysostomos Nanakos } 75be8d8537SStefan Hajnoczi iothread->stopping = true; 76be8d8537SStefan Hajnoczi aio_notify(iothread->ctx); 77be8d8537SStefan Hajnoczi qemu_thread_join(&iothread->thread); 78dce8921bSFam Zheng return 0; 79dce8921bSFam Zheng } 80dce8921bSFam Zheng 81dce8921bSFam Zheng static void iothread_instance_finalize(Object *obj) 82dce8921bSFam Zheng { 83dce8921bSFam Zheng IOThread *iothread = IOTHREAD(obj); 84dce8921bSFam Zheng 85dce8921bSFam Zheng iothread_stop(obj, NULL); 8688eb7c29SStefan Hajnoczi qemu_cond_destroy(&iothread->init_done_cond); 8788eb7c29SStefan Hajnoczi qemu_mutex_destroy(&iothread->init_done_lock); 88eb7b5c35SLin Ma if (!iothread->ctx) { 89eb7b5c35SLin Ma return; 90eb7b5c35SLin Ma } 91be8d8537SStefan Hajnoczi aio_context_unref(iothread->ctx); 92be8d8537SStefan Hajnoczi } 93be8d8537SStefan Hajnoczi 94be8d8537SStefan Hajnoczi static void iothread_complete(UserCreatable *obj, Error **errp) 95be8d8537SStefan Hajnoczi { 962f78e491SChrysostomos Nanakos Error *local_error = NULL; 97be8d8537SStefan Hajnoczi IOThread *iothread = IOTHREAD(obj); 98d21e8776SPaolo Bonzini char *name, *thread_name; 99be8d8537SStefan Hajnoczi 100be8d8537SStefan Hajnoczi iothread->stopping = false; 10188eb7c29SStefan Hajnoczi iothread->thread_id = -1; 1022f78e491SChrysostomos Nanakos iothread->ctx = aio_context_new(&local_error); 1032f78e491SChrysostomos Nanakos if (!iothread->ctx) { 1042f78e491SChrysostomos Nanakos error_propagate(errp, local_error); 1052f78e491SChrysostomos Nanakos return; 1062f78e491SChrysostomos Nanakos } 10788eb7c29SStefan Hajnoczi 10888eb7c29SStefan Hajnoczi qemu_mutex_init(&iothread->init_done_lock); 10988eb7c29SStefan Hajnoczi qemu_cond_init(&iothread->init_done_cond); 110be8d8537SStefan Hajnoczi 111be8d8537SStefan Hajnoczi /* This assumes we are called from a thread with useful CPU affinity for us 112be8d8537SStefan Hajnoczi * to inherit. 113be8d8537SStefan Hajnoczi */ 114d21e8776SPaolo Bonzini name = object_get_canonical_path_component(OBJECT(obj)); 115d21e8776SPaolo Bonzini thread_name = g_strdup_printf("IO %s", name); 116d21e8776SPaolo Bonzini qemu_thread_create(&iothread->thread, thread_name, iothread_run, 117be8d8537SStefan Hajnoczi iothread, QEMU_THREAD_JOINABLE); 118d21e8776SPaolo Bonzini g_free(thread_name); 119d21e8776SPaolo Bonzini g_free(name); 12088eb7c29SStefan Hajnoczi 12188eb7c29SStefan Hajnoczi /* Wait for initialization to complete */ 12288eb7c29SStefan Hajnoczi qemu_mutex_lock(&iothread->init_done_lock); 12388eb7c29SStefan Hajnoczi while (iothread->thread_id == -1) { 12488eb7c29SStefan Hajnoczi qemu_cond_wait(&iothread->init_done_cond, 12588eb7c29SStefan Hajnoczi &iothread->init_done_lock); 12688eb7c29SStefan Hajnoczi } 12788eb7c29SStefan Hajnoczi qemu_mutex_unlock(&iothread->init_done_lock); 128be8d8537SStefan Hajnoczi } 129be8d8537SStefan Hajnoczi 130be8d8537SStefan Hajnoczi static void iothread_class_init(ObjectClass *klass, void *class_data) 131be8d8537SStefan Hajnoczi { 132be8d8537SStefan Hajnoczi UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass); 133be8d8537SStefan Hajnoczi ucc->complete = iothread_complete; 134be8d8537SStefan Hajnoczi } 135be8d8537SStefan Hajnoczi 136be8d8537SStefan Hajnoczi static const TypeInfo iothread_info = { 137be8d8537SStefan Hajnoczi .name = TYPE_IOTHREAD, 138be8d8537SStefan Hajnoczi .parent = TYPE_OBJECT, 139be8d8537SStefan Hajnoczi .class_init = iothread_class_init, 140be8d8537SStefan Hajnoczi .instance_size = sizeof(IOThread), 141be8d8537SStefan Hajnoczi .instance_finalize = iothread_instance_finalize, 142be8d8537SStefan Hajnoczi .interfaces = (InterfaceInfo[]) { 143be8d8537SStefan Hajnoczi {TYPE_USER_CREATABLE}, 144be8d8537SStefan Hajnoczi {} 145be8d8537SStefan Hajnoczi }, 146be8d8537SStefan Hajnoczi }; 147be8d8537SStefan Hajnoczi 148be8d8537SStefan Hajnoczi static void iothread_register_types(void) 149be8d8537SStefan Hajnoczi { 150be8d8537SStefan Hajnoczi type_register_static(&iothread_info); 151be8d8537SStefan Hajnoczi } 152be8d8537SStefan Hajnoczi 153be8d8537SStefan Hajnoczi type_init(iothread_register_types) 154be8d8537SStefan Hajnoczi 155be8d8537SStefan Hajnoczi char *iothread_get_id(IOThread *iothread) 156be8d8537SStefan Hajnoczi { 157be8d8537SStefan Hajnoczi return object_get_canonical_path_component(OBJECT(iothread)); 158be8d8537SStefan Hajnoczi } 159be8d8537SStefan Hajnoczi 160be8d8537SStefan Hajnoczi AioContext *iothread_get_aio_context(IOThread *iothread) 161be8d8537SStefan Hajnoczi { 162be8d8537SStefan Hajnoczi return iothread->ctx; 163be8d8537SStefan Hajnoczi } 164dc3dd0d2SStefan Hajnoczi 165dc3dd0d2SStefan Hajnoczi static int query_one_iothread(Object *object, void *opaque) 166dc3dd0d2SStefan Hajnoczi { 167dc3dd0d2SStefan Hajnoczi IOThreadInfoList ***prev = opaque; 168dc3dd0d2SStefan Hajnoczi IOThreadInfoList *elem; 169dc3dd0d2SStefan Hajnoczi IOThreadInfo *info; 170dc3dd0d2SStefan Hajnoczi IOThread *iothread; 171dc3dd0d2SStefan Hajnoczi 172dc3dd0d2SStefan Hajnoczi iothread = (IOThread *)object_dynamic_cast(object, TYPE_IOTHREAD); 173dc3dd0d2SStefan Hajnoczi if (!iothread) { 174dc3dd0d2SStefan Hajnoczi return 0; 175dc3dd0d2SStefan Hajnoczi } 176dc3dd0d2SStefan Hajnoczi 177dc3dd0d2SStefan Hajnoczi info = g_new0(IOThreadInfo, 1); 178dc3dd0d2SStefan Hajnoczi info->id = iothread_get_id(iothread); 179dc3dd0d2SStefan Hajnoczi info->thread_id = iothread->thread_id; 180dc3dd0d2SStefan Hajnoczi 181dc3dd0d2SStefan Hajnoczi elem = g_new0(IOThreadInfoList, 1); 182dc3dd0d2SStefan Hajnoczi elem->value = info; 183dc3dd0d2SStefan Hajnoczi elem->next = NULL; 184dc3dd0d2SStefan Hajnoczi 185dc3dd0d2SStefan Hajnoczi **prev = elem; 186dc3dd0d2SStefan Hajnoczi *prev = &elem->next; 187dc3dd0d2SStefan Hajnoczi return 0; 188dc3dd0d2SStefan Hajnoczi } 189dc3dd0d2SStefan Hajnoczi 190dc3dd0d2SStefan Hajnoczi IOThreadInfoList *qmp_query_iothreads(Error **errp) 191dc3dd0d2SStefan Hajnoczi { 192dc3dd0d2SStefan Hajnoczi IOThreadInfoList *head = NULL; 193dc3dd0d2SStefan Hajnoczi IOThreadInfoList **prev = &head; 194bc2256c4SDaniel P. Berrange Object *container = object_get_objects_root(); 195dc3dd0d2SStefan Hajnoczi 196dc3dd0d2SStefan Hajnoczi object_child_foreach(container, query_one_iothread, &prev); 197dc3dd0d2SStefan Hajnoczi return head; 198dc3dd0d2SStefan Hajnoczi } 199dce8921bSFam Zheng 200dce8921bSFam Zheng void iothread_stop_all(void) 201dce8921bSFam Zheng { 202dce8921bSFam Zheng Object *container = object_get_objects_root(); 203*d16341faSPaolo Bonzini BlockDriverState *bs; 204*d16341faSPaolo Bonzini BdrvNextIterator it; 205*d16341faSPaolo Bonzini 206*d16341faSPaolo Bonzini for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { 207*d16341faSPaolo Bonzini AioContext *ctx = bdrv_get_aio_context(bs); 208*d16341faSPaolo Bonzini if (ctx == qemu_get_aio_context()) { 209*d16341faSPaolo Bonzini continue; 210*d16341faSPaolo Bonzini } 211*d16341faSPaolo Bonzini aio_context_acquire(ctx); 212*d16341faSPaolo Bonzini bdrv_set_aio_context(bs, qemu_get_aio_context()); 213*d16341faSPaolo Bonzini aio_context_release(ctx); 214*d16341faSPaolo Bonzini } 215dce8921bSFam Zheng 216dce8921bSFam Zheng object_child_foreach(container, iothread_stop, NULL); 217dce8921bSFam Zheng } 218