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