xref: /qemu/include/io/task.h (revision e4eb089c62fa7b1e758a895aec7682b4bed6a360)
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