]>
Commit | Line | Data |
---|---|---|
b02db2d9 DB |
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 | ||
2a6a4076 MA |
21 | #ifndef QIO_TASK_H |
22 | #define QIO_TASK_H | |
b02db2d9 | 23 | |
b02db2d9 DB |
24 | #include "qom/object.h" |
25 | ||
26 | typedef struct QIOTask QIOTask; | |
27 | ||
60e705c5 | 28 | typedef void (*QIOTaskFunc)(QIOTask *task, |
b02db2d9 DB |
29 | gpointer opaque); |
30 | ||
59de517d DB |
31 | typedef void (*QIOTaskWorker)(QIOTask *task, |
32 | gpointer opaque); | |
b02db2d9 DB |
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> | |
60e705c5 | 44 | * <title>Task function signature</title> |
b02db2d9 DB |
45 | * <programlisting> |
46 | * void myobject_operation(QMyObject *obj, | |
47 | * QIOTaskFunc *func, | |
48 | * gpointer opaque, | |
e8c8adec | 49 | * GDestroyNotify notify); |
b02db2d9 DB |
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 | * | |
60e705c5 DB |
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 | |
b02db2d9 DB |
61 | * |
62 | * <example> | |
60e705c5 DB |
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> | |
b02db2d9 DB |
87 | * <programlisting> |
88 | * void myobject_operation(QMyObject *obj, | |
89 | * QIOTaskFunc *func, | |
90 | * gpointer opaque, | |
e8c8adec | 91 | * GDestroyNotify notify) |
b02db2d9 DB |
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) { | |
60e705c5 DB |
126 | * qio_task_set_error(task, err); |
127 | * qio_task_complete(task); | |
b02db2d9 DB |
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 | * | |
60e705c5 DB |
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 | * | |
b02db2d9 DB |
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> | |
59de517d DB |
164 | * static void myobject_listen_worker(QIOTask *task, |
165 | * gpointer opaque) | |
b02db2d9 DB |
166 | * { |
167 | * QMyObject obj = QMY_OBJECT(qio_task_get_source(task)); | |
168 | * SocketAddress *addr = opaque; | |
59de517d | 169 | * Error *err = NULL; |
b02db2d9 | 170 | * |
59de517d DB |
171 | * obj->fd = socket_listen(addr, &err); |
172 | * | |
173 | qio_task_set_error(task, err); | |
b02db2d9 DB |
174 | * } |
175 | * | |
176 | * void myobject_listen_async(QMyObject *obj, | |
177 | * SocketAddress *addr, | |
178 | * QIOTaskFunc *func, | |
179 | * gpointer opaque, | |
e8c8adec | 180 | * GDestroyNotify notify) |
b02db2d9 DB |
181 | * { |
182 | * QIOTask *task; | |
183 | * SocketAddress *addrCopy; | |
184 | * | |
37f9e0a2 | 185 | * addrCopy = QAPI_CLONE(SocketAddress, addr); |
b02db2d9 DB |
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 | * | |
60e705c5 DB |
213 | * The returned task will be released when qio_task_complete() |
214 | * is invoked. | |
b02db2d9 DB |
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 | |
a17536c5 PX |
229 | * @context: the context to run the complete hook. If %NULL, the |
230 | * default context will be used. | |
b02db2d9 | 231 | * |
60e705c5 DB |
232 | * Run a task in a background thread. When @worker |
233 | * returns it will call qio_task_complete() in | |
dbb44504 DB |
234 | * the thread that is running the main loop associated |
235 | * with @context. | |
b02db2d9 DB |
236 | */ |
237 | void qio_task_run_in_thread(QIOTask *task, | |
238 | QIOTaskWorker worker, | |
239 | gpointer opaque, | |
a17536c5 PX |
240 | GDestroyNotify destroy, |
241 | GMainContext *context); | |
b02db2d9 | 242 | |
dbb44504 DB |
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 | ||
b02db2d9 DB |
269 | /** |
270 | * qio_task_complete: | |
271 | * @task: the task struct | |
272 | * | |
60e705c5 DB |
273 | * Invoke the completion callback for @task and |
274 | * then free its memory. | |
b02db2d9 DB |
275 | */ |
276 | void qio_task_complete(QIOTask *task); | |
277 | ||
b02db2d9 | 278 | |
1a447e4f DB |
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 | ||
52dd99e8 DB |
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 | ||
b02db2d9 DB |
338 | /** |
339 | * qio_task_get_source: | |
340 | * @task: the task struct | |
341 | * | |
342 | * Get the source object associated with the background | |
937470bb DB |
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. | |
b02db2d9 DB |
347 | * |
348 | * Returns: the source object | |
349 | */ | |
350 | Object *qio_task_get_source(QIOTask *task); | |
351 | ||
2a6a4076 | 352 | #endif /* QIO_TASK_H */ |