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