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 "qemu/osdep.h" 22 #include "io/task.h" 23 #include "qapi/error.h" 24 #include "qemu/thread.h" 25 #include "trace.h" 26 27 struct QIOTask { 28 Object *source; 29 QIOTaskFunc func; 30 gpointer opaque; 31 GDestroyNotify destroy; 32 Error *err; 33 gpointer result; 34 GDestroyNotify destroyResult; 35 }; 36 37 38 QIOTask *qio_task_new(Object *source, 39 QIOTaskFunc func, 40 gpointer opaque, 41 GDestroyNotify destroy) 42 { 43 QIOTask *task; 44 45 task = g_new0(QIOTask, 1); 46 47 task->source = source; 48 object_ref(source); 49 task->func = func; 50 task->opaque = opaque; 51 task->destroy = destroy; 52 53 trace_qio_task_new(task, source, func, opaque); 54 55 return task; 56 } 57 58 static void qio_task_free(QIOTask *task) 59 { 60 if (task->destroy) { 61 task->destroy(task->opaque); 62 } 63 if (task->destroyResult) { 64 task->destroyResult(task->result); 65 } 66 if (task->err) { 67 error_free(task->err); 68 } 69 object_unref(task->source); 70 71 g_free(task); 72 } 73 74 75 struct QIOTaskThreadData { 76 QIOTask *task; 77 QIOTaskWorker worker; 78 gpointer opaque; 79 GDestroyNotify destroy; 80 }; 81 82 83 static gboolean gio_task_thread_result(gpointer opaque) 84 { 85 struct QIOTaskThreadData *data = opaque; 86 87 trace_qio_task_thread_result(data->task); 88 qio_task_complete(data->task); 89 90 if (data->destroy) { 91 data->destroy(data->opaque); 92 } 93 94 g_free(data); 95 96 return FALSE; 97 } 98 99 100 static gpointer qio_task_thread_worker(gpointer opaque) 101 { 102 struct QIOTaskThreadData *data = opaque; 103 104 trace_qio_task_thread_run(data->task); 105 data->worker(data->task, data->opaque); 106 107 /* We're running in the background thread, and must only 108 * ever report the task results in the main event loop 109 * thread. So we schedule an idle callback to report 110 * the worker results 111 */ 112 trace_qio_task_thread_exit(data->task); 113 g_idle_add(gio_task_thread_result, data); 114 return NULL; 115 } 116 117 118 void qio_task_run_in_thread(QIOTask *task, 119 QIOTaskWorker worker, 120 gpointer opaque, 121 GDestroyNotify destroy) 122 { 123 struct QIOTaskThreadData *data = g_new0(struct QIOTaskThreadData, 1); 124 QemuThread thread; 125 126 data->task = task; 127 data->worker = worker; 128 data->opaque = opaque; 129 data->destroy = destroy; 130 131 trace_qio_task_thread_start(task, worker, opaque); 132 qemu_thread_create(&thread, 133 "io-task-worker", 134 qio_task_thread_worker, 135 data, 136 QEMU_THREAD_DETACHED); 137 } 138 139 140 void qio_task_complete(QIOTask *task) 141 { 142 task->func(task, task->opaque); 143 trace_qio_task_complete(task); 144 qio_task_free(task); 145 } 146 147 148 void qio_task_set_error(QIOTask *task, 149 Error *err) 150 { 151 error_propagate(&task->err, err); 152 } 153 154 155 bool qio_task_propagate_error(QIOTask *task, 156 Error **errp) 157 { 158 if (task->err) { 159 error_propagate(errp, task->err); 160 return true; 161 } 162 163 return false; 164 } 165 166 167 void qio_task_set_result_pointer(QIOTask *task, 168 gpointer result, 169 GDestroyNotify destroy) 170 { 171 task->result = result; 172 task->destroyResult = destroy; 173 } 174 175 176 gpointer qio_task_get_result_pointer(QIOTask *task) 177 { 178 return task->result; 179 } 180 181 182 Object *qio_task_get_source(QIOTask *task) 183 { 184 return task->source; 185 } 186