xref: /openbmc/qemu/io/task.c (revision 9a2ea4f4a7230fe224dee91d9adf2ef872c3d226)
1b02db2d9SDaniel P. Berrange /*
2b02db2d9SDaniel P. Berrange  * QEMU I/O task
3b02db2d9SDaniel P. Berrange  *
4b02db2d9SDaniel P. Berrange  * Copyright (c) 2015 Red Hat, Inc.
5b02db2d9SDaniel P. Berrange  *
6b02db2d9SDaniel P. Berrange  * This library is free software; you can redistribute it and/or
7b02db2d9SDaniel P. Berrange  * modify it under the terms of the GNU Lesser General Public
8b02db2d9SDaniel P. Berrange  * License as published by the Free Software Foundation; either
9*c8198bd5SChetan Pant  * version 2.1 of the License, or (at your option) any later version.
10b02db2d9SDaniel P. Berrange  *
11b02db2d9SDaniel P. Berrange  * This library is distributed in the hope that it will be useful,
12b02db2d9SDaniel P. Berrange  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13b02db2d9SDaniel P. Berrange  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14b02db2d9SDaniel P. Berrange  * Lesser General Public License for more details.
15b02db2d9SDaniel P. Berrange  *
16b02db2d9SDaniel P. Berrange  * You should have received a copy of the GNU Lesser General Public
17b02db2d9SDaniel P. Berrange  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18b02db2d9SDaniel P. Berrange  *
19b02db2d9SDaniel P. Berrange  */
20b02db2d9SDaniel P. Berrange 
21cae9fc56SPeter Maydell #include "qemu/osdep.h"
22b02db2d9SDaniel P. Berrange #include "io/task.h"
23da34e65cSMarkus Armbruster #include "qapi/error.h"
24b02db2d9SDaniel P. Berrange #include "qemu/thread.h"
2578f8d497SPhilippe Mathieu-Daudé #include "qom/object.h"
26b02db2d9SDaniel P. Berrange #include "trace.h"
27b02db2d9SDaniel P. Berrange 
2852d6cfecSDaniel P. Berrangé struct QIOTaskThreadData {
2952d6cfecSDaniel P. Berrangé     QIOTaskWorker worker;
3052d6cfecSDaniel P. Berrangé     gpointer opaque;
3152d6cfecSDaniel P. Berrangé     GDestroyNotify destroy;
3252d6cfecSDaniel P. Berrangé     GMainContext *context;
33dbb44504SDaniel P. Berrangé     GSource *completion;
3452d6cfecSDaniel P. Berrangé };
3552d6cfecSDaniel P. Berrangé 
3652d6cfecSDaniel P. Berrangé 
37b02db2d9SDaniel P. Berrange struct QIOTask {
38b02db2d9SDaniel P. Berrange     Object *source;
39b02db2d9SDaniel P. Berrange     QIOTaskFunc func;
40b02db2d9SDaniel P. Berrange     gpointer opaque;
41b02db2d9SDaniel P. Berrange     GDestroyNotify destroy;
421a447e4fSDaniel P. Berrange     Error *err;
4352dd99e8SDaniel P. Berrange     gpointer result;
4452dd99e8SDaniel P. Berrange     GDestroyNotify destroyResult;
45dbb44504SDaniel P. Berrangé     QemuMutex thread_lock;
46dbb44504SDaniel P. Berrangé     QemuCond thread_cond;
4752d6cfecSDaniel P. Berrangé     struct QIOTaskThreadData *thread;
48b02db2d9SDaniel P. Berrange };
49b02db2d9SDaniel P. Berrange 
50b02db2d9SDaniel P. Berrange 
qio_task_new(Object * source,QIOTaskFunc func,gpointer opaque,GDestroyNotify destroy)51b02db2d9SDaniel P. Berrange QIOTask *qio_task_new(Object *source,
52b02db2d9SDaniel P. Berrange                       QIOTaskFunc func,
53b02db2d9SDaniel P. Berrange                       gpointer opaque,
54b02db2d9SDaniel P. Berrange                       GDestroyNotify destroy)
55b02db2d9SDaniel P. Berrange {
56b02db2d9SDaniel P. Berrange     QIOTask *task;
57b02db2d9SDaniel P. Berrange 
58b02db2d9SDaniel P. Berrange     task = g_new0(QIOTask, 1);
59b02db2d9SDaniel P. Berrange 
60b02db2d9SDaniel P. Berrange     task->source = source;
61b02db2d9SDaniel P. Berrange     object_ref(source);
62b02db2d9SDaniel P. Berrange     task->func = func;
63b02db2d9SDaniel P. Berrange     task->opaque = opaque;
64b02db2d9SDaniel P. Berrange     task->destroy = destroy;
65dbb44504SDaniel P. Berrangé     qemu_mutex_init(&task->thread_lock);
66dbb44504SDaniel P. Berrangé     qemu_cond_init(&task->thread_cond);
67b02db2d9SDaniel P. Berrange 
68b02db2d9SDaniel P. Berrange     trace_qio_task_new(task, source, func, opaque);
69b02db2d9SDaniel P. Berrange 
70b02db2d9SDaniel P. Berrange     return task;
71b02db2d9SDaniel P. Berrange }
72b02db2d9SDaniel P. Berrange 
qio_task_free(QIOTask * task)73b02db2d9SDaniel P. Berrange static void qio_task_free(QIOTask *task)
74b02db2d9SDaniel P. Berrange {
75dbb44504SDaniel P. Berrangé     qemu_mutex_lock(&task->thread_lock);
7652d6cfecSDaniel P. Berrangé     if (task->thread) {
7752d6cfecSDaniel P. Berrangé         if (task->thread->destroy) {
7852d6cfecSDaniel P. Berrangé             task->thread->destroy(task->thread->opaque);
7952d6cfecSDaniel P. Berrangé         }
8052d6cfecSDaniel P. Berrangé 
8152d6cfecSDaniel P. Berrangé         if (task->thread->context) {
8252d6cfecSDaniel P. Berrangé             g_main_context_unref(task->thread->context);
8352d6cfecSDaniel P. Berrangé         }
8452d6cfecSDaniel P. Berrangé 
8552d6cfecSDaniel P. Berrangé         g_free(task->thread);
8652d6cfecSDaniel P. Berrangé     }
8752d6cfecSDaniel P. Berrangé 
88b02db2d9SDaniel P. Berrange     if (task->destroy) {
89b02db2d9SDaniel P. Berrange         task->destroy(task->opaque);
90b02db2d9SDaniel P. Berrange     }
9152dd99e8SDaniel P. Berrange     if (task->destroyResult) {
9252dd99e8SDaniel P. Berrange         task->destroyResult(task->result);
9352dd99e8SDaniel P. Berrange     }
941a447e4fSDaniel P. Berrange     if (task->err) {
951a447e4fSDaniel P. Berrange         error_free(task->err);
961a447e4fSDaniel P. Berrange     }
97b02db2d9SDaniel P. Berrange     object_unref(task->source);
98b02db2d9SDaniel P. Berrange 
99dbb44504SDaniel P. Berrangé     qemu_mutex_unlock(&task->thread_lock);
100dbb44504SDaniel P. Berrangé     qemu_mutex_destroy(&task->thread_lock);
101dbb44504SDaniel P. Berrangé     qemu_cond_destroy(&task->thread_cond);
102dbb44504SDaniel P. Berrangé 
103b02db2d9SDaniel P. Berrange     g_free(task);
104b02db2d9SDaniel P. Berrange }
105b02db2d9SDaniel P. Berrange 
106b02db2d9SDaniel P. Berrange 
qio_task_thread_result(gpointer opaque)1077c28768fSPeter Xu static gboolean qio_task_thread_result(gpointer opaque)
108b02db2d9SDaniel P. Berrange {
10952d6cfecSDaniel P. Berrangé     QIOTask *task = opaque;
110b02db2d9SDaniel P. Berrange 
11152d6cfecSDaniel P. Berrangé     trace_qio_task_thread_result(task);
11252d6cfecSDaniel P. Berrangé     qio_task_complete(task);
113b02db2d9SDaniel P. Berrange 
114b02db2d9SDaniel P. Berrange     return FALSE;
115b02db2d9SDaniel P. Berrange }
116b02db2d9SDaniel P. Berrange 
117b02db2d9SDaniel P. Berrange 
qio_task_thread_worker(gpointer opaque)118b02db2d9SDaniel P. Berrange static gpointer qio_task_thread_worker(gpointer opaque)
119b02db2d9SDaniel P. Berrange {
12052d6cfecSDaniel P. Berrangé     QIOTask *task = opaque;
121b02db2d9SDaniel P. Berrange 
12252d6cfecSDaniel P. Berrangé     trace_qio_task_thread_run(task);
12352d6cfecSDaniel P. Berrangé 
12452d6cfecSDaniel P. Berrangé     task->thread->worker(task, task->thread->opaque);
125b02db2d9SDaniel P. Berrange 
126b02db2d9SDaniel P. Berrange     /* We're running in the background thread, and must only
127b02db2d9SDaniel P. Berrange      * ever report the task results in the main event loop
128b02db2d9SDaniel P. Berrange      * thread. So we schedule an idle callback to report
129b02db2d9SDaniel P. Berrange      * the worker results
130b02db2d9SDaniel P. Berrange      */
13152d6cfecSDaniel P. Berrangé     trace_qio_task_thread_exit(task);
132a17536c5SPeter Xu 
133dbb44504SDaniel P. Berrangé     qemu_mutex_lock(&task->thread_lock);
134dbb44504SDaniel P. Berrangé 
135dbb44504SDaniel P. Berrangé     task->thread->completion = g_idle_source_new();
136dbb44504SDaniel P. Berrangé     g_source_set_callback(task->thread->completion,
137dbb44504SDaniel P. Berrangé                           qio_task_thread_result, task, NULL);
138dbb44504SDaniel P. Berrangé     g_source_attach(task->thread->completion,
139dbb44504SDaniel P. Berrangé                     task->thread->context);
140b65cb867SAlberto Garcia     g_source_unref(task->thread->completion);
141dbb44504SDaniel P. Berrangé     trace_qio_task_thread_source_attach(task, task->thread->completion);
142dbb44504SDaniel P. Berrangé 
143dbb44504SDaniel P. Berrangé     qemu_cond_signal(&task->thread_cond);
144dbb44504SDaniel P. Berrangé     qemu_mutex_unlock(&task->thread_lock);
145a17536c5SPeter Xu 
146b02db2d9SDaniel P. Berrange     return NULL;
147b02db2d9SDaniel P. Berrange }
148b02db2d9SDaniel P. Berrange 
149b02db2d9SDaniel P. Berrange 
qio_task_run_in_thread(QIOTask * task,QIOTaskWorker worker,gpointer opaque,GDestroyNotify destroy,GMainContext * context)150b02db2d9SDaniel P. Berrange void qio_task_run_in_thread(QIOTask *task,
151b02db2d9SDaniel P. Berrange                             QIOTaskWorker worker,
152b02db2d9SDaniel P. Berrange                             gpointer opaque,
153a17536c5SPeter Xu                             GDestroyNotify destroy,
154a17536c5SPeter Xu                             GMainContext *context)
155b02db2d9SDaniel P. Berrange {
156b02db2d9SDaniel P. Berrange     struct QIOTaskThreadData *data = g_new0(struct QIOTaskThreadData, 1);
157b02db2d9SDaniel P. Berrange     QemuThread thread;
158b02db2d9SDaniel P. Berrange 
159a17536c5SPeter Xu     if (context) {
160a17536c5SPeter Xu         g_main_context_ref(context);
161a17536c5SPeter Xu     }
162a17536c5SPeter Xu 
163b02db2d9SDaniel P. Berrange     data->worker = worker;
164b02db2d9SDaniel P. Berrange     data->opaque = opaque;
165b02db2d9SDaniel P. Berrange     data->destroy = destroy;
166a17536c5SPeter Xu     data->context = context;
167b02db2d9SDaniel P. Berrange 
16852d6cfecSDaniel P. Berrangé     task->thread = data;
16952d6cfecSDaniel P. Berrangé 
170b02db2d9SDaniel P. Berrange     trace_qio_task_thread_start(task, worker, opaque);
171b02db2d9SDaniel P. Berrange     qemu_thread_create(&thread,
172b02db2d9SDaniel P. Berrange                        "io-task-worker",
173b02db2d9SDaniel P. Berrange                        qio_task_thread_worker,
17452d6cfecSDaniel P. Berrangé                        task,
175b02db2d9SDaniel P. Berrange                        QEMU_THREAD_DETACHED);
176b02db2d9SDaniel P. Berrange }
177b02db2d9SDaniel P. Berrange 
178b02db2d9SDaniel P. Berrange 
qio_task_wait_thread(QIOTask * task)179dbb44504SDaniel P. Berrangé void qio_task_wait_thread(QIOTask *task)
180dbb44504SDaniel P. Berrangé {
181dbb44504SDaniel P. Berrangé     qemu_mutex_lock(&task->thread_lock);
182dbb44504SDaniel P. Berrangé     g_assert(task->thread != NULL);
183dbb44504SDaniel P. Berrangé     while (task->thread->completion == NULL) {
184dbb44504SDaniel P. Berrangé         qemu_cond_wait(&task->thread_cond, &task->thread_lock);
185dbb44504SDaniel P. Berrangé     }
186dbb44504SDaniel P. Berrangé 
187dbb44504SDaniel P. Berrangé     trace_qio_task_thread_source_cancel(task, task->thread->completion);
188dbb44504SDaniel P. Berrangé     g_source_destroy(task->thread->completion);
189dbb44504SDaniel P. Berrangé     qemu_mutex_unlock(&task->thread_lock);
190dbb44504SDaniel P. Berrangé 
191dbb44504SDaniel P. Berrangé     qio_task_thread_result(task);
192dbb44504SDaniel P. Berrangé }
193dbb44504SDaniel P. Berrangé 
194dbb44504SDaniel P. Berrangé 
qio_task_complete(QIOTask * task)195b02db2d9SDaniel P. Berrange void qio_task_complete(QIOTask *task)
196b02db2d9SDaniel P. Berrange {
19760e705c5SDaniel P. Berrange     task->func(task, task->opaque);
198b02db2d9SDaniel P. Berrange     trace_qio_task_complete(task);
199b02db2d9SDaniel P. Berrange     qio_task_free(task);
200b02db2d9SDaniel P. Berrange }
201b02db2d9SDaniel P. Berrange 
202b02db2d9SDaniel P. Berrange 
qio_task_set_error(QIOTask * task,Error * err)2031a447e4fSDaniel P. Berrange void qio_task_set_error(QIOTask *task,
2041a447e4fSDaniel P. Berrange                         Error *err)
2051a447e4fSDaniel P. Berrange {
2061a447e4fSDaniel P. Berrange     error_propagate(&task->err, err);
2071a447e4fSDaniel P. Berrange }
2081a447e4fSDaniel P. Berrange 
2091a447e4fSDaniel P. Berrange 
qio_task_propagate_error(QIOTask * task,Error ** errp)2101a447e4fSDaniel P. Berrange bool qio_task_propagate_error(QIOTask *task,
2111a447e4fSDaniel P. Berrange                               Error **errp)
2121a447e4fSDaniel P. Berrange {
2131a447e4fSDaniel P. Berrange     if (task->err) {
2141a447e4fSDaniel P. Berrange         error_propagate(errp, task->err);
21580fb34edSDaniel P. Berrange         task->err = NULL;
2161a447e4fSDaniel P. Berrange         return true;
2171a447e4fSDaniel P. Berrange     }
2181a447e4fSDaniel P. Berrange 
2191a447e4fSDaniel P. Berrange     return false;
2201a447e4fSDaniel P. Berrange }
2211a447e4fSDaniel P. Berrange 
2221a447e4fSDaniel P. Berrange 
qio_task_set_result_pointer(QIOTask * task,gpointer result,GDestroyNotify destroy)22352dd99e8SDaniel P. Berrange void qio_task_set_result_pointer(QIOTask *task,
22452dd99e8SDaniel P. Berrange                                  gpointer result,
22552dd99e8SDaniel P. Berrange                                  GDestroyNotify destroy)
22652dd99e8SDaniel P. Berrange {
22752dd99e8SDaniel P. Berrange     task->result = result;
22852dd99e8SDaniel P. Berrange     task->destroyResult = destroy;
22952dd99e8SDaniel P. Berrange }
23052dd99e8SDaniel P. Berrange 
23152dd99e8SDaniel P. Berrange 
qio_task_get_result_pointer(QIOTask * task)23252dd99e8SDaniel P. Berrange gpointer qio_task_get_result_pointer(QIOTask *task)
23352dd99e8SDaniel P. Berrange {
23452dd99e8SDaniel P. Berrange     return task->result;
23552dd99e8SDaniel P. Berrange }
23652dd99e8SDaniel P. Berrange 
23752dd99e8SDaniel P. Berrange 
qio_task_get_source(QIOTask * task)238b02db2d9SDaniel P. Berrange Object *qio_task_get_source(QIOTask *task)
239b02db2d9SDaniel P. Berrange {
240b02db2d9SDaniel P. Berrange     return task->source;
241b02db2d9SDaniel P. Berrange }
242