1 /* 2 * QEMU I/O task 3 * 4 * Copyright (c) 2015 Red Hat, Inc. 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18 * 19 */ 20 21 #include "io/task.h" 22 #include "qemu/thread.h" 23 #include "trace.h" 24 25 struct QIOTask { 26 Object *source; 27 QIOTaskFunc func; 28 gpointer opaque; 29 GDestroyNotify destroy; 30 }; 31 32 33 QIOTask *qio_task_new(Object *source, 34 QIOTaskFunc func, 35 gpointer opaque, 36 GDestroyNotify destroy) 37 { 38 QIOTask *task; 39 40 task = g_new0(QIOTask, 1); 41 42 task->source = source; 43 object_ref(source); 44 task->func = func; 45 task->opaque = opaque; 46 task->destroy = destroy; 47 48 trace_qio_task_new(task, source, func, opaque); 49 50 return task; 51 } 52 53 static void qio_task_free(QIOTask *task) 54 { 55 if (task->destroy) { 56 task->destroy(task->opaque); 57 } 58 object_unref(task->source); 59 60 g_free(task); 61 } 62 63 64 struct QIOTaskThreadData { 65 QIOTask *task; 66 QIOTaskWorker worker; 67 gpointer opaque; 68 GDestroyNotify destroy; 69 Error *err; 70 int ret; 71 }; 72 73 74 static gboolean gio_task_thread_result(gpointer opaque) 75 { 76 struct QIOTaskThreadData *data = opaque; 77 78 trace_qio_task_thread_result(data->task); 79 if (data->ret == 0) { 80 qio_task_complete(data->task); 81 } else { 82 qio_task_abort(data->task, data->err); 83 } 84 85 error_free(data->err); 86 if (data->destroy) { 87 data->destroy(data->opaque); 88 } 89 90 g_free(data); 91 92 return FALSE; 93 } 94 95 96 static gpointer qio_task_thread_worker(gpointer opaque) 97 { 98 struct QIOTaskThreadData *data = opaque; 99 100 trace_qio_task_thread_run(data->task); 101 data->ret = data->worker(data->task, &data->err, data->opaque); 102 if (data->ret < 0 && data->err == NULL) { 103 error_setg(&data->err, "Task worker failed but did not set an error"); 104 } 105 106 /* We're running in the background thread, and must only 107 * ever report the task results in the main event loop 108 * thread. So we schedule an idle callback to report 109 * the worker results 110 */ 111 trace_qio_task_thread_exit(data->task); 112 g_idle_add(gio_task_thread_result, data); 113 return NULL; 114 } 115 116 117 void qio_task_run_in_thread(QIOTask *task, 118 QIOTaskWorker worker, 119 gpointer opaque, 120 GDestroyNotify destroy) 121 { 122 struct QIOTaskThreadData *data = g_new0(struct QIOTaskThreadData, 1); 123 QemuThread thread; 124 125 data->task = task; 126 data->worker = worker; 127 data->opaque = opaque; 128 data->destroy = destroy; 129 130 trace_qio_task_thread_start(task, worker, opaque); 131 qemu_thread_create(&thread, 132 "io-task-worker", 133 qio_task_thread_worker, 134 data, 135 QEMU_THREAD_DETACHED); 136 } 137 138 139 void qio_task_complete(QIOTask *task) 140 { 141 task->func(task->source, NULL, task->opaque); 142 trace_qio_task_complete(task); 143 qio_task_free(task); 144 } 145 146 void qio_task_abort(QIOTask *task, 147 Error *err) 148 { 149 task->func(task->source, err, task->opaque); 150 trace_qio_task_abort(task); 151 qio_task_free(task); 152 } 153 154 155 Object *qio_task_get_source(QIOTask *task) 156 { 157 object_ref(task->source); 158 return task->source; 159 } 160