xref: /openbmc/qemu/include/io/task.h (revision 0dacec87)
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 "qom/object.h"
26 
27 typedef struct QIOTask QIOTask;
28 
29 typedef void (*QIOTaskFunc)(QIOTask *task,
30                             gpointer opaque);
31 
32 typedef void (*QIOTaskWorker)(QIOTask *task,
33                               gpointer opaque);
34 
35 /**
36  * QIOTask:
37  *
38  * The QIOTask object provides a simple mechanism for reporting
39  * success / failure of long running background operations.
40  *
41  * A object on which the operation is to be performed could have
42  * a public API which accepts a task callback:
43  *
44  * <example>
45  *   <title>Task function signature</title>
46  *   <programlisting>
47  *  void myobject_operation(QMyObject *obj,
48  *                          QIOTaskFunc *func,
49  *                          gpointer opaque,
50  *                          GDestroyNotify notify);
51  *   </programlisting>
52  * </example>
53  *
54  * The 'func' parameter is the callback to be invoked, and 'opaque'
55  * is data to pass to it. The optional 'notify' function is used
56  * to free 'opaque' when no longer needed.
57  *
58  * When the operation completes, the 'func' callback will be
59  * invoked, allowing the calling code to determine the result
60  * of the operation. An example QIOTaskFunc implementation may
61  * look like
62  *
63  * <example>
64  *   <title>Task callback implementation</title>
65  *   <programlisting>
66  *  static void myobject_operation_notify(QIOTask *task,
67  *                                        gpointer opaque)
68  *  {
69  *      Error *err = NULL;
70  *      if (qio_task_propagate_error(task, &err)) {
71  *          ...deal with the failure...
72  *          error_free(err);
73  *      } else {
74  *          QMyObject *src = QMY_OBJECT(qio_task_get_source(task));
75  *          ...deal with the completion...
76  *      }
77  *  }
78  *   </programlisting>
79  * </example>
80  *
81  * Now, lets say the implementation of the method using the
82  * task wants to set a timer to run once a second checking
83  * for completion of some activity. It would do something
84  * like
85  *
86  * <example>
87  *   <title>Task function implementation</title>
88  *   <programlisting>
89  *    void myobject_operation(QMyObject *obj,
90  *                            QIOTaskFunc *func,
91  *                            gpointer opaque,
92  *                            GDestroyNotify notify)
93  *    {
94  *      QIOTask *task;
95  *
96  *      task = qio_task_new(OBJECT(obj), func, opaque, notify);
97  *
98  *      g_timeout_add_full(G_PRIORITY_DEFAULT,
99  *                         1000,
100  *                         myobject_operation_timer,
101  *                         task,
102  *                         NULL);
103  *    }
104  *   </programlisting>
105  * </example>
106  *
107  * It could equally have setup a watch on a file descriptor or
108  * created a background thread, or something else entirely.
109  * Notice that the source object is passed to the task, and
110  * QIOTask will hold a reference on that. This ensure that
111  * the QMyObject instance cannot be garbage collected while
112  * the async task is still in progress.
113  *
114  * In this case, myobject_operation_timer will fire after
115  * 3 secs and do
116  *
117  * <example>
118  *   <title>Task timer function</title>
119  *   <programlisting>
120  *   gboolean myobject_operation_timer(gpointer opaque)
121  *   {
122  *      QIOTask *task = QIO_TASK(opaque);
123  *      Error *err;*
124  *
125  *      ...check something important...
126  *       if (err) {
127  *           qio_task_set_error(task, err);
128  *           qio_task_complete(task);
129  *           return FALSE;
130  *       } else if (...work is completed ...) {
131  *           qio_task_complete(task);
132  *           return FALSE;
133  *       }
134  *       ...carry on polling ...
135  *       return TRUE;
136  *   }
137  *   </programlisting>
138  * </example>
139  *
140  * The 'qio_task_complete' call in this method will trigger
141  * the callback func 'myobject_operation_notify' shown
142  * earlier to deal with the results.
143  *
144  * Once this function returns false, object_unref will be called
145  * automatically on the task causing it to be released and the
146  * ref on QMyObject dropped too.
147  *
148  * The QIOTask module can also be used to perform operations
149  * in a background thread context, while still reporting the
150  * results in the main event thread. This allows code which
151  * cannot easily be rewritten to be asychronous (such as DNS
152  * lookups) to be easily run non-blocking. Reporting the
153  * results in the main thread context means that the caller
154  * typically does not need to be concerned about thread
155  * safety wrt the QEMU global mutex.
156  *
157  * For example, the socket_listen() method will block the caller
158  * while DNS lookups take place if given a name, instead of IP
159  * address. The C library often do not provide a practical async
160  * DNS API, so the to get non-blocking DNS lookups in a portable
161  * manner requires use of a thread. So achieve a non-blocking
162  * socket listen using QIOTask would require:
163  *
164  * <example>
165  *    static void myobject_listen_worker(QIOTask *task,
166  *                                       gpointer opaque)
167  *    {
168  *       QMyObject obj = QMY_OBJECT(qio_task_get_source(task));
169  *       SocketAddress *addr = opaque;
170  *       Error *err = NULL;
171  *
172  *       obj->fd = socket_listen(addr, &err);
173  *
174          qio_task_set_error(task, err);
175  *    }
176  *
177  *    void myobject_listen_async(QMyObject *obj,
178  *                               SocketAddress *addr,
179  *                               QIOTaskFunc *func,
180  *                               gpointer opaque,
181  *                               GDestroyNotify notify)
182  *    {
183  *      QIOTask *task;
184  *      SocketAddress *addrCopy;
185  *
186  *      addrCopy = QAPI_CLONE(SocketAddress, addr);
187  *      task = qio_task_new(OBJECT(obj), func, opaque, notify);
188  *
189  *      qio_task_run_in_thread(task, myobject_listen_worker,
190  *                             addrCopy,
191  *                             qapi_free_SocketAddress);
192  *    }
193  * </example>
194  *
195  * NB, The 'func' callback passed into myobject_listen_async
196  * will be invoked from the main event thread, despite the
197  * actual operation being performed in a different thread.
198  */
199 
200 /**
201  * qio_task_new:
202  * @source: the object on which the operation is invoked
203  * @func: the callback to invoke when the task completes
204  * @opaque: opaque data to pass to @func when invoked
205  * @destroy: optional callback to free @opaque
206  *
207  * Creates a new task struct to track completion of a
208  * background operation running on the object @source.
209  * When the operation completes or fails, the callback
210  * @func will be invoked. The callback can access the
211  * 'err' attribute in the task object to determine if
212  * the operation was successful or not.
213  *
214  * The returned task will be released when qio_task_complete()
215  * is invoked.
216  *
217  * Returns: the task struct
218  */
219 QIOTask *qio_task_new(Object *source,
220                       QIOTaskFunc func,
221                       gpointer opaque,
222                       GDestroyNotify destroy);
223 
224 /**
225  * qio_task_run_in_thread:
226  * @task: the task struct
227  * @worker: the function to invoke in a thread
228  * @opaque: opaque data to pass to @worker
229  * @destroy: function to free @opaque
230  * @context: the context to run the complete hook. If %NULL, the
231  *           default context will be used.
232  *
233  * Run a task in a background thread. When @worker
234  * returns it will call qio_task_complete() in
235  * the event thread context that provided.
236  */
237 void qio_task_run_in_thread(QIOTask *task,
238                             QIOTaskWorker worker,
239                             gpointer opaque,
240                             GDestroyNotify destroy,
241                             GMainContext *context);
242 
243 /**
244  * qio_task_complete:
245  * @task: the task struct
246  *
247  * Invoke the completion callback for @task and
248  * then free its memory.
249  */
250 void qio_task_complete(QIOTask *task);
251 
252 
253 /**
254  * qio_task_set_error:
255  * @task: the task struct
256  * @err: pointer to the error, or NULL
257  *
258  * Associate an error with the task, which can later
259  * be retrieved with the qio_task_propagate_error()
260  * method. This method takes ownership of @err, so
261  * it is not valid to access it after this call
262  * completes. If @err is NULL this is a no-op. If
263  * this is call multiple times, only the first
264  * provided @err will be recorded, later ones will
265  * be discarded and freed.
266  */
267 void qio_task_set_error(QIOTask *task,
268                         Error *err);
269 
270 
271 /**
272  * qio_task_propagate_error:
273  * @task: the task struct
274  * @errp: pointer to a NULL-initialized error object
275  *
276  * Propagate the error associated with @task
277  * into @errp.
278  *
279  * Returns: true if an error was propagated, false otherwise
280  */
281 bool qio_task_propagate_error(QIOTask *task,
282                               Error **errp);
283 
284 
285 /**
286  * qio_task_set_result_pointer:
287  * @task: the task struct
288  * @result: pointer to the result data
289  *
290  * Associate an opaque result with the task,
291  * which can later be retrieved with the
292  * qio_task_get_result_pointer() method
293  *
294  */
295 void qio_task_set_result_pointer(QIOTask *task,
296                                  gpointer result,
297                                  GDestroyNotify notify);
298 
299 
300 /**
301  * qio_task_get_result_pointer:
302  * @task: the task struct
303  *
304  * Retrieve the opaque result data associated
305  * with the task, if any.
306  *
307  * Returns: the task result, or NULL
308  */
309 gpointer qio_task_get_result_pointer(QIOTask *task);
310 
311 
312 /**
313  * qio_task_get_source:
314  * @task: the task struct
315  *
316  * Get the source object associated with the background
317  * task. The caller does not own a reference on the
318  * returned Object, and so should call object_ref()
319  * if it wants to keep the object pointer outside the
320  * lifetime of the QIOTask object.
321  *
322  * Returns: the source object
323  */
324 Object *qio_task_get_source(QIOTask *task);
325 
326 #endif /* QIO_TASK_H */
327