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