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 "qom/object.h" 25b02db2d9SDaniel P. Berrange 26b02db2d9SDaniel P. Berrange typedef struct QIOTask QIOTask; 27b02db2d9SDaniel P. Berrange 2860e705c5SDaniel P. Berrange typedef void (*QIOTaskFunc)(QIOTask *task, 29b02db2d9SDaniel P. Berrange gpointer opaque); 30b02db2d9SDaniel P. Berrange 3159de517dSDaniel P. Berrange typedef void (*QIOTaskWorker)(QIOTask *task, 32b02db2d9SDaniel P. Berrange gpointer opaque); 33b02db2d9SDaniel P. Berrange 34b02db2d9SDaniel P. Berrange /** 35b02db2d9SDaniel P. Berrange * QIOTask: 36b02db2d9SDaniel P. Berrange * 37b02db2d9SDaniel P. Berrange * The QIOTask object provides a simple mechanism for reporting 38b02db2d9SDaniel P. Berrange * success / failure of long running background operations. 39b02db2d9SDaniel P. Berrange * 40b02db2d9SDaniel P. Berrange * A object on which the operation is to be performed could have 41b02db2d9SDaniel P. Berrange * a public API which accepts a task callback: 42b02db2d9SDaniel P. Berrange * 43b02db2d9SDaniel P. Berrange * <example> 4460e705c5SDaniel P. Berrange * <title>Task function signature</title> 45b02db2d9SDaniel P. Berrange * <programlisting> 46b02db2d9SDaniel P. Berrange * void myobject_operation(QMyObject *obj, 47b02db2d9SDaniel P. Berrange * QIOTaskFunc *func, 48b02db2d9SDaniel P. Berrange * gpointer opaque, 49e8c8adecSDaniel P. Berrange * GDestroyNotify notify); 50b02db2d9SDaniel P. Berrange * </programlisting> 51b02db2d9SDaniel P. Berrange * </example> 52b02db2d9SDaniel P. Berrange * 53b02db2d9SDaniel P. Berrange * The 'func' parameter is the callback to be invoked, and 'opaque' 54b02db2d9SDaniel P. Berrange * is data to pass to it. The optional 'notify' function is used 55b02db2d9SDaniel P. Berrange * to free 'opaque' when no longer needed. 56b02db2d9SDaniel P. Berrange * 5760e705c5SDaniel P. Berrange * When the operation completes, the 'func' callback will be 5860e705c5SDaniel P. Berrange * invoked, allowing the calling code to determine the result 5960e705c5SDaniel P. Berrange * of the operation. An example QIOTaskFunc implementation may 6060e705c5SDaniel P. Berrange * look like 61b02db2d9SDaniel P. Berrange * 62b02db2d9SDaniel P. Berrange * <example> 6360e705c5SDaniel P. Berrange * <title>Task callback implementation</title> 6460e705c5SDaniel P. Berrange * <programlisting> 6560e705c5SDaniel P. Berrange * static void myobject_operation_notify(QIOTask *task, 6660e705c5SDaniel P. Berrange * gpointer opaque) 6760e705c5SDaniel P. Berrange * { 6860e705c5SDaniel P. Berrange * Error *err = NULL; 6960e705c5SDaniel P. Berrange * if (qio_task_propagate_error(task, &err)) { 7060e705c5SDaniel P. Berrange * ...deal with the failure... 7160e705c5SDaniel P. Berrange * error_free(err); 7260e705c5SDaniel P. Berrange * } else { 7360e705c5SDaniel P. Berrange * QMyObject *src = QMY_OBJECT(qio_task_get_source(task)); 7460e705c5SDaniel P. Berrange * ...deal with the completion... 7560e705c5SDaniel P. Berrange * } 7660e705c5SDaniel P. Berrange * } 7760e705c5SDaniel P. Berrange * </programlisting> 7860e705c5SDaniel P. Berrange * </example> 7960e705c5SDaniel P. Berrange * 8060e705c5SDaniel P. Berrange * Now, lets say the implementation of the method using the 8160e705c5SDaniel P. Berrange * task wants to set a timer to run once a second checking 8260e705c5SDaniel P. Berrange * for completion of some activity. It would do something 8360e705c5SDaniel P. Berrange * like 8460e705c5SDaniel P. Berrange * 8560e705c5SDaniel P. Berrange * <example> 8660e705c5SDaniel P. Berrange * <title>Task function implementation</title> 87b02db2d9SDaniel P. Berrange * <programlisting> 88b02db2d9SDaniel P. Berrange * void myobject_operation(QMyObject *obj, 89b02db2d9SDaniel P. Berrange * QIOTaskFunc *func, 90b02db2d9SDaniel P. Berrange * gpointer opaque, 91e8c8adecSDaniel P. Berrange * GDestroyNotify notify) 92b02db2d9SDaniel P. Berrange * { 93b02db2d9SDaniel P. Berrange * QIOTask *task; 94b02db2d9SDaniel P. Berrange * 95b02db2d9SDaniel P. Berrange * task = qio_task_new(OBJECT(obj), func, opaque, notify); 96b02db2d9SDaniel P. Berrange * 97b02db2d9SDaniel P. Berrange * g_timeout_add_full(G_PRIORITY_DEFAULT, 98b02db2d9SDaniel P. Berrange * 1000, 99b02db2d9SDaniel P. Berrange * myobject_operation_timer, 100b02db2d9SDaniel P. Berrange * task, 101b02db2d9SDaniel P. Berrange * NULL); 102b02db2d9SDaniel P. Berrange * } 103b02db2d9SDaniel P. Berrange * </programlisting> 104b02db2d9SDaniel P. Berrange * </example> 105b02db2d9SDaniel P. Berrange * 106b02db2d9SDaniel P. Berrange * It could equally have setup a watch on a file descriptor or 107b02db2d9SDaniel P. Berrange * created a background thread, or something else entirely. 108b02db2d9SDaniel P. Berrange * Notice that the source object is passed to the task, and 109b02db2d9SDaniel P. Berrange * QIOTask will hold a reference on that. This ensure that 110b02db2d9SDaniel P. Berrange * the QMyObject instance cannot be garbage collected while 111b02db2d9SDaniel P. Berrange * the async task is still in progress. 112b02db2d9SDaniel P. Berrange * 113b02db2d9SDaniel P. Berrange * In this case, myobject_operation_timer will fire after 114b02db2d9SDaniel P. Berrange * 3 secs and do 115b02db2d9SDaniel P. Berrange * 116b02db2d9SDaniel P. Berrange * <example> 117b02db2d9SDaniel P. Berrange * <title>Task timer function</title> 118b02db2d9SDaniel P. Berrange * <programlisting> 119b02db2d9SDaniel P. Berrange * gboolean myobject_operation_timer(gpointer opaque) 120b02db2d9SDaniel P. Berrange * { 121b02db2d9SDaniel P. Berrange * QIOTask *task = QIO_TASK(opaque); 122*e4eb089cSMarkus Armbruster * Error *err = NULL; 123b02db2d9SDaniel P. Berrange * 124b02db2d9SDaniel P. Berrange * ...check something important... 125b02db2d9SDaniel P. Berrange * if (err) { 12660e705c5SDaniel P. Berrange * qio_task_set_error(task, err); 12760e705c5SDaniel P. Berrange * qio_task_complete(task); 128b02db2d9SDaniel P. Berrange * return FALSE; 129b02db2d9SDaniel P. Berrange * } else if (...work is completed ...) { 130b02db2d9SDaniel P. Berrange * qio_task_complete(task); 131b02db2d9SDaniel P. Berrange * return FALSE; 132b02db2d9SDaniel P. Berrange * } 133b02db2d9SDaniel P. Berrange * ...carry on polling ... 134b02db2d9SDaniel P. Berrange * return TRUE; 135b02db2d9SDaniel P. Berrange * } 136b02db2d9SDaniel P. Berrange * </programlisting> 137b02db2d9SDaniel P. Berrange * </example> 138b02db2d9SDaniel P. Berrange * 13960e705c5SDaniel P. Berrange * The 'qio_task_complete' call in this method will trigger 14060e705c5SDaniel P. Berrange * the callback func 'myobject_operation_notify' shown 14160e705c5SDaniel P. Berrange * earlier to deal with the results. 14260e705c5SDaniel P. Berrange * 143b02db2d9SDaniel P. Berrange * Once this function returns false, object_unref will be called 144b02db2d9SDaniel P. Berrange * automatically on the task causing it to be released and the 145b02db2d9SDaniel P. Berrange * ref on QMyObject dropped too. 146b02db2d9SDaniel P. Berrange * 147b02db2d9SDaniel P. Berrange * The QIOTask module can also be used to perform operations 148b02db2d9SDaniel P. Berrange * in a background thread context, while still reporting the 149b02db2d9SDaniel P. Berrange * results in the main event thread. This allows code which 150b02db2d9SDaniel P. Berrange * cannot easily be rewritten to be asychronous (such as DNS 151b02db2d9SDaniel P. Berrange * lookups) to be easily run non-blocking. Reporting the 152b02db2d9SDaniel P. Berrange * results in the main thread context means that the caller 153b02db2d9SDaniel P. Berrange * typically does not need to be concerned about thread 154b02db2d9SDaniel P. Berrange * safety wrt the QEMU global mutex. 155b02db2d9SDaniel P. Berrange * 156b02db2d9SDaniel P. Berrange * For example, the socket_listen() method will block the caller 157b02db2d9SDaniel P. Berrange * while DNS lookups take place if given a name, instead of IP 158b02db2d9SDaniel P. Berrange * address. The C library often do not provide a practical async 159b02db2d9SDaniel P. Berrange * DNS API, so the to get non-blocking DNS lookups in a portable 160b02db2d9SDaniel P. Berrange * manner requires use of a thread. So achieve a non-blocking 161b02db2d9SDaniel P. Berrange * socket listen using QIOTask would require: 162b02db2d9SDaniel P. Berrange * 163b02db2d9SDaniel P. Berrange * <example> 16459de517dSDaniel P. Berrange * static void myobject_listen_worker(QIOTask *task, 165b02db2d9SDaniel P. Berrange * gpointer opaque) 166b02db2d9SDaniel P. Berrange * { 167b02db2d9SDaniel P. Berrange * QMyObject obj = QMY_OBJECT(qio_task_get_source(task)); 168b02db2d9SDaniel P. Berrange * SocketAddress *addr = opaque; 16959de517dSDaniel P. Berrange * Error *err = NULL; 170b02db2d9SDaniel P. Berrange * 17159de517dSDaniel P. Berrange * obj->fd = socket_listen(addr, &err); 17259de517dSDaniel P. Berrange * 17359de517dSDaniel P. Berrange qio_task_set_error(task, err); 174b02db2d9SDaniel P. Berrange * } 175b02db2d9SDaniel P. Berrange * 176b02db2d9SDaniel P. Berrange * void myobject_listen_async(QMyObject *obj, 177b02db2d9SDaniel P. Berrange * SocketAddress *addr, 178b02db2d9SDaniel P. Berrange * QIOTaskFunc *func, 179b02db2d9SDaniel P. Berrange * gpointer opaque, 180e8c8adecSDaniel P. Berrange * GDestroyNotify notify) 181b02db2d9SDaniel P. Berrange * { 182b02db2d9SDaniel P. Berrange * QIOTask *task; 183b02db2d9SDaniel P. Berrange * SocketAddress *addrCopy; 184b02db2d9SDaniel P. Berrange * 18537f9e0a2SEric Blake * addrCopy = QAPI_CLONE(SocketAddress, addr); 186b02db2d9SDaniel P. Berrange * task = qio_task_new(OBJECT(obj), func, opaque, notify); 187b02db2d9SDaniel P. Berrange * 188b02db2d9SDaniel P. Berrange * qio_task_run_in_thread(task, myobject_listen_worker, 189b02db2d9SDaniel P. Berrange * addrCopy, 190b02db2d9SDaniel P. Berrange * qapi_free_SocketAddress); 191b02db2d9SDaniel P. Berrange * } 192b02db2d9SDaniel P. Berrange * </example> 193b02db2d9SDaniel P. Berrange * 194b02db2d9SDaniel P. Berrange * NB, The 'func' callback passed into myobject_listen_async 195b02db2d9SDaniel P. Berrange * will be invoked from the main event thread, despite the 196b02db2d9SDaniel P. Berrange * actual operation being performed in a different thread. 197b02db2d9SDaniel P. Berrange */ 198b02db2d9SDaniel P. Berrange 199b02db2d9SDaniel P. Berrange /** 200b02db2d9SDaniel P. Berrange * qio_task_new: 201b02db2d9SDaniel P. Berrange * @source: the object on which the operation is invoked 202b02db2d9SDaniel P. Berrange * @func: the callback to invoke when the task completes 203b02db2d9SDaniel P. Berrange * @opaque: opaque data to pass to @func when invoked 204b02db2d9SDaniel P. Berrange * @destroy: optional callback to free @opaque 205b02db2d9SDaniel P. Berrange * 206b02db2d9SDaniel P. Berrange * Creates a new task struct to track completion of a 207b02db2d9SDaniel P. Berrange * background operation running on the object @source. 208b02db2d9SDaniel P. Berrange * When the operation completes or fails, the callback 209b02db2d9SDaniel P. Berrange * @func will be invoked. The callback can access the 210b02db2d9SDaniel P. Berrange * 'err' attribute in the task object to determine if 211b02db2d9SDaniel P. Berrange * the operation was successful or not. 212b02db2d9SDaniel P. Berrange * 21360e705c5SDaniel P. Berrange * The returned task will be released when qio_task_complete() 21460e705c5SDaniel P. Berrange * is invoked. 215b02db2d9SDaniel P. Berrange * 216b02db2d9SDaniel P. Berrange * Returns: the task struct 217b02db2d9SDaniel P. Berrange */ 218b02db2d9SDaniel P. Berrange QIOTask *qio_task_new(Object *source, 219b02db2d9SDaniel P. Berrange QIOTaskFunc func, 220b02db2d9SDaniel P. Berrange gpointer opaque, 221b02db2d9SDaniel P. Berrange GDestroyNotify destroy); 222b02db2d9SDaniel P. Berrange 223b02db2d9SDaniel P. Berrange /** 224b02db2d9SDaniel P. Berrange * qio_task_run_in_thread: 225b02db2d9SDaniel P. Berrange * @task: the task struct 226b02db2d9SDaniel P. Berrange * @worker: the function to invoke in a thread 227b02db2d9SDaniel P. Berrange * @opaque: opaque data to pass to @worker 228b02db2d9SDaniel P. Berrange * @destroy: function to free @opaque 229a17536c5SPeter Xu * @context: the context to run the complete hook. If %NULL, the 230a17536c5SPeter Xu * default context will be used. 231b02db2d9SDaniel P. Berrange * 23260e705c5SDaniel P. Berrange * Run a task in a background thread. When @worker 23360e705c5SDaniel P. Berrange * returns it will call qio_task_complete() in 234dbb44504SDaniel P. Berrangé * the thread that is running the main loop associated 235dbb44504SDaniel P. Berrangé * with @context. 236b02db2d9SDaniel P. Berrange */ 237b02db2d9SDaniel P. Berrange void qio_task_run_in_thread(QIOTask *task, 238b02db2d9SDaniel P. Berrange QIOTaskWorker worker, 239b02db2d9SDaniel P. Berrange gpointer opaque, 240a17536c5SPeter Xu GDestroyNotify destroy, 241a17536c5SPeter Xu GMainContext *context); 242b02db2d9SDaniel P. Berrange 243dbb44504SDaniel P. Berrangé 244dbb44504SDaniel P. Berrangé /** 245dbb44504SDaniel P. Berrangé * qio_task_wait_thread: 246dbb44504SDaniel P. Berrangé * @task: the task struct 247dbb44504SDaniel P. Berrangé * 248dbb44504SDaniel P. Berrangé * Wait for completion of a task that was previously 249dbb44504SDaniel P. Berrangé * invoked using qio_task_run_in_thread. This MUST 250dbb44504SDaniel P. Berrangé * ONLY be invoked if the task has not already 251dbb44504SDaniel P. Berrangé * completed, since after the completion callback 252dbb44504SDaniel P. Berrangé * is invoked, @task will have been freed. 253dbb44504SDaniel P. Berrangé * 254dbb44504SDaniel P. Berrangé * To avoid racing with execution of the completion 255dbb44504SDaniel P. Berrangé * callback provided with qio_task_new, this method 256dbb44504SDaniel P. Berrangé * MUST ONLY be invoked from the thread that is 257dbb44504SDaniel P. Berrangé * running the main loop associated with @context 258dbb44504SDaniel P. Berrangé * parameter to qio_task_run_in_thread. 259dbb44504SDaniel P. Berrangé * 260dbb44504SDaniel P. Berrangé * When the thread has completed, the completion 261dbb44504SDaniel P. Berrangé * callback provided to qio_task_new will be invoked. 262dbb44504SDaniel P. Berrangé * When that callback returns @task will be freed, 263dbb44504SDaniel P. Berrangé * so @task must not be referenced after this 264dbb44504SDaniel P. Berrangé * method completes. 265dbb44504SDaniel P. Berrangé */ 266dbb44504SDaniel P. Berrangé void qio_task_wait_thread(QIOTask *task); 267dbb44504SDaniel P. Berrangé 268dbb44504SDaniel P. Berrangé 269b02db2d9SDaniel P. Berrange /** 270b02db2d9SDaniel P. Berrange * qio_task_complete: 271b02db2d9SDaniel P. Berrange * @task: the task struct 272b02db2d9SDaniel P. Berrange * 27360e705c5SDaniel P. Berrange * Invoke the completion callback for @task and 27460e705c5SDaniel P. Berrange * then free its memory. 275b02db2d9SDaniel P. Berrange */ 276b02db2d9SDaniel P. Berrange void qio_task_complete(QIOTask *task); 277b02db2d9SDaniel P. Berrange 278b02db2d9SDaniel P. Berrange 279b02db2d9SDaniel P. Berrange /** 2801a447e4fSDaniel P. Berrange * qio_task_set_error: 2811a447e4fSDaniel P. Berrange * @task: the task struct 2821a447e4fSDaniel P. Berrange * @err: pointer to the error, or NULL 2831a447e4fSDaniel P. Berrange * 2841a447e4fSDaniel P. Berrange * Associate an error with the task, which can later 2851a447e4fSDaniel P. Berrange * be retrieved with the qio_task_propagate_error() 2861a447e4fSDaniel P. Berrange * method. This method takes ownership of @err, so 2871a447e4fSDaniel P. Berrange * it is not valid to access it after this call 2881a447e4fSDaniel P. Berrange * completes. If @err is NULL this is a no-op. If 2891a447e4fSDaniel P. Berrange * this is call multiple times, only the first 2901a447e4fSDaniel P. Berrange * provided @err will be recorded, later ones will 2911a447e4fSDaniel P. Berrange * be discarded and freed. 2921a447e4fSDaniel P. Berrange */ 2931a447e4fSDaniel P. Berrange void qio_task_set_error(QIOTask *task, 2941a447e4fSDaniel P. Berrange Error *err); 2951a447e4fSDaniel P. Berrange 2961a447e4fSDaniel P. Berrange 2971a447e4fSDaniel P. Berrange /** 2981a447e4fSDaniel P. Berrange * qio_task_propagate_error: 2991a447e4fSDaniel P. Berrange * @task: the task struct 3001a447e4fSDaniel P. Berrange * @errp: pointer to a NULL-initialized error object 3011a447e4fSDaniel P. Berrange * 3021a447e4fSDaniel P. Berrange * Propagate the error associated with @task 3031a447e4fSDaniel P. Berrange * into @errp. 3041a447e4fSDaniel P. Berrange * 3051a447e4fSDaniel P. Berrange * Returns: true if an error was propagated, false otherwise 3061a447e4fSDaniel P. Berrange */ 3071a447e4fSDaniel P. Berrange bool qio_task_propagate_error(QIOTask *task, 3081a447e4fSDaniel P. Berrange Error **errp); 3091a447e4fSDaniel P. Berrange 3101a447e4fSDaniel P. Berrange 3111a447e4fSDaniel P. Berrange /** 31252dd99e8SDaniel P. Berrange * qio_task_set_result_pointer: 31352dd99e8SDaniel P. Berrange * @task: the task struct 31452dd99e8SDaniel P. Berrange * @result: pointer to the result data 31552dd99e8SDaniel P. Berrange * 31652dd99e8SDaniel P. Berrange * Associate an opaque result with the task, 31752dd99e8SDaniel P. Berrange * which can later be retrieved with the 31852dd99e8SDaniel P. Berrange * qio_task_get_result_pointer() method 31952dd99e8SDaniel P. Berrange * 32052dd99e8SDaniel P. Berrange */ 32152dd99e8SDaniel P. Berrange void qio_task_set_result_pointer(QIOTask *task, 32252dd99e8SDaniel P. Berrange gpointer result, 32352dd99e8SDaniel P. Berrange GDestroyNotify notify); 32452dd99e8SDaniel P. Berrange 32552dd99e8SDaniel P. Berrange 32652dd99e8SDaniel P. Berrange /** 32752dd99e8SDaniel P. Berrange * qio_task_get_result_pointer: 32852dd99e8SDaniel P. Berrange * @task: the task struct 32952dd99e8SDaniel P. Berrange * 33052dd99e8SDaniel P. Berrange * Retrieve the opaque result data associated 33152dd99e8SDaniel P. Berrange * with the task, if any. 33252dd99e8SDaniel P. Berrange * 33352dd99e8SDaniel P. Berrange * Returns: the task result, or NULL 33452dd99e8SDaniel P. Berrange */ 33552dd99e8SDaniel P. Berrange gpointer qio_task_get_result_pointer(QIOTask *task); 33652dd99e8SDaniel P. Berrange 33752dd99e8SDaniel P. Berrange 33852dd99e8SDaniel P. Berrange /** 339b02db2d9SDaniel P. Berrange * qio_task_get_source: 340b02db2d9SDaniel P. Berrange * @task: the task struct 341b02db2d9SDaniel P. Berrange * 342b02db2d9SDaniel P. Berrange * Get the source object associated with the background 343937470bbSDaniel P. Berrange * task. The caller does not own a reference on the 344937470bbSDaniel P. Berrange * returned Object, and so should call object_ref() 345937470bbSDaniel P. Berrange * if it wants to keep the object pointer outside the 346937470bbSDaniel P. Berrange * lifetime of the QIOTask object. 347b02db2d9SDaniel P. Berrange * 348b02db2d9SDaniel P. Berrange * Returns: the source object 349b02db2d9SDaniel P. Berrange */ 350b02db2d9SDaniel P. Berrange Object *qio_task_get_source(QIOTask *task); 351b02db2d9SDaniel P. Berrange 3522a6a4076SMarkus Armbruster #endif /* QIO_TASK_H */ 353