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 "qemu/thread.h" 18be8d8537SStefan Hajnoczi #include "block/aio.h" 19be8d8537SStefan Hajnoczi #include "sysemu/iothread.h" 20be8d8537SStefan Hajnoczi 21be8d8537SStefan Hajnoczi #define IOTHREADS_PATH "/objects" 22be8d8537SStefan Hajnoczi 23be8d8537SStefan Hajnoczi typedef ObjectClass IOThreadClass; 24be8d8537SStefan Hajnoczi struct IOThread { 25be8d8537SStefan Hajnoczi Object parent_obj; 26be8d8537SStefan Hajnoczi 27be8d8537SStefan Hajnoczi QemuThread thread; 28be8d8537SStefan Hajnoczi AioContext *ctx; 29*88eb7c29SStefan Hajnoczi QemuMutex init_done_lock; 30*88eb7c29SStefan Hajnoczi QemuCond init_done_cond; /* is thread initialization done? */ 31be8d8537SStefan Hajnoczi bool stopping; 32*88eb7c29SStefan Hajnoczi int thread_id; 33be8d8537SStefan Hajnoczi }; 34be8d8537SStefan Hajnoczi 35be8d8537SStefan Hajnoczi #define IOTHREAD_GET_CLASS(obj) \ 36be8d8537SStefan Hajnoczi OBJECT_GET_CLASS(IOThreadClass, obj, TYPE_IOTHREAD) 37be8d8537SStefan Hajnoczi #define IOTHREAD_CLASS(klass) \ 38be8d8537SStefan Hajnoczi OBJECT_CLASS_CHECK(IOThreadClass, klass, TYPE_IOTHREAD) 39be8d8537SStefan Hajnoczi 40be8d8537SStefan Hajnoczi static void *iothread_run(void *opaque) 41be8d8537SStefan Hajnoczi { 42be8d8537SStefan Hajnoczi IOThread *iothread = opaque; 43be8d8537SStefan Hajnoczi 44*88eb7c29SStefan Hajnoczi qemu_mutex_lock(&iothread->init_done_lock); 45*88eb7c29SStefan Hajnoczi iothread->thread_id = qemu_get_thread_id(); 46*88eb7c29SStefan Hajnoczi qemu_cond_signal(&iothread->init_done_cond); 47*88eb7c29SStefan Hajnoczi qemu_mutex_unlock(&iothread->init_done_lock); 48*88eb7c29SStefan Hajnoczi 49be8d8537SStefan Hajnoczi while (!iothread->stopping) { 50be8d8537SStefan Hajnoczi aio_context_acquire(iothread->ctx); 51be8d8537SStefan Hajnoczi while (!iothread->stopping && aio_poll(iothread->ctx, true)) { 52be8d8537SStefan Hajnoczi /* Progress was made, keep going */ 53be8d8537SStefan Hajnoczi } 54be8d8537SStefan Hajnoczi aio_context_release(iothread->ctx); 55be8d8537SStefan Hajnoczi } 56be8d8537SStefan Hajnoczi return NULL; 57be8d8537SStefan Hajnoczi } 58be8d8537SStefan Hajnoczi 59be8d8537SStefan Hajnoczi static void iothread_instance_finalize(Object *obj) 60be8d8537SStefan Hajnoczi { 61be8d8537SStefan Hajnoczi IOThread *iothread = IOTHREAD(obj); 62be8d8537SStefan Hajnoczi 63be8d8537SStefan Hajnoczi iothread->stopping = true; 64be8d8537SStefan Hajnoczi aio_notify(iothread->ctx); 65be8d8537SStefan Hajnoczi qemu_thread_join(&iothread->thread); 66*88eb7c29SStefan Hajnoczi qemu_cond_destroy(&iothread->init_done_cond); 67*88eb7c29SStefan 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 { 73be8d8537SStefan Hajnoczi IOThread *iothread = IOTHREAD(obj); 74be8d8537SStefan Hajnoczi 75be8d8537SStefan Hajnoczi iothread->stopping = false; 76be8d8537SStefan Hajnoczi iothread->ctx = aio_context_new(); 77*88eb7c29SStefan Hajnoczi iothread->thread_id = -1; 78*88eb7c29SStefan Hajnoczi 79*88eb7c29SStefan Hajnoczi qemu_mutex_init(&iothread->init_done_lock); 80*88eb7c29SStefan Hajnoczi qemu_cond_init(&iothread->init_done_cond); 81be8d8537SStefan Hajnoczi 82be8d8537SStefan Hajnoczi /* This assumes we are called from a thread with useful CPU affinity for us 83be8d8537SStefan Hajnoczi * to inherit. 84be8d8537SStefan Hajnoczi */ 85be8d8537SStefan Hajnoczi qemu_thread_create(&iothread->thread, "iothread", iothread_run, 86be8d8537SStefan Hajnoczi iothread, QEMU_THREAD_JOINABLE); 87*88eb7c29SStefan Hajnoczi 88*88eb7c29SStefan Hajnoczi /* Wait for initialization to complete */ 89*88eb7c29SStefan Hajnoczi qemu_mutex_lock(&iothread->init_done_lock); 90*88eb7c29SStefan Hajnoczi while (iothread->thread_id == -1) { 91*88eb7c29SStefan Hajnoczi qemu_cond_wait(&iothread->init_done_cond, 92*88eb7c29SStefan Hajnoczi &iothread->init_done_lock); 93*88eb7c29SStefan Hajnoczi } 94*88eb7c29SStefan Hajnoczi qemu_mutex_unlock(&iothread->init_done_lock); 95be8d8537SStefan Hajnoczi } 96be8d8537SStefan Hajnoczi 97be8d8537SStefan Hajnoczi static void iothread_class_init(ObjectClass *klass, void *class_data) 98be8d8537SStefan Hajnoczi { 99be8d8537SStefan Hajnoczi UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass); 100be8d8537SStefan Hajnoczi ucc->complete = iothread_complete; 101be8d8537SStefan Hajnoczi } 102be8d8537SStefan Hajnoczi 103be8d8537SStefan Hajnoczi static const TypeInfo iothread_info = { 104be8d8537SStefan Hajnoczi .name = TYPE_IOTHREAD, 105be8d8537SStefan Hajnoczi .parent = TYPE_OBJECT, 106be8d8537SStefan Hajnoczi .class_init = iothread_class_init, 107be8d8537SStefan Hajnoczi .instance_size = sizeof(IOThread), 108be8d8537SStefan Hajnoczi .instance_finalize = iothread_instance_finalize, 109be8d8537SStefan Hajnoczi .interfaces = (InterfaceInfo[]) { 110be8d8537SStefan Hajnoczi {TYPE_USER_CREATABLE}, 111be8d8537SStefan Hajnoczi {} 112be8d8537SStefan Hajnoczi }, 113be8d8537SStefan Hajnoczi }; 114be8d8537SStefan Hajnoczi 115be8d8537SStefan Hajnoczi static void iothread_register_types(void) 116be8d8537SStefan Hajnoczi { 117be8d8537SStefan Hajnoczi type_register_static(&iothread_info); 118be8d8537SStefan Hajnoczi } 119be8d8537SStefan Hajnoczi 120be8d8537SStefan Hajnoczi type_init(iothread_register_types) 121be8d8537SStefan Hajnoczi 122be8d8537SStefan Hajnoczi IOThread *iothread_find(const char *id) 123be8d8537SStefan Hajnoczi { 124be8d8537SStefan Hajnoczi Object *container = container_get(object_get_root(), IOTHREADS_PATH); 125be8d8537SStefan Hajnoczi Object *child; 126be8d8537SStefan Hajnoczi 127be8d8537SStefan Hajnoczi child = object_property_get_link(container, id, NULL); 128be8d8537SStefan Hajnoczi if (!child) { 129be8d8537SStefan Hajnoczi return NULL; 130be8d8537SStefan Hajnoczi } 131be8d8537SStefan Hajnoczi return (IOThread *)object_dynamic_cast(child, TYPE_IOTHREAD); 132be8d8537SStefan Hajnoczi } 133be8d8537SStefan Hajnoczi 134be8d8537SStefan Hajnoczi char *iothread_get_id(IOThread *iothread) 135be8d8537SStefan Hajnoczi { 136be8d8537SStefan Hajnoczi return object_get_canonical_path_component(OBJECT(iothread)); 137be8d8537SStefan Hajnoczi } 138be8d8537SStefan Hajnoczi 139be8d8537SStefan Hajnoczi AioContext *iothread_get_aio_context(IOThread *iothread) 140be8d8537SStefan Hajnoczi { 141be8d8537SStefan Hajnoczi return iothread->ctx; 142be8d8537SStefan Hajnoczi } 143