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