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 9b02db2d9SDaniel P. Berrange * version 2 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 212a6a4076SMarkus Armbruster #ifndef QIO_TASK_H 222a6a4076SMarkus Armbruster #define QIO_TASK_H 23b02db2d9SDaniel P. Berrange 24b02db2d9SDaniel P. Berrange #include "qemu-common.h" 25b02db2d9SDaniel P. Berrange #include "qom/object.h" 26b02db2d9SDaniel P. Berrange 27b02db2d9SDaniel P. Berrange typedef struct QIOTask QIOTask; 28b02db2d9SDaniel P. Berrange 29b02db2d9SDaniel P. Berrange typedef void (*QIOTaskFunc)(Object *source, 30b02db2d9SDaniel P. Berrange Error *err, 31b02db2d9SDaniel P. Berrange gpointer opaque); 32b02db2d9SDaniel P. Berrange 33b02db2d9SDaniel P. Berrange typedef int (*QIOTaskWorker)(QIOTask *task, 34b02db2d9SDaniel P. Berrange Error **errp, 35b02db2d9SDaniel P. Berrange gpointer opaque); 36b02db2d9SDaniel P. Berrange 37b02db2d9SDaniel P. Berrange /** 38b02db2d9SDaniel P. Berrange * QIOTask: 39b02db2d9SDaniel P. Berrange * 40b02db2d9SDaniel P. Berrange * The QIOTask object provides a simple mechanism for reporting 41b02db2d9SDaniel P. Berrange * success / failure of long running background operations. 42b02db2d9SDaniel P. Berrange * 43b02db2d9SDaniel P. Berrange * A object on which the operation is to be performed could have 44b02db2d9SDaniel P. Berrange * a public API which accepts a task callback: 45b02db2d9SDaniel P. Berrange * 46b02db2d9SDaniel P. Berrange * <example> 47b02db2d9SDaniel P. Berrange * <title>Task callback function signature</title> 48b02db2d9SDaniel P. Berrange * <programlisting> 49b02db2d9SDaniel P. Berrange * void myobject_operation(QMyObject *obj, 50b02db2d9SDaniel P. Berrange * QIOTaskFunc *func, 51b02db2d9SDaniel P. Berrange * gpointer opaque, 52*e8c8adecSDaniel P. Berrange * GDestroyNotify notify); 53b02db2d9SDaniel P. Berrange * </programlisting> 54b02db2d9SDaniel P. Berrange * </example> 55b02db2d9SDaniel P. Berrange * 56b02db2d9SDaniel P. Berrange * The 'func' parameter is the callback to be invoked, and 'opaque' 57b02db2d9SDaniel P. Berrange * is data to pass to it. The optional 'notify' function is used 58b02db2d9SDaniel P. Berrange * to free 'opaque' when no longer needed. 59b02db2d9SDaniel P. Berrange * 60b02db2d9SDaniel P. Berrange * Now, lets say the implementation of this method wants to set 61b02db2d9SDaniel P. Berrange * a timer to run once a second checking for completion of some 62b02db2d9SDaniel P. Berrange * activity. It would do something like 63b02db2d9SDaniel P. Berrange * 64b02db2d9SDaniel P. Berrange * <example> 65b02db2d9SDaniel P. Berrange * <title>Task callback function implementation</title> 66b02db2d9SDaniel P. Berrange * <programlisting> 67b02db2d9SDaniel P. Berrange * void myobject_operation(QMyObject *obj, 68b02db2d9SDaniel P. Berrange * QIOTaskFunc *func, 69b02db2d9SDaniel P. Berrange * gpointer opaque, 70*e8c8adecSDaniel P. Berrange * GDestroyNotify notify) 71b02db2d9SDaniel P. Berrange * { 72b02db2d9SDaniel P. Berrange * QIOTask *task; 73b02db2d9SDaniel P. Berrange * 74b02db2d9SDaniel P. Berrange * task = qio_task_new(OBJECT(obj), func, opaque, notify); 75b02db2d9SDaniel P. Berrange * 76b02db2d9SDaniel P. Berrange * g_timeout_add_full(G_PRIORITY_DEFAULT, 77b02db2d9SDaniel P. Berrange * 1000, 78b02db2d9SDaniel P. Berrange * myobject_operation_timer, 79b02db2d9SDaniel P. Berrange * task, 80b02db2d9SDaniel P. Berrange * NULL); 81b02db2d9SDaniel P. Berrange * } 82b02db2d9SDaniel P. Berrange * </programlisting> 83b02db2d9SDaniel P. Berrange * </example> 84b02db2d9SDaniel P. Berrange * 85b02db2d9SDaniel P. Berrange * It could equally have setup a watch on a file descriptor or 86b02db2d9SDaniel P. Berrange * created a background thread, or something else entirely. 87b02db2d9SDaniel P. Berrange * Notice that the source object is passed to the task, and 88b02db2d9SDaniel P. Berrange * QIOTask will hold a reference on that. This ensure that 89b02db2d9SDaniel P. Berrange * the QMyObject instance cannot be garbage collected while 90b02db2d9SDaniel P. Berrange * the async task is still in progress. 91b02db2d9SDaniel P. Berrange * 92b02db2d9SDaniel P. Berrange * In this case, myobject_operation_timer will fire after 93b02db2d9SDaniel P. Berrange * 3 secs and do 94b02db2d9SDaniel P. Berrange * 95b02db2d9SDaniel P. Berrange * <example> 96b02db2d9SDaniel P. Berrange * <title>Task timer function</title> 97b02db2d9SDaniel P. Berrange * <programlisting> 98b02db2d9SDaniel P. Berrange * gboolean myobject_operation_timer(gpointer opaque) 99b02db2d9SDaniel P. Berrange * { 100b02db2d9SDaniel P. Berrange * QIOTask *task = QIO_TASK(opaque); 101b02db2d9SDaniel P. Berrange * Error *err;* 102b02db2d9SDaniel P. Berrange * 103b02db2d9SDaniel P. Berrange * ...check something important... 104b02db2d9SDaniel P. Berrange * if (err) { 105b02db2d9SDaniel P. Berrange * qio_task_abort(task, err); 106b02db2d9SDaniel P. Berrange * error_free(task); 107b02db2d9SDaniel P. Berrange * return FALSE; 108b02db2d9SDaniel P. Berrange * } else if (...work is completed ...) { 109b02db2d9SDaniel P. Berrange * qio_task_complete(task); 110b02db2d9SDaniel P. Berrange * return FALSE; 111b02db2d9SDaniel P. Berrange * } 112b02db2d9SDaniel P. Berrange * ...carry on polling ... 113b02db2d9SDaniel P. Berrange * return TRUE; 114b02db2d9SDaniel P. Berrange * } 115b02db2d9SDaniel P. Berrange * </programlisting> 116b02db2d9SDaniel P. Berrange * </example> 117b02db2d9SDaniel P. Berrange * 118b02db2d9SDaniel P. Berrange * Once this function returns false, object_unref will be called 119b02db2d9SDaniel P. Berrange * automatically on the task causing it to be released and the 120b02db2d9SDaniel P. Berrange * ref on QMyObject dropped too. 121b02db2d9SDaniel P. Berrange * 122b02db2d9SDaniel P. Berrange * The QIOTask module can also be used to perform operations 123b02db2d9SDaniel P. Berrange * in a background thread context, while still reporting the 124b02db2d9SDaniel P. Berrange * results in the main event thread. This allows code which 125b02db2d9SDaniel P. Berrange * cannot easily be rewritten to be asychronous (such as DNS 126b02db2d9SDaniel P. Berrange * lookups) to be easily run non-blocking. Reporting the 127b02db2d9SDaniel P. Berrange * results in the main thread context means that the caller 128b02db2d9SDaniel P. Berrange * typically does not need to be concerned about thread 129b02db2d9SDaniel P. Berrange * safety wrt the QEMU global mutex. 130b02db2d9SDaniel P. Berrange * 131b02db2d9SDaniel P. Berrange * For example, the socket_listen() method will block the caller 132b02db2d9SDaniel P. Berrange * while DNS lookups take place if given a name, instead of IP 133b02db2d9SDaniel P. Berrange * address. The C library often do not provide a practical async 134b02db2d9SDaniel P. Berrange * DNS API, so the to get non-blocking DNS lookups in a portable 135b02db2d9SDaniel P. Berrange * manner requires use of a thread. So achieve a non-blocking 136b02db2d9SDaniel P. Berrange * socket listen using QIOTask would require: 137b02db2d9SDaniel P. Berrange * 138b02db2d9SDaniel P. Berrange * <example> 139b02db2d9SDaniel P. Berrange * static int myobject_listen_worker(QIOTask *task, 140b02db2d9SDaniel P. Berrange * Error **errp, 141b02db2d9SDaniel P. Berrange * gpointer opaque) 142b02db2d9SDaniel P. Berrange * { 143b02db2d9SDaniel P. Berrange * QMyObject obj = QMY_OBJECT(qio_task_get_source(task)); 144b02db2d9SDaniel P. Berrange * SocketAddress *addr = opaque; 145b02db2d9SDaniel P. Berrange * 146b02db2d9SDaniel P. Berrange * obj->fd = socket_listen(addr, errp); 147b02db2d9SDaniel P. Berrange * if (obj->fd < 0) { 148b02db2d9SDaniel P. Berrange * return -1; 149b02db2d9SDaniel P. Berrange * } 150b02db2d9SDaniel P. Berrange * return 0; 151b02db2d9SDaniel P. Berrange * } 152b02db2d9SDaniel P. Berrange * 153b02db2d9SDaniel P. Berrange * void myobject_listen_async(QMyObject *obj, 154b02db2d9SDaniel P. Berrange * SocketAddress *addr, 155b02db2d9SDaniel P. Berrange * QIOTaskFunc *func, 156b02db2d9SDaniel P. Berrange * gpointer opaque, 157*e8c8adecSDaniel P. Berrange * GDestroyNotify notify) 158b02db2d9SDaniel P. Berrange * { 159b02db2d9SDaniel P. Berrange * QIOTask *task; 160b02db2d9SDaniel P. Berrange * SocketAddress *addrCopy; 161b02db2d9SDaniel P. Berrange * 16237f9e0a2SEric Blake * addrCopy = QAPI_CLONE(SocketAddress, addr); 163b02db2d9SDaniel P. Berrange * task = qio_task_new(OBJECT(obj), func, opaque, notify); 164b02db2d9SDaniel P. Berrange * 165b02db2d9SDaniel P. Berrange * qio_task_run_in_thread(task, myobject_listen_worker, 166b02db2d9SDaniel P. Berrange * addrCopy, 167b02db2d9SDaniel P. Berrange * qapi_free_SocketAddress); 168b02db2d9SDaniel P. Berrange * } 169b02db2d9SDaniel P. Berrange * </example> 170b02db2d9SDaniel P. Berrange * 171b02db2d9SDaniel P. Berrange * NB, The 'func' callback passed into myobject_listen_async 172b02db2d9SDaniel P. Berrange * will be invoked from the main event thread, despite the 173b02db2d9SDaniel P. Berrange * actual operation being performed in a different thread. 174b02db2d9SDaniel P. Berrange */ 175b02db2d9SDaniel P. Berrange 176b02db2d9SDaniel P. Berrange /** 177b02db2d9SDaniel P. Berrange * qio_task_new: 178b02db2d9SDaniel P. Berrange * @source: the object on which the operation is invoked 179b02db2d9SDaniel P. Berrange * @func: the callback to invoke when the task completes 180b02db2d9SDaniel P. Berrange * @opaque: opaque data to pass to @func when invoked 181b02db2d9SDaniel P. Berrange * @destroy: optional callback to free @opaque 182b02db2d9SDaniel P. Berrange * 183b02db2d9SDaniel P. Berrange * Creates a new task struct to track completion of a 184b02db2d9SDaniel P. Berrange * background operation running on the object @source. 185b02db2d9SDaniel P. Berrange * When the operation completes or fails, the callback 186b02db2d9SDaniel P. Berrange * @func will be invoked. The callback can access the 187b02db2d9SDaniel P. Berrange * 'err' attribute in the task object to determine if 188b02db2d9SDaniel P. Berrange * the operation was successful or not. 189b02db2d9SDaniel P. Berrange * 190b02db2d9SDaniel P. Berrange * The returned task will be released when one of 191b02db2d9SDaniel P. Berrange * qio_task_abort() or qio_task_complete() are invoked. 192b02db2d9SDaniel P. Berrange * 193b02db2d9SDaniel P. Berrange * Returns: the task struct 194b02db2d9SDaniel P. Berrange */ 195b02db2d9SDaniel P. Berrange QIOTask *qio_task_new(Object *source, 196b02db2d9SDaniel P. Berrange QIOTaskFunc func, 197b02db2d9SDaniel P. Berrange gpointer opaque, 198b02db2d9SDaniel P. Berrange GDestroyNotify destroy); 199b02db2d9SDaniel P. Berrange 200b02db2d9SDaniel P. Berrange /** 201b02db2d9SDaniel P. Berrange * qio_task_run_in_thread: 202b02db2d9SDaniel P. Berrange * @task: the task struct 203b02db2d9SDaniel P. Berrange * @worker: the function to invoke in a thread 204b02db2d9SDaniel P. Berrange * @opaque: opaque data to pass to @worker 205b02db2d9SDaniel P. Berrange * @destroy: function to free @opaque 206b02db2d9SDaniel P. Berrange * 207b02db2d9SDaniel P. Berrange * Run a task in a background thread. If @worker 208b02db2d9SDaniel P. Berrange * returns 0 it will call qio_task_complete() in 209b02db2d9SDaniel P. Berrange * the main event thread context. If @worker 210b02db2d9SDaniel P. Berrange * returns -1 it will call qio_task_abort() in 211b02db2d9SDaniel P. Berrange * the main event thread context. 212b02db2d9SDaniel P. Berrange */ 213b02db2d9SDaniel P. Berrange void qio_task_run_in_thread(QIOTask *task, 214b02db2d9SDaniel P. Berrange QIOTaskWorker worker, 215b02db2d9SDaniel P. Berrange gpointer opaque, 216b02db2d9SDaniel P. Berrange GDestroyNotify destroy); 217b02db2d9SDaniel P. Berrange 218b02db2d9SDaniel P. Berrange /** 219b02db2d9SDaniel P. Berrange * qio_task_complete: 220b02db2d9SDaniel P. Berrange * @task: the task struct 221b02db2d9SDaniel P. Berrange * 222cb8d4c8fSStefan Weil * Mark the operation as successfully completed 223b02db2d9SDaniel P. Berrange * and free the memory for @task. 224b02db2d9SDaniel P. Berrange */ 225b02db2d9SDaniel P. Berrange void qio_task_complete(QIOTask *task); 226b02db2d9SDaniel P. Berrange 227b02db2d9SDaniel P. Berrange /** 228b02db2d9SDaniel P. Berrange * qio_task_abort: 229b02db2d9SDaniel P. Berrange * @task: the task struct 230b02db2d9SDaniel P. Berrange * @err: the error to record for the operation 231b02db2d9SDaniel P. Berrange * 232b02db2d9SDaniel P. Berrange * Mark the operation as failed, with @err providing 233b02db2d9SDaniel P. Berrange * details about the failure. The @err may be freed 234b02db2d9SDaniel P. Berrange * afer the function returns, as the notification 235b02db2d9SDaniel P. Berrange * callback is invoked synchronously. The @task will 236b02db2d9SDaniel P. Berrange * be freed when this call completes. 237b02db2d9SDaniel P. Berrange */ 238b02db2d9SDaniel P. Berrange void qio_task_abort(QIOTask *task, 239b02db2d9SDaniel P. Berrange Error *err); 240b02db2d9SDaniel P. Berrange 241b02db2d9SDaniel P. Berrange 242b02db2d9SDaniel P. Berrange /** 243b02db2d9SDaniel P. Berrange * qio_task_get_source: 244b02db2d9SDaniel P. Berrange * @task: the task struct 245b02db2d9SDaniel P. Berrange * 246b02db2d9SDaniel P. Berrange * Get the source object associated with the background 247937470bbSDaniel P. Berrange * task. The caller does not own a reference on the 248937470bbSDaniel P. Berrange * returned Object, and so should call object_ref() 249937470bbSDaniel P. Berrange * if it wants to keep the object pointer outside the 250937470bbSDaniel P. Berrange * lifetime of the QIOTask object. 251b02db2d9SDaniel P. Berrange * 252b02db2d9SDaniel P. Berrange * Returns: the source object 253b02db2d9SDaniel P. Berrange */ 254b02db2d9SDaniel P. Berrange Object *qio_task_get_source(QIOTask *task); 255b02db2d9SDaniel P. Berrange 2562a6a4076SMarkus Armbruster #endif /* QIO_TASK_H */ 257