xref: /openbmc/qemu/include/io/task.h (revision ac1d8878)
1 /*
2  * QEMU I/O task
3  *
4  * Copyright (c) 2015 Red Hat, Inc.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 #ifndef QIO_TASK_H__
22 #define QIO_TASK_H__
23 
24 #include "qemu-common.h"
25 #include "qapi/error.h"
26 #include "qom/object.h"
27 
28 typedef struct QIOTask QIOTask;
29 
30 typedef void (*QIOTaskFunc)(Object *source,
31                             Error *err,
32                             gpointer opaque);
33 
34 typedef int (*QIOTaskWorker)(QIOTask *task,
35                              Error **errp,
36                              gpointer opaque);
37 
38 /**
39  * QIOTask:
40  *
41  * The QIOTask object provides a simple mechanism for reporting
42  * success / failure of long running background operations.
43  *
44  * A object on which the operation is to be performed could have
45  * a public API which accepts a task callback:
46  *
47  * <example>
48  *   <title>Task callback function signature</title>
49  *   <programlisting>
50  *  void myobject_operation(QMyObject *obj,
51  *                          QIOTaskFunc *func,
52  *                          gpointer opaque,
53  *                          GDestroyNotify *notify);
54  *   </programlisting>
55  * </example>
56  *
57  * The 'func' parameter is the callback to be invoked, and 'opaque'
58  * is data to pass to it. The optional 'notify' function is used
59  * to free 'opaque' when no longer needed.
60  *
61  * Now, lets say the implementation of this method wants to set
62  * a timer to run once a second checking for completion of some
63  * activity. It would do something like
64  *
65  * <example>
66  *   <title>Task callback function implementation</title>
67  *   <programlisting>
68  *    void myobject_operation(QMyObject *obj,
69  *                            QIOTaskFunc *func,
70  *                            gpointer opaque,
71  *                            GDestroyNotify *notify)
72  *    {
73  *      QIOTask *task;
74  *
75  *      task = qio_task_new(OBJECT(obj), func, opaque, notify);
76  *
77  *      g_timeout_add_full(G_PRIORITY_DEFAULT,
78  *                         1000,
79  *                         myobject_operation_timer,
80  *                         task,
81  *                         NULL);
82  *    }
83  *   </programlisting>
84  * </example>
85  *
86  * It could equally have setup a watch on a file descriptor or
87  * created a background thread, or something else entirely.
88  * Notice that the source object is passed to the task, and
89  * QIOTask will hold a reference on that. This ensure that
90  * the QMyObject instance cannot be garbage collected while
91  * the async task is still in progress.
92  *
93  * In this case, myobject_operation_timer will fire after
94  * 3 secs and do
95  *
96  * <example>
97  *   <title>Task timer function</title>
98  *   <programlisting>
99  *   gboolean myobject_operation_timer(gpointer opaque)
100  *   {
101  *      QIOTask *task = QIO_TASK(opaque);
102  *      Error *err;*
103  *
104  *      ...check something important...
105  *       if (err) {
106  *           qio_task_abort(task, err);
107  *           error_free(task);
108  *           return FALSE;
109  *       } else if (...work is completed ...) {
110  *           qio_task_complete(task);
111  *           return FALSE;
112  *       }
113  *       ...carry on polling ...
114  *       return TRUE;
115  *   }
116  *   </programlisting>
117  * </example>
118  *
119  * Once this function returns false, object_unref will be called
120  * automatically on the task causing it to be released and the
121  * ref on QMyObject dropped too.
122  *
123  * The QIOTask module can also be used to perform operations
124  * in a background thread context, while still reporting the
125  * results in the main event thread. This allows code which
126  * cannot easily be rewritten to be asychronous (such as DNS
127  * lookups) to be easily run non-blocking. Reporting the
128  * results in the main thread context means that the caller
129  * typically does not need to be concerned about thread
130  * safety wrt the QEMU global mutex.
131  *
132  * For example, the socket_listen() method will block the caller
133  * while DNS lookups take place if given a name, instead of IP
134  * address. The C library often do not provide a practical async
135  * DNS API, so the to get non-blocking DNS lookups in a portable
136  * manner requires use of a thread. So achieve a non-blocking
137  * socket listen using QIOTask would require:
138  *
139  * <example>
140  *    static int myobject_listen_worker(QIOTask *task,
141  *                                      Error **errp,
142  *                                      gpointer opaque)
143  *    {
144  *       QMyObject obj = QMY_OBJECT(qio_task_get_source(task));
145  *       SocketAddress *addr = opaque;
146  *
147  *       obj->fd = socket_listen(addr, errp);
148  *       if (obj->fd < 0) {
149  *          return -1;
150  *       }
151  *       return 0;
152  *    }
153  *
154  *    void myobject_listen_async(QMyObject *obj,
155  *                               SocketAddress *addr,
156  *                               QIOTaskFunc *func,
157  *                               gpointer opaque,
158  *                               GDestroyNotify *notify)
159  *    {
160  *      QIOTask *task;
161  *      SocketAddress *addrCopy;
162  *
163  *      qapi_copy_SocketAddress(&addrCopy, addr);
164  *      task = qio_task_new(OBJECT(obj), func, opaque, notify);
165  *
166  *      qio_task_run_in_thread(task, myobject_listen_worker,
167  *                             addrCopy,
168  *                             qapi_free_SocketAddress);
169  *    }
170  * </example>
171  *
172  * NB, The 'func' callback passed into myobject_listen_async
173  * will be invoked from the main event thread, despite the
174  * actual operation being performed in a different thread.
175  */
176 
177 /**
178  * qio_task_new:
179  * @source: the object on which the operation is invoked
180  * @func: the callback to invoke when the task completes
181  * @opaque: opaque data to pass to @func when invoked
182  * @destroy: optional callback to free @opaque
183  *
184  * Creates a new task struct to track completion of a
185  * background operation running on the object @source.
186  * When the operation completes or fails, the callback
187  * @func will be invoked. The callback can access the
188  * 'err' attribute in the task object to determine if
189  * the operation was successful or not.
190  *
191  * The returned task will be released when one of
192  * qio_task_abort() or qio_task_complete() are invoked.
193  *
194  * Returns: the task struct
195  */
196 QIOTask *qio_task_new(Object *source,
197                       QIOTaskFunc func,
198                       gpointer opaque,
199                       GDestroyNotify destroy);
200 
201 /**
202  * qio_task_run_in_thread:
203  * @task: the task struct
204  * @worker: the function to invoke in a thread
205  * @opaque: opaque data to pass to @worker
206  * @destroy: function to free @opaque
207  *
208  * Run a task in a background thread. If @worker
209  * returns 0 it will call qio_task_complete() in
210  * the main event thread context. If @worker
211  * returns -1 it will call qio_task_abort() in
212  * the main event thread context.
213  */
214 void qio_task_run_in_thread(QIOTask *task,
215                             QIOTaskWorker worker,
216                             gpointer opaque,
217                             GDestroyNotify destroy);
218 
219 /**
220  * qio_task_complete:
221  * @task: the task struct
222  *
223  * Mark the operation as succesfully completed
224  * and free the memory for @task.
225  */
226 void qio_task_complete(QIOTask *task);
227 
228 /**
229  * qio_task_abort:
230  * @task: the task struct
231  * @err: the error to record for the operation
232  *
233  * Mark the operation as failed, with @err providing
234  * details about the failure. The @err may be freed
235  * afer the function returns, as the notification
236  * callback is invoked synchronously. The @task will
237  * be freed when this call completes.
238  */
239 void qio_task_abort(QIOTask *task,
240                     Error *err);
241 
242 
243 /**
244  * qio_task_get_source:
245  * @task: the task struct
246  *
247  * Get the source object associated with the background
248  * task. This returns a new reference to the object,
249  * which the caller must released with object_unref()
250  * when no longer required.
251  *
252  * Returns: the source object
253  */
254 Object *qio_task_get_source(QIOTask *task);
255 
256 #endif /* QIO_TASK_H__ */
257