xref: /qemu/include/io/task.h (revision a17536c594bfed94d05667b419f747b692f5fc7f)
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 
2960e705c5SDaniel P. Berrange typedef void (*QIOTaskFunc)(QIOTask *task,
30b02db2d9SDaniel P. Berrange                             gpointer opaque);
31b02db2d9SDaniel P. Berrange 
3259de517dSDaniel P. Berrange typedef void (*QIOTaskWorker)(QIOTask *task,
33b02db2d9SDaniel P. Berrange                               gpointer opaque);
34b02db2d9SDaniel P. Berrange 
35b02db2d9SDaniel P. Berrange /**
36b02db2d9SDaniel P. Berrange  * QIOTask:
37b02db2d9SDaniel P. Berrange  *
38b02db2d9SDaniel P. Berrange  * The QIOTask object provides a simple mechanism for reporting
39b02db2d9SDaniel P. Berrange  * success / failure of long running background operations.
40b02db2d9SDaniel P. Berrange  *
41b02db2d9SDaniel P. Berrange  * A object on which the operation is to be performed could have
42b02db2d9SDaniel P. Berrange  * a public API which accepts a task callback:
43b02db2d9SDaniel P. Berrange  *
44b02db2d9SDaniel P. Berrange  * <example>
4560e705c5SDaniel P. Berrange  *   <title>Task function signature</title>
46b02db2d9SDaniel P. Berrange  *   <programlisting>
47b02db2d9SDaniel P. Berrange  *  void myobject_operation(QMyObject *obj,
48b02db2d9SDaniel P. Berrange  *                          QIOTaskFunc *func,
49b02db2d9SDaniel P. Berrange  *                          gpointer opaque,
50e8c8adecSDaniel P. Berrange  *                          GDestroyNotify notify);
51b02db2d9SDaniel P. Berrange  *   </programlisting>
52b02db2d9SDaniel P. Berrange  * </example>
53b02db2d9SDaniel P. Berrange  *
54b02db2d9SDaniel P. Berrange  * The 'func' parameter is the callback to be invoked, and 'opaque'
55b02db2d9SDaniel P. Berrange  * is data to pass to it. The optional 'notify' function is used
56b02db2d9SDaniel P. Berrange  * to free 'opaque' when no longer needed.
57b02db2d9SDaniel P. Berrange  *
5860e705c5SDaniel P. Berrange  * When the operation completes, the 'func' callback will be
5960e705c5SDaniel P. Berrange  * invoked, allowing the calling code to determine the result
6060e705c5SDaniel P. Berrange  * of the operation. An example QIOTaskFunc implementation may
6160e705c5SDaniel P. Berrange  * look like
62b02db2d9SDaniel P. Berrange  *
63b02db2d9SDaniel P. Berrange  * <example>
6460e705c5SDaniel P. Berrange  *   <title>Task callback implementation</title>
6560e705c5SDaniel P. Berrange  *   <programlisting>
6660e705c5SDaniel P. Berrange  *  static void myobject_operation_notify(QIOTask *task,
6760e705c5SDaniel P. Berrange  *                                        gpointer opaque)
6860e705c5SDaniel P. Berrange  *  {
6960e705c5SDaniel P. Berrange  *      Error *err = NULL;
7060e705c5SDaniel P. Berrange  *      if (qio_task_propagate_error(task, &err)) {
7160e705c5SDaniel P. Berrange  *          ...deal with the failure...
7260e705c5SDaniel P. Berrange  *          error_free(err);
7360e705c5SDaniel P. Berrange  *      } else {
7460e705c5SDaniel P. Berrange  *          QMyObject *src = QMY_OBJECT(qio_task_get_source(task));
7560e705c5SDaniel P. Berrange  *          ...deal with the completion...
7660e705c5SDaniel P. Berrange  *      }
7760e705c5SDaniel P. Berrange  *  }
7860e705c5SDaniel P. Berrange  *   </programlisting>
7960e705c5SDaniel P. Berrange  * </example>
8060e705c5SDaniel P. Berrange  *
8160e705c5SDaniel P. Berrange  * Now, lets say the implementation of the method using the
8260e705c5SDaniel P. Berrange  * task wants to set a timer to run once a second checking
8360e705c5SDaniel P. Berrange  * for completion of some activity. It would do something
8460e705c5SDaniel P. Berrange  * like
8560e705c5SDaniel P. Berrange  *
8660e705c5SDaniel P. Berrange  * <example>
8760e705c5SDaniel P. Berrange  *   <title>Task function implementation</title>
88b02db2d9SDaniel P. Berrange  *   <programlisting>
89b02db2d9SDaniel P. Berrange  *    void myobject_operation(QMyObject *obj,
90b02db2d9SDaniel P. Berrange  *                            QIOTaskFunc *func,
91b02db2d9SDaniel P. Berrange  *                            gpointer opaque,
92e8c8adecSDaniel P. Berrange  *                            GDestroyNotify notify)
93b02db2d9SDaniel P. Berrange  *    {
94b02db2d9SDaniel P. Berrange  *      QIOTask *task;
95b02db2d9SDaniel P. Berrange  *
96b02db2d9SDaniel P. Berrange  *      task = qio_task_new(OBJECT(obj), func, opaque, notify);
97b02db2d9SDaniel P. Berrange  *
98b02db2d9SDaniel P. Berrange  *      g_timeout_add_full(G_PRIORITY_DEFAULT,
99b02db2d9SDaniel P. Berrange  *                         1000,
100b02db2d9SDaniel P. Berrange  *                         myobject_operation_timer,
101b02db2d9SDaniel P. Berrange  *                         task,
102b02db2d9SDaniel P. Berrange  *                         NULL);
103b02db2d9SDaniel P. Berrange  *    }
104b02db2d9SDaniel P. Berrange  *   </programlisting>
105b02db2d9SDaniel P. Berrange  * </example>
106b02db2d9SDaniel P. Berrange  *
107b02db2d9SDaniel P. Berrange  * It could equally have setup a watch on a file descriptor or
108b02db2d9SDaniel P. Berrange  * created a background thread, or something else entirely.
109b02db2d9SDaniel P. Berrange  * Notice that the source object is passed to the task, and
110b02db2d9SDaniel P. Berrange  * QIOTask will hold a reference on that. This ensure that
111b02db2d9SDaniel P. Berrange  * the QMyObject instance cannot be garbage collected while
112b02db2d9SDaniel P. Berrange  * the async task is still in progress.
113b02db2d9SDaniel P. Berrange  *
114b02db2d9SDaniel P. Berrange  * In this case, myobject_operation_timer will fire after
115b02db2d9SDaniel P. Berrange  * 3 secs and do
116b02db2d9SDaniel P. Berrange  *
117b02db2d9SDaniel P. Berrange  * <example>
118b02db2d9SDaniel P. Berrange  *   <title>Task timer function</title>
119b02db2d9SDaniel P. Berrange  *   <programlisting>
120b02db2d9SDaniel P. Berrange  *   gboolean myobject_operation_timer(gpointer opaque)
121b02db2d9SDaniel P. Berrange  *   {
122b02db2d9SDaniel P. Berrange  *      QIOTask *task = QIO_TASK(opaque);
123b02db2d9SDaniel P. Berrange  *      Error *err;*
124b02db2d9SDaniel P. Berrange  *
125b02db2d9SDaniel P. Berrange  *      ...check something important...
126b02db2d9SDaniel P. Berrange  *       if (err) {
12760e705c5SDaniel P. Berrange  *           qio_task_set_error(task, err);
12860e705c5SDaniel P. Berrange  *           qio_task_complete(task);
129b02db2d9SDaniel P. Berrange  *           return FALSE;
130b02db2d9SDaniel P. Berrange  *       } else if (...work is completed ...) {
131b02db2d9SDaniel P. Berrange  *           qio_task_complete(task);
132b02db2d9SDaniel P. Berrange  *           return FALSE;
133b02db2d9SDaniel P. Berrange  *       }
134b02db2d9SDaniel P. Berrange  *       ...carry on polling ...
135b02db2d9SDaniel P. Berrange  *       return TRUE;
136b02db2d9SDaniel P. Berrange  *   }
137b02db2d9SDaniel P. Berrange  *   </programlisting>
138b02db2d9SDaniel P. Berrange  * </example>
139b02db2d9SDaniel P. Berrange  *
14060e705c5SDaniel P. Berrange  * The 'qio_task_complete' call in this method will trigger
14160e705c5SDaniel P. Berrange  * the callback func 'myobject_operation_notify' shown
14260e705c5SDaniel P. Berrange  * earlier to deal with the results.
14360e705c5SDaniel P. Berrange  *
144b02db2d9SDaniel P. Berrange  * Once this function returns false, object_unref will be called
145b02db2d9SDaniel P. Berrange  * automatically on the task causing it to be released and the
146b02db2d9SDaniel P. Berrange  * ref on QMyObject dropped too.
147b02db2d9SDaniel P. Berrange  *
148b02db2d9SDaniel P. Berrange  * The QIOTask module can also be used to perform operations
149b02db2d9SDaniel P. Berrange  * in a background thread context, while still reporting the
150b02db2d9SDaniel P. Berrange  * results in the main event thread. This allows code which
151b02db2d9SDaniel P. Berrange  * cannot easily be rewritten to be asychronous (such as DNS
152b02db2d9SDaniel P. Berrange  * lookups) to be easily run non-blocking. Reporting the
153b02db2d9SDaniel P. Berrange  * results in the main thread context means that the caller
154b02db2d9SDaniel P. Berrange  * typically does not need to be concerned about thread
155b02db2d9SDaniel P. Berrange  * safety wrt the QEMU global mutex.
156b02db2d9SDaniel P. Berrange  *
157b02db2d9SDaniel P. Berrange  * For example, the socket_listen() method will block the caller
158b02db2d9SDaniel P. Berrange  * while DNS lookups take place if given a name, instead of IP
159b02db2d9SDaniel P. Berrange  * address. The C library often do not provide a practical async
160b02db2d9SDaniel P. Berrange  * DNS API, so the to get non-blocking DNS lookups in a portable
161b02db2d9SDaniel P. Berrange  * manner requires use of a thread. So achieve a non-blocking
162b02db2d9SDaniel P. Berrange  * socket listen using QIOTask would require:
163b02db2d9SDaniel P. Berrange  *
164b02db2d9SDaniel P. Berrange  * <example>
16559de517dSDaniel P. Berrange  *    static void myobject_listen_worker(QIOTask *task,
166b02db2d9SDaniel P. Berrange  *                                       gpointer opaque)
167b02db2d9SDaniel P. Berrange  *    {
168b02db2d9SDaniel P. Berrange  *       QMyObject obj = QMY_OBJECT(qio_task_get_source(task));
169b02db2d9SDaniel P. Berrange  *       SocketAddress *addr = opaque;
17059de517dSDaniel P. Berrange  *       Error *err = NULL;
171b02db2d9SDaniel P. Berrange  *
17259de517dSDaniel P. Berrange  *       obj->fd = socket_listen(addr, &err);
17359de517dSDaniel P. Berrange  *
17459de517dSDaniel P. Berrange          qio_task_set_error(task, err);
175b02db2d9SDaniel P. Berrange  *    }
176b02db2d9SDaniel P. Berrange  *
177b02db2d9SDaniel P. Berrange  *    void myobject_listen_async(QMyObject *obj,
178b02db2d9SDaniel P. Berrange  *                               SocketAddress *addr,
179b02db2d9SDaniel P. Berrange  *                               QIOTaskFunc *func,
180b02db2d9SDaniel P. Berrange  *                               gpointer opaque,
181e8c8adecSDaniel P. Berrange  *                               GDestroyNotify notify)
182b02db2d9SDaniel P. Berrange  *    {
183b02db2d9SDaniel P. Berrange  *      QIOTask *task;
184b02db2d9SDaniel P. Berrange  *      SocketAddress *addrCopy;
185b02db2d9SDaniel P. Berrange  *
18637f9e0a2SEric Blake  *      addrCopy = QAPI_CLONE(SocketAddress, addr);
187b02db2d9SDaniel P. Berrange  *      task = qio_task_new(OBJECT(obj), func, opaque, notify);
188b02db2d9SDaniel P. Berrange  *
189b02db2d9SDaniel P. Berrange  *      qio_task_run_in_thread(task, myobject_listen_worker,
190b02db2d9SDaniel P. Berrange  *                             addrCopy,
191b02db2d9SDaniel P. Berrange  *                             qapi_free_SocketAddress);
192b02db2d9SDaniel P. Berrange  *    }
193b02db2d9SDaniel P. Berrange  * </example>
194b02db2d9SDaniel P. Berrange  *
195b02db2d9SDaniel P. Berrange  * NB, The 'func' callback passed into myobject_listen_async
196b02db2d9SDaniel P. Berrange  * will be invoked from the main event thread, despite the
197b02db2d9SDaniel P. Berrange  * actual operation being performed in a different thread.
198b02db2d9SDaniel P. Berrange  */
199b02db2d9SDaniel P. Berrange 
200b02db2d9SDaniel P. Berrange /**
201b02db2d9SDaniel P. Berrange  * qio_task_new:
202b02db2d9SDaniel P. Berrange  * @source: the object on which the operation is invoked
203b02db2d9SDaniel P. Berrange  * @func: the callback to invoke when the task completes
204b02db2d9SDaniel P. Berrange  * @opaque: opaque data to pass to @func when invoked
205b02db2d9SDaniel P. Berrange  * @destroy: optional callback to free @opaque
206b02db2d9SDaniel P. Berrange  *
207b02db2d9SDaniel P. Berrange  * Creates a new task struct to track completion of a
208b02db2d9SDaniel P. Berrange  * background operation running on the object @source.
209b02db2d9SDaniel P. Berrange  * When the operation completes or fails, the callback
210b02db2d9SDaniel P. Berrange  * @func will be invoked. The callback can access the
211b02db2d9SDaniel P. Berrange  * 'err' attribute in the task object to determine if
212b02db2d9SDaniel P. Berrange  * the operation was successful or not.
213b02db2d9SDaniel P. Berrange  *
21460e705c5SDaniel P. Berrange  * The returned task will be released when qio_task_complete()
21560e705c5SDaniel P. Berrange  * is invoked.
216b02db2d9SDaniel P. Berrange  *
217b02db2d9SDaniel P. Berrange  * Returns: the task struct
218b02db2d9SDaniel P. Berrange  */
219b02db2d9SDaniel P. Berrange QIOTask *qio_task_new(Object *source,
220b02db2d9SDaniel P. Berrange                       QIOTaskFunc func,
221b02db2d9SDaniel P. Berrange                       gpointer opaque,
222b02db2d9SDaniel P. Berrange                       GDestroyNotify destroy);
223b02db2d9SDaniel P. Berrange 
224b02db2d9SDaniel P. Berrange /**
225b02db2d9SDaniel P. Berrange  * qio_task_run_in_thread:
226b02db2d9SDaniel P. Berrange  * @task: the task struct
227b02db2d9SDaniel P. Berrange  * @worker: the function to invoke in a thread
228b02db2d9SDaniel P. Berrange  * @opaque: opaque data to pass to @worker
229b02db2d9SDaniel P. Berrange  * @destroy: function to free @opaque
230*a17536c5SPeter Xu  * @context: the context to run the complete hook. If %NULL, the
231*a17536c5SPeter Xu  *           default context will be used.
232b02db2d9SDaniel P. Berrange  *
23360e705c5SDaniel P. Berrange  * Run a task in a background thread. When @worker
23460e705c5SDaniel P. Berrange  * returns it will call qio_task_complete() in
235*a17536c5SPeter Xu  * the event thread context that provided.
236b02db2d9SDaniel P. Berrange  */
237b02db2d9SDaniel P. Berrange void qio_task_run_in_thread(QIOTask *task,
238b02db2d9SDaniel P. Berrange                             QIOTaskWorker worker,
239b02db2d9SDaniel P. Berrange                             gpointer opaque,
240*a17536c5SPeter Xu                             GDestroyNotify destroy,
241*a17536c5SPeter Xu                             GMainContext *context);
242b02db2d9SDaniel P. Berrange 
243b02db2d9SDaniel P. Berrange /**
244b02db2d9SDaniel P. Berrange  * qio_task_complete:
245b02db2d9SDaniel P. Berrange  * @task: the task struct
246b02db2d9SDaniel P. Berrange  *
24760e705c5SDaniel P. Berrange  * Invoke the completion callback for @task and
24860e705c5SDaniel P. Berrange  * then free its memory.
249b02db2d9SDaniel P. Berrange  */
250b02db2d9SDaniel P. Berrange void qio_task_complete(QIOTask *task);
251b02db2d9SDaniel P. Berrange 
252b02db2d9SDaniel P. Berrange 
253b02db2d9SDaniel P. Berrange /**
2541a447e4fSDaniel P. Berrange  * qio_task_set_error:
2551a447e4fSDaniel P. Berrange  * @task: the task struct
2561a447e4fSDaniel P. Berrange  * @err: pointer to the error, or NULL
2571a447e4fSDaniel P. Berrange  *
2581a447e4fSDaniel P. Berrange  * Associate an error with the task, which can later
2591a447e4fSDaniel P. Berrange  * be retrieved with the qio_task_propagate_error()
2601a447e4fSDaniel P. Berrange  * method. This method takes ownership of @err, so
2611a447e4fSDaniel P. Berrange  * it is not valid to access it after this call
2621a447e4fSDaniel P. Berrange  * completes. If @err is NULL this is a no-op. If
2631a447e4fSDaniel P. Berrange  * this is call multiple times, only the first
2641a447e4fSDaniel P. Berrange  * provided @err will be recorded, later ones will
2651a447e4fSDaniel P. Berrange  * be discarded and freed.
2661a447e4fSDaniel P. Berrange  */
2671a447e4fSDaniel P. Berrange void qio_task_set_error(QIOTask *task,
2681a447e4fSDaniel P. Berrange                         Error *err);
2691a447e4fSDaniel P. Berrange 
2701a447e4fSDaniel P. Berrange 
2711a447e4fSDaniel P. Berrange /**
2721a447e4fSDaniel P. Berrange  * qio_task_propagate_error:
2731a447e4fSDaniel P. Berrange  * @task: the task struct
2741a447e4fSDaniel P. Berrange  * @errp: pointer to a NULL-initialized error object
2751a447e4fSDaniel P. Berrange  *
2761a447e4fSDaniel P. Berrange  * Propagate the error associated with @task
2771a447e4fSDaniel P. Berrange  * into @errp.
2781a447e4fSDaniel P. Berrange  *
2791a447e4fSDaniel P. Berrange  * Returns: true if an error was propagated, false otherwise
2801a447e4fSDaniel P. Berrange  */
2811a447e4fSDaniel P. Berrange bool qio_task_propagate_error(QIOTask *task,
2821a447e4fSDaniel P. Berrange                               Error **errp);
2831a447e4fSDaniel P. Berrange 
2841a447e4fSDaniel P. Berrange 
2851a447e4fSDaniel P. Berrange /**
28652dd99e8SDaniel P. Berrange  * qio_task_set_result_pointer:
28752dd99e8SDaniel P. Berrange  * @task: the task struct
28852dd99e8SDaniel P. Berrange  * @result: pointer to the result data
28952dd99e8SDaniel P. Berrange  *
29052dd99e8SDaniel P. Berrange  * Associate an opaque result with the task,
29152dd99e8SDaniel P. Berrange  * which can later be retrieved with the
29252dd99e8SDaniel P. Berrange  * qio_task_get_result_pointer() method
29352dd99e8SDaniel P. Berrange  *
29452dd99e8SDaniel P. Berrange  */
29552dd99e8SDaniel P. Berrange void qio_task_set_result_pointer(QIOTask *task,
29652dd99e8SDaniel P. Berrange                                  gpointer result,
29752dd99e8SDaniel P. Berrange                                  GDestroyNotify notify);
29852dd99e8SDaniel P. Berrange 
29952dd99e8SDaniel P. Berrange 
30052dd99e8SDaniel P. Berrange /**
30152dd99e8SDaniel P. Berrange  * qio_task_get_result_pointer:
30252dd99e8SDaniel P. Berrange  * @task: the task struct
30352dd99e8SDaniel P. Berrange  *
30452dd99e8SDaniel P. Berrange  * Retrieve the opaque result data associated
30552dd99e8SDaniel P. Berrange  * with the task, if any.
30652dd99e8SDaniel P. Berrange  *
30752dd99e8SDaniel P. Berrange  * Returns: the task result, or NULL
30852dd99e8SDaniel P. Berrange  */
30952dd99e8SDaniel P. Berrange gpointer qio_task_get_result_pointer(QIOTask *task);
31052dd99e8SDaniel P. Berrange 
31152dd99e8SDaniel P. Berrange 
31252dd99e8SDaniel P. Berrange /**
313b02db2d9SDaniel P. Berrange  * qio_task_get_source:
314b02db2d9SDaniel P. Berrange  * @task: the task struct
315b02db2d9SDaniel P. Berrange  *
316b02db2d9SDaniel P. Berrange  * Get the source object associated with the background
317937470bbSDaniel P. Berrange  * task. The caller does not own a reference on the
318937470bbSDaniel P. Berrange  * returned Object, and so should call object_ref()
319937470bbSDaniel P. Berrange  * if it wants to keep the object pointer outside the
320937470bbSDaniel P. Berrange  * lifetime of the QIOTask object.
321b02db2d9SDaniel P. Berrange  *
322b02db2d9SDaniel P. Berrange  * Returns: the source object
323b02db2d9SDaniel P. Berrange  */
324b02db2d9SDaniel P. Berrange Object *qio_task_get_source(QIOTask *task);
325b02db2d9SDaniel P. Berrange 
3262a6a4076SMarkus Armbruster #endif /* QIO_TASK_H */
327