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