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