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" 19d16341faSPaolo 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; 43be8d8537SStefan Hajnoczi 44ab28bd23SPaolo Bonzini rcu_register_thread(); 45ab28bd23SPaolo Bonzini 46e4370165SPaolo Bonzini my_iothread = iothread; 4788eb7c29SStefan Hajnoczi qemu_mutex_lock(&iothread->init_done_lock); 4888eb7c29SStefan Hajnoczi iothread->thread_id = qemu_get_thread_id(); 4988eb7c29SStefan Hajnoczi qemu_cond_signal(&iothread->init_done_cond); 5088eb7c29SStefan Hajnoczi qemu_mutex_unlock(&iothread->init_done_lock); 5188eb7c29SStefan Hajnoczi 5265c1b5b6SPaolo Bonzini while (!atomic_read(&iothread->stopping)) { 5365c1b5b6SPaolo Bonzini aio_poll(iothread->ctx, true); 54be8d8537SStefan Hajnoczi } 55ab28bd23SPaolo Bonzini 56ab28bd23SPaolo Bonzini rcu_unregister_thread(); 57be8d8537SStefan Hajnoczi return NULL; 58be8d8537SStefan Hajnoczi } 59be8d8537SStefan Hajnoczi 60dce8921bSFam Zheng static int iothread_stop(Object *object, void *opaque) 61be8d8537SStefan Hajnoczi { 62dce8921bSFam Zheng IOThread *iothread; 63be8d8537SStefan Hajnoczi 64dce8921bSFam Zheng iothread = (IOThread *)object_dynamic_cast(object, TYPE_IOTHREAD); 65dce8921bSFam Zheng if (!iothread || !iothread->ctx) { 66dce8921bSFam Zheng return 0; 672f78e491SChrysostomos Nanakos } 68be8d8537SStefan Hajnoczi iothread->stopping = true; 69be8d8537SStefan Hajnoczi aio_notify(iothread->ctx); 70be8d8537SStefan Hajnoczi qemu_thread_join(&iothread->thread); 71dce8921bSFam Zheng return 0; 72dce8921bSFam Zheng } 73dce8921bSFam Zheng 74dce8921bSFam Zheng static void iothread_instance_finalize(Object *obj) 75dce8921bSFam Zheng { 76dce8921bSFam Zheng IOThread *iothread = IOTHREAD(obj); 77dce8921bSFam Zheng 78dce8921bSFam Zheng iothread_stop(obj, NULL); 7988eb7c29SStefan Hajnoczi qemu_cond_destroy(&iothread->init_done_cond); 8088eb7c29SStefan Hajnoczi qemu_mutex_destroy(&iothread->init_done_lock); 81eb7b5c35SLin Ma if (!iothread->ctx) { 82eb7b5c35SLin Ma return; 83eb7b5c35SLin Ma } 84be8d8537SStefan Hajnoczi aio_context_unref(iothread->ctx); 85be8d8537SStefan Hajnoczi } 86be8d8537SStefan Hajnoczi 87be8d8537SStefan Hajnoczi static void iothread_complete(UserCreatable *obj, Error **errp) 88be8d8537SStefan Hajnoczi { 892f78e491SChrysostomos Nanakos Error *local_error = NULL; 90be8d8537SStefan Hajnoczi IOThread *iothread = IOTHREAD(obj); 91d21e8776SPaolo Bonzini char *name, *thread_name; 92be8d8537SStefan Hajnoczi 93be8d8537SStefan Hajnoczi iothread->stopping = false; 9488eb7c29SStefan Hajnoczi iothread->thread_id = -1; 952f78e491SChrysostomos Nanakos iothread->ctx = aio_context_new(&local_error); 962f78e491SChrysostomos Nanakos if (!iothread->ctx) { 972f78e491SChrysostomos Nanakos error_propagate(errp, local_error); 982f78e491SChrysostomos Nanakos return; 992f78e491SChrysostomos Nanakos } 10088eb7c29SStefan Hajnoczi 101*5e5db499SStefan Hajnoczi aio_context_set_poll_params(iothread->ctx, 102*5e5db499SStefan Hajnoczi iothread->poll_max_ns, 103*5e5db499SStefan Hajnoczi iothread->poll_grow, 104*5e5db499SStefan Hajnoczi iothread->poll_shrink, 1050d9d86fbSStefan Hajnoczi &local_error); 1060d9d86fbSStefan Hajnoczi if (local_error) { 1070d9d86fbSStefan Hajnoczi error_propagate(errp, local_error); 1080d9d86fbSStefan Hajnoczi aio_context_unref(iothread->ctx); 1090d9d86fbSStefan Hajnoczi iothread->ctx = NULL; 1100d9d86fbSStefan Hajnoczi return; 1110d9d86fbSStefan Hajnoczi } 1120d9d86fbSStefan Hajnoczi 11388eb7c29SStefan Hajnoczi qemu_mutex_init(&iothread->init_done_lock); 11488eb7c29SStefan Hajnoczi qemu_cond_init(&iothread->init_done_cond); 115be8d8537SStefan Hajnoczi 116be8d8537SStefan Hajnoczi /* This assumes we are called from a thread with useful CPU affinity for us 117be8d8537SStefan Hajnoczi * to inherit. 118be8d8537SStefan Hajnoczi */ 119d21e8776SPaolo Bonzini name = object_get_canonical_path_component(OBJECT(obj)); 120d21e8776SPaolo Bonzini thread_name = g_strdup_printf("IO %s", name); 121d21e8776SPaolo Bonzini qemu_thread_create(&iothread->thread, thread_name, iothread_run, 122be8d8537SStefan Hajnoczi iothread, QEMU_THREAD_JOINABLE); 123d21e8776SPaolo Bonzini g_free(thread_name); 124d21e8776SPaolo Bonzini g_free(name); 12588eb7c29SStefan Hajnoczi 12688eb7c29SStefan Hajnoczi /* Wait for initialization to complete */ 12788eb7c29SStefan Hajnoczi qemu_mutex_lock(&iothread->init_done_lock); 12888eb7c29SStefan Hajnoczi while (iothread->thread_id == -1) { 12988eb7c29SStefan Hajnoczi qemu_cond_wait(&iothread->init_done_cond, 13088eb7c29SStefan Hajnoczi &iothread->init_done_lock); 13188eb7c29SStefan Hajnoczi } 13288eb7c29SStefan Hajnoczi qemu_mutex_unlock(&iothread->init_done_lock); 133be8d8537SStefan Hajnoczi } 134be8d8537SStefan Hajnoczi 135*5e5db499SStefan Hajnoczi typedef struct { 136*5e5db499SStefan Hajnoczi const char *name; 137*5e5db499SStefan Hajnoczi ptrdiff_t offset; /* field's byte offset in IOThread struct */ 138*5e5db499SStefan Hajnoczi } PollParamInfo; 139*5e5db499SStefan Hajnoczi 140*5e5db499SStefan Hajnoczi static PollParamInfo poll_max_ns_info = { 141*5e5db499SStefan Hajnoczi "poll-max-ns", offsetof(IOThread, poll_max_ns), 142*5e5db499SStefan Hajnoczi }; 143*5e5db499SStefan Hajnoczi static PollParamInfo poll_grow_info = { 144*5e5db499SStefan Hajnoczi "poll-grow", offsetof(IOThread, poll_grow), 145*5e5db499SStefan Hajnoczi }; 146*5e5db499SStefan Hajnoczi static PollParamInfo poll_shrink_info = { 147*5e5db499SStefan Hajnoczi "poll-shrink", offsetof(IOThread, poll_shrink), 148*5e5db499SStefan Hajnoczi }; 149*5e5db499SStefan Hajnoczi 150*5e5db499SStefan Hajnoczi static void iothread_get_poll_param(Object *obj, Visitor *v, 1510d9d86fbSStefan Hajnoczi const char *name, void *opaque, Error **errp) 1520d9d86fbSStefan Hajnoczi { 1530d9d86fbSStefan Hajnoczi IOThread *iothread = IOTHREAD(obj); 154*5e5db499SStefan Hajnoczi PollParamInfo *info = opaque; 155*5e5db499SStefan Hajnoczi int64_t *field = (void *)iothread + info->offset; 1560d9d86fbSStefan Hajnoczi 157*5e5db499SStefan Hajnoczi visit_type_int64(v, name, field, errp); 1580d9d86fbSStefan Hajnoczi } 1590d9d86fbSStefan Hajnoczi 160*5e5db499SStefan Hajnoczi static void iothread_set_poll_param(Object *obj, Visitor *v, 1610d9d86fbSStefan Hajnoczi const char *name, void *opaque, Error **errp) 1620d9d86fbSStefan Hajnoczi { 1630d9d86fbSStefan Hajnoczi IOThread *iothread = IOTHREAD(obj); 164*5e5db499SStefan Hajnoczi PollParamInfo *info = opaque; 165*5e5db499SStefan Hajnoczi int64_t *field = (void *)iothread + info->offset; 1660d9d86fbSStefan Hajnoczi Error *local_err = NULL; 1670d9d86fbSStefan Hajnoczi int64_t value; 1680d9d86fbSStefan Hajnoczi 1690d9d86fbSStefan Hajnoczi visit_type_int64(v, name, &value, &local_err); 1700d9d86fbSStefan Hajnoczi if (local_err) { 1710d9d86fbSStefan Hajnoczi goto out; 1720d9d86fbSStefan Hajnoczi } 1730d9d86fbSStefan Hajnoczi 1740d9d86fbSStefan Hajnoczi if (value < 0) { 175*5e5db499SStefan Hajnoczi error_setg(&local_err, "%s value must be in range [0, %"PRId64"]", 176*5e5db499SStefan Hajnoczi info->name, INT64_MAX); 1770d9d86fbSStefan Hajnoczi goto out; 1780d9d86fbSStefan Hajnoczi } 1790d9d86fbSStefan Hajnoczi 180*5e5db499SStefan Hajnoczi *field = value; 1810d9d86fbSStefan Hajnoczi 1820d9d86fbSStefan Hajnoczi if (iothread->ctx) { 183*5e5db499SStefan Hajnoczi aio_context_set_poll_params(iothread->ctx, 184*5e5db499SStefan Hajnoczi iothread->poll_max_ns, 185*5e5db499SStefan Hajnoczi iothread->poll_grow, 186*5e5db499SStefan Hajnoczi iothread->poll_shrink, 187*5e5db499SStefan Hajnoczi &local_err); 1880d9d86fbSStefan Hajnoczi } 1890d9d86fbSStefan Hajnoczi 1900d9d86fbSStefan Hajnoczi out: 1910d9d86fbSStefan Hajnoczi error_propagate(errp, local_err); 1920d9d86fbSStefan Hajnoczi } 1930d9d86fbSStefan Hajnoczi 194be8d8537SStefan Hajnoczi static void iothread_class_init(ObjectClass *klass, void *class_data) 195be8d8537SStefan Hajnoczi { 196be8d8537SStefan Hajnoczi UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass); 197be8d8537SStefan Hajnoczi ucc->complete = iothread_complete; 1980d9d86fbSStefan Hajnoczi 1990d9d86fbSStefan Hajnoczi object_class_property_add(klass, "poll-max-ns", "int", 200*5e5db499SStefan Hajnoczi iothread_get_poll_param, 201*5e5db499SStefan Hajnoczi iothread_set_poll_param, 202*5e5db499SStefan Hajnoczi NULL, &poll_max_ns_info, &error_abort); 203*5e5db499SStefan Hajnoczi object_class_property_add(klass, "poll-grow", "int", 204*5e5db499SStefan Hajnoczi iothread_get_poll_param, 205*5e5db499SStefan Hajnoczi iothread_set_poll_param, 206*5e5db499SStefan Hajnoczi NULL, &poll_grow_info, &error_abort); 207*5e5db499SStefan Hajnoczi object_class_property_add(klass, "poll-shrink", "int", 208*5e5db499SStefan Hajnoczi iothread_get_poll_param, 209*5e5db499SStefan Hajnoczi iothread_set_poll_param, 210*5e5db499SStefan Hajnoczi NULL, &poll_shrink_info, &error_abort); 211be8d8537SStefan Hajnoczi } 212be8d8537SStefan Hajnoczi 213be8d8537SStefan Hajnoczi static const TypeInfo iothread_info = { 214be8d8537SStefan Hajnoczi .name = TYPE_IOTHREAD, 215be8d8537SStefan Hajnoczi .parent = TYPE_OBJECT, 216be8d8537SStefan Hajnoczi .class_init = iothread_class_init, 217be8d8537SStefan Hajnoczi .instance_size = sizeof(IOThread), 218be8d8537SStefan Hajnoczi .instance_finalize = iothread_instance_finalize, 219be8d8537SStefan Hajnoczi .interfaces = (InterfaceInfo[]) { 220be8d8537SStefan Hajnoczi {TYPE_USER_CREATABLE}, 221be8d8537SStefan Hajnoczi {} 222be8d8537SStefan Hajnoczi }, 223be8d8537SStefan Hajnoczi }; 224be8d8537SStefan Hajnoczi 225be8d8537SStefan Hajnoczi static void iothread_register_types(void) 226be8d8537SStefan Hajnoczi { 227be8d8537SStefan Hajnoczi type_register_static(&iothread_info); 228be8d8537SStefan Hajnoczi } 229be8d8537SStefan Hajnoczi 230be8d8537SStefan Hajnoczi type_init(iothread_register_types) 231be8d8537SStefan Hajnoczi 232be8d8537SStefan Hajnoczi char *iothread_get_id(IOThread *iothread) 233be8d8537SStefan Hajnoczi { 234be8d8537SStefan Hajnoczi return object_get_canonical_path_component(OBJECT(iothread)); 235be8d8537SStefan Hajnoczi } 236be8d8537SStefan Hajnoczi 237be8d8537SStefan Hajnoczi AioContext *iothread_get_aio_context(IOThread *iothread) 238be8d8537SStefan Hajnoczi { 239be8d8537SStefan Hajnoczi return iothread->ctx; 240be8d8537SStefan Hajnoczi } 241dc3dd0d2SStefan Hajnoczi 242dc3dd0d2SStefan Hajnoczi static int query_one_iothread(Object *object, void *opaque) 243dc3dd0d2SStefan Hajnoczi { 244dc3dd0d2SStefan Hajnoczi IOThreadInfoList ***prev = opaque; 245dc3dd0d2SStefan Hajnoczi IOThreadInfoList *elem; 246dc3dd0d2SStefan Hajnoczi IOThreadInfo *info; 247dc3dd0d2SStefan Hajnoczi IOThread *iothread; 248dc3dd0d2SStefan Hajnoczi 249dc3dd0d2SStefan Hajnoczi iothread = (IOThread *)object_dynamic_cast(object, TYPE_IOTHREAD); 250dc3dd0d2SStefan Hajnoczi if (!iothread) { 251dc3dd0d2SStefan Hajnoczi return 0; 252dc3dd0d2SStefan Hajnoczi } 253dc3dd0d2SStefan Hajnoczi 254dc3dd0d2SStefan Hajnoczi info = g_new0(IOThreadInfo, 1); 255dc3dd0d2SStefan Hajnoczi info->id = iothread_get_id(iothread); 256dc3dd0d2SStefan Hajnoczi info->thread_id = iothread->thread_id; 257dc3dd0d2SStefan Hajnoczi 258dc3dd0d2SStefan Hajnoczi elem = g_new0(IOThreadInfoList, 1); 259dc3dd0d2SStefan Hajnoczi elem->value = info; 260dc3dd0d2SStefan Hajnoczi elem->next = NULL; 261dc3dd0d2SStefan Hajnoczi 262dc3dd0d2SStefan Hajnoczi **prev = elem; 263dc3dd0d2SStefan Hajnoczi *prev = &elem->next; 264dc3dd0d2SStefan Hajnoczi return 0; 265dc3dd0d2SStefan Hajnoczi } 266dc3dd0d2SStefan Hajnoczi 267dc3dd0d2SStefan Hajnoczi IOThreadInfoList *qmp_query_iothreads(Error **errp) 268dc3dd0d2SStefan Hajnoczi { 269dc3dd0d2SStefan Hajnoczi IOThreadInfoList *head = NULL; 270dc3dd0d2SStefan Hajnoczi IOThreadInfoList **prev = &head; 271bc2256c4SDaniel P. Berrange Object *container = object_get_objects_root(); 272dc3dd0d2SStefan Hajnoczi 273dc3dd0d2SStefan Hajnoczi object_child_foreach(container, query_one_iothread, &prev); 274dc3dd0d2SStefan Hajnoczi return head; 275dc3dd0d2SStefan Hajnoczi } 276dce8921bSFam Zheng 277dce8921bSFam Zheng void iothread_stop_all(void) 278dce8921bSFam Zheng { 279dce8921bSFam Zheng Object *container = object_get_objects_root(); 280d16341faSPaolo Bonzini BlockDriverState *bs; 281d16341faSPaolo Bonzini BdrvNextIterator it; 282d16341faSPaolo Bonzini 283d16341faSPaolo Bonzini for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { 284d16341faSPaolo Bonzini AioContext *ctx = bdrv_get_aio_context(bs); 285d16341faSPaolo Bonzini if (ctx == qemu_get_aio_context()) { 286d16341faSPaolo Bonzini continue; 287d16341faSPaolo Bonzini } 288d16341faSPaolo Bonzini aio_context_acquire(ctx); 289d16341faSPaolo Bonzini bdrv_set_aio_context(bs, qemu_get_aio_context()); 290d16341faSPaolo Bonzini aio_context_release(ctx); 291d16341faSPaolo Bonzini } 292dce8921bSFam Zheng 293dce8921bSFam Zheng object_child_foreach(container, iothread_stop, NULL); 294dce8921bSFam Zheng } 295