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 #ifndef QIO_TASK_H 22 #define QIO_TASK_H 23 24 #include "qemu-common.h" 25 #include "qom/object.h" 26 27 typedef struct QIOTask QIOTask; 28 29 typedef void (*QIOTaskFunc)(QIOTask *task, 30 gpointer opaque); 31 32 typedef void (*QIOTaskWorker)(QIOTask *task, 33 gpointer opaque); 34 35 /** 36 * QIOTask: 37 * 38 * The QIOTask object provides a simple mechanism for reporting 39 * success / failure of long running background operations. 40 * 41 * A object on which the operation is to be performed could have 42 * a public API which accepts a task callback: 43 * 44 * <example> 45 * <title>Task function signature</title> 46 * <programlisting> 47 * void myobject_operation(QMyObject *obj, 48 * QIOTaskFunc *func, 49 * gpointer opaque, 50 * GDestroyNotify notify); 51 * </programlisting> 52 * </example> 53 * 54 * The 'func' parameter is the callback to be invoked, and 'opaque' 55 * is data to pass to it. The optional 'notify' function is used 56 * to free 'opaque' when no longer needed. 57 * 58 * When the operation completes, the 'func' callback will be 59 * invoked, allowing the calling code to determine the result 60 * of the operation. An example QIOTaskFunc implementation may 61 * look like 62 * 63 * <example> 64 * <title>Task callback implementation</title> 65 * <programlisting> 66 * static void myobject_operation_notify(QIOTask *task, 67 * gpointer opaque) 68 * { 69 * Error *err = NULL; 70 * if (qio_task_propagate_error(task, &err)) { 71 * ...deal with the failure... 72 * error_free(err); 73 * } else { 74 * QMyObject *src = QMY_OBJECT(qio_task_get_source(task)); 75 * ...deal with the completion... 76 * } 77 * } 78 * </programlisting> 79 * </example> 80 * 81 * Now, lets say the implementation of the method using the 82 * task wants to set a timer to run once a second checking 83 * for completion of some activity. It would do something 84 * like 85 * 86 * <example> 87 * <title>Task function implementation</title> 88 * <programlisting> 89 * void myobject_operation(QMyObject *obj, 90 * QIOTaskFunc *func, 91 * gpointer opaque, 92 * GDestroyNotify notify) 93 * { 94 * QIOTask *task; 95 * 96 * task = qio_task_new(OBJECT(obj), func, opaque, notify); 97 * 98 * g_timeout_add_full(G_PRIORITY_DEFAULT, 99 * 1000, 100 * myobject_operation_timer, 101 * task, 102 * NULL); 103 * } 104 * </programlisting> 105 * </example> 106 * 107 * It could equally have setup a watch on a file descriptor or 108 * created a background thread, or something else entirely. 109 * Notice that the source object is passed to the task, and 110 * QIOTask will hold a reference on that. This ensure that 111 * the QMyObject instance cannot be garbage collected while 112 * the async task is still in progress. 113 * 114 * In this case, myobject_operation_timer will fire after 115 * 3 secs and do 116 * 117 * <example> 118 * <title>Task timer function</title> 119 * <programlisting> 120 * gboolean myobject_operation_timer(gpointer opaque) 121 * { 122 * QIOTask *task = QIO_TASK(opaque); 123 * Error *err;* 124 * 125 * ...check something important... 126 * if (err) { 127 * qio_task_set_error(task, err); 128 * qio_task_complete(task); 129 * return FALSE; 130 * } else if (...work is completed ...) { 131 * qio_task_complete(task); 132 * return FALSE; 133 * } 134 * ...carry on polling ... 135 * return TRUE; 136 * } 137 * </programlisting> 138 * </example> 139 * 140 * The 'qio_task_complete' call in this method will trigger 141 * the callback func 'myobject_operation_notify' shown 142 * earlier to deal with the results. 143 * 144 * Once this function returns false, object_unref will be called 145 * automatically on the task causing it to be released and the 146 * ref on QMyObject dropped too. 147 * 148 * The QIOTask module can also be used to perform operations 149 * in a background thread context, while still reporting the 150 * results in the main event thread. This allows code which 151 * cannot easily be rewritten to be asychronous (such as DNS 152 * lookups) to be easily run non-blocking. Reporting the 153 * results in the main thread context means that the caller 154 * typically does not need to be concerned about thread 155 * safety wrt the QEMU global mutex. 156 * 157 * For example, the socket_listen() method will block the caller 158 * while DNS lookups take place if given a name, instead of IP 159 * address. The C library often do not provide a practical async 160 * DNS API, so the to get non-blocking DNS lookups in a portable 161 * manner requires use of a thread. So achieve a non-blocking 162 * socket listen using QIOTask would require: 163 * 164 * <example> 165 * static void myobject_listen_worker(QIOTask *task, 166 * gpointer opaque) 167 * { 168 * QMyObject obj = QMY_OBJECT(qio_task_get_source(task)); 169 * SocketAddress *addr = opaque; 170 * Error *err = NULL; 171 * 172 * obj->fd = socket_listen(addr, &err); 173 * 174 qio_task_set_error(task, err); 175 * } 176 * 177 * void myobject_listen_async(QMyObject *obj, 178 * SocketAddress *addr, 179 * QIOTaskFunc *func, 180 * gpointer opaque, 181 * GDestroyNotify notify) 182 * { 183 * QIOTask *task; 184 * SocketAddress *addrCopy; 185 * 186 * addrCopy = QAPI_CLONE(SocketAddress, addr); 187 * task = qio_task_new(OBJECT(obj), func, opaque, notify); 188 * 189 * qio_task_run_in_thread(task, myobject_listen_worker, 190 * addrCopy, 191 * qapi_free_SocketAddress); 192 * } 193 * </example> 194 * 195 * NB, The 'func' callback passed into myobject_listen_async 196 * will be invoked from the main event thread, despite the 197 * actual operation being performed in a different thread. 198 */ 199 200 /** 201 * qio_task_new: 202 * @source: the object on which the operation is invoked 203 * @func: the callback to invoke when the task completes 204 * @opaque: opaque data to pass to @func when invoked 205 * @destroy: optional callback to free @opaque 206 * 207 * Creates a new task struct to track completion of a 208 * background operation running on the object @source. 209 * When the operation completes or fails, the callback 210 * @func will be invoked. The callback can access the 211 * 'err' attribute in the task object to determine if 212 * the operation was successful or not. 213 * 214 * The returned task will be released when qio_task_complete() 215 * is invoked. 216 * 217 * Returns: the task struct 218 */ 219 QIOTask *qio_task_new(Object *source, 220 QIOTaskFunc func, 221 gpointer opaque, 222 GDestroyNotify destroy); 223 224 /** 225 * qio_task_run_in_thread: 226 * @task: the task struct 227 * @worker: the function to invoke in a thread 228 * @opaque: opaque data to pass to @worker 229 * @destroy: function to free @opaque 230 * @context: the context to run the complete hook. If %NULL, the 231 * default context will be used. 232 * 233 * Run a task in a background thread. When @worker 234 * returns it will call qio_task_complete() in 235 * the event thread context that provided. 236 */ 237 void qio_task_run_in_thread(QIOTask *task, 238 QIOTaskWorker worker, 239 gpointer opaque, 240 GDestroyNotify destroy, 241 GMainContext *context); 242 243 /** 244 * qio_task_complete: 245 * @task: the task struct 246 * 247 * Invoke the completion callback for @task and 248 * then free its memory. 249 */ 250 void qio_task_complete(QIOTask *task); 251 252 253 /** 254 * qio_task_set_error: 255 * @task: the task struct 256 * @err: pointer to the error, or NULL 257 * 258 * Associate an error with the task, which can later 259 * be retrieved with the qio_task_propagate_error() 260 * method. This method takes ownership of @err, so 261 * it is not valid to access it after this call 262 * completes. If @err is NULL this is a no-op. If 263 * this is call multiple times, only the first 264 * provided @err will be recorded, later ones will 265 * be discarded and freed. 266 */ 267 void qio_task_set_error(QIOTask *task, 268 Error *err); 269 270 271 /** 272 * qio_task_propagate_error: 273 * @task: the task struct 274 * @errp: pointer to a NULL-initialized error object 275 * 276 * Propagate the error associated with @task 277 * into @errp. 278 * 279 * Returns: true if an error was propagated, false otherwise 280 */ 281 bool qio_task_propagate_error(QIOTask *task, 282 Error **errp); 283 284 285 /** 286 * qio_task_set_result_pointer: 287 * @task: the task struct 288 * @result: pointer to the result data 289 * 290 * Associate an opaque result with the task, 291 * which can later be retrieved with the 292 * qio_task_get_result_pointer() method 293 * 294 */ 295 void qio_task_set_result_pointer(QIOTask *task, 296 gpointer result, 297 GDestroyNotify notify); 298 299 300 /** 301 * qio_task_get_result_pointer: 302 * @task: the task struct 303 * 304 * Retrieve the opaque result data associated 305 * with the task, if any. 306 * 307 * Returns: the task result, or NULL 308 */ 309 gpointer qio_task_get_result_pointer(QIOTask *task); 310 311 312 /** 313 * qio_task_get_source: 314 * @task: the task struct 315 * 316 * Get the source object associated with the background 317 * task. The caller does not own a reference on the 318 * returned Object, and so should call object_ref() 319 * if it wants to keep the object pointer outside the 320 * lifetime of the QIOTask object. 321 * 322 * Returns: the source object 323 */ 324 Object *qio_task_get_source(QIOTask *task); 325 326 #endif /* QIO_TASK_H */ 327