]>
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 DB |
23 | |
24 | #include "qemu-common.h" | |
b02db2d9 DB |
25 | #include "qom/object.h" |
26 | ||
27 | typedef struct QIOTask QIOTask; | |
28 | ||
60e705c5 | 29 | typedef void (*QIOTaskFunc)(QIOTask *task, |
b02db2d9 DB |
30 | gpointer opaque); |
31 | ||
59de517d DB |
32 | typedef void (*QIOTaskWorker)(QIOTask *task, |
33 | gpointer opaque); | |
b02db2d9 DB |
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> | |
60e705c5 | 45 | * <title>Task function signature</title> |
b02db2d9 DB |
46 | * <programlisting> |
47 | * void myobject_operation(QMyObject *obj, | |
48 | * QIOTaskFunc *func, | |
49 | * gpointer opaque, | |
e8c8adec | 50 | * GDestroyNotify notify); |
b02db2d9 DB |
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 | * | |
60e705c5 DB |
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 | |
b02db2d9 DB |
62 | * |
63 | * <example> | |
60e705c5 DB |
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> | |
b02db2d9 DB |
88 | * <programlisting> |
89 | * void myobject_operation(QMyObject *obj, | |
90 | * QIOTaskFunc *func, | |
91 | * gpointer opaque, | |
e8c8adec | 92 | * GDestroyNotify notify) |
b02db2d9 DB |
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) { | |
60e705c5 DB |
127 | * qio_task_set_error(task, err); |
128 | * qio_task_complete(task); | |
b02db2d9 DB |
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 | * | |
60e705c5 DB |
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 | * | |
b02db2d9 DB |
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> | |
59de517d DB |
165 | * static void myobject_listen_worker(QIOTask *task, |
166 | * gpointer opaque) | |
b02db2d9 DB |
167 | * { |
168 | * QMyObject obj = QMY_OBJECT(qio_task_get_source(task)); | |
169 | * SocketAddress *addr = opaque; | |
59de517d | 170 | * Error *err = NULL; |
b02db2d9 | 171 | * |
59de517d DB |
172 | * obj->fd = socket_listen(addr, &err); |
173 | * | |
174 | qio_task_set_error(task, err); | |
b02db2d9 DB |
175 | * } |
176 | * | |
177 | * void myobject_listen_async(QMyObject *obj, | |
178 | * SocketAddress *addr, | |
179 | * QIOTaskFunc *func, | |
180 | * gpointer opaque, | |
e8c8adec | 181 | * GDestroyNotify notify) |
b02db2d9 DB |
182 | * { |
183 | * QIOTask *task; | |
184 | * SocketAddress *addrCopy; | |
185 | * | |
37f9e0a2 | 186 | * addrCopy = QAPI_CLONE(SocketAddress, addr); |
b02db2d9 DB |
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 | * | |
60e705c5 DB |
214 | * The returned task will be released when qio_task_complete() |
215 | * is invoked. | |
b02db2d9 DB |
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 | * | |
60e705c5 DB |
231 | * Run a task in a background thread. When @worker |
232 | * returns it will call qio_task_complete() in | |
b02db2d9 DB |
233 | * the main event thread context. |
234 | */ | |
235 | void qio_task_run_in_thread(QIOTask *task, | |
236 | QIOTaskWorker worker, | |
237 | gpointer opaque, | |
238 | GDestroyNotify destroy); | |
239 | ||
240 | /** | |
241 | * qio_task_complete: | |
242 | * @task: the task struct | |
243 | * | |
60e705c5 DB |
244 | * Invoke the completion callback for @task and |
245 | * then free its memory. | |
b02db2d9 DB |
246 | */ |
247 | void qio_task_complete(QIOTask *task); | |
248 | ||
b02db2d9 | 249 | |
1a447e4f DB |
250 | /** |
251 | * qio_task_set_error: | |
252 | * @task: the task struct | |
253 | * @err: pointer to the error, or NULL | |
254 | * | |
255 | * Associate an error with the task, which can later | |
256 | * be retrieved with the qio_task_propagate_error() | |
257 | * method. This method takes ownership of @err, so | |
258 | * it is not valid to access it after this call | |
259 | * completes. If @err is NULL this is a no-op. If | |
260 | * this is call multiple times, only the first | |
261 | * provided @err will be recorded, later ones will | |
262 | * be discarded and freed. | |
263 | */ | |
264 | void qio_task_set_error(QIOTask *task, | |
265 | Error *err); | |
266 | ||
267 | ||
268 | /** | |
269 | * qio_task_propagate_error: | |
270 | * @task: the task struct | |
271 | * @errp: pointer to a NULL-initialized error object | |
272 | * | |
273 | * Propagate the error associated with @task | |
274 | * into @errp. | |
275 | * | |
276 | * Returns: true if an error was propagated, false otherwise | |
277 | */ | |
278 | bool qio_task_propagate_error(QIOTask *task, | |
279 | Error **errp); | |
280 | ||
281 | ||
52dd99e8 DB |
282 | /** |
283 | * qio_task_set_result_pointer: | |
284 | * @task: the task struct | |
285 | * @result: pointer to the result data | |
286 | * | |
287 | * Associate an opaque result with the task, | |
288 | * which can later be retrieved with the | |
289 | * qio_task_get_result_pointer() method | |
290 | * | |
291 | */ | |
292 | void qio_task_set_result_pointer(QIOTask *task, | |
293 | gpointer result, | |
294 | GDestroyNotify notify); | |
295 | ||
296 | ||
297 | /** | |
298 | * qio_task_get_result_pointer: | |
299 | * @task: the task struct | |
300 | * | |
301 | * Retrieve the opaque result data associated | |
302 | * with the task, if any. | |
303 | * | |
304 | * Returns: the task result, or NULL | |
305 | */ | |
306 | gpointer qio_task_get_result_pointer(QIOTask *task); | |
307 | ||
308 | ||
b02db2d9 DB |
309 | /** |
310 | * qio_task_get_source: | |
311 | * @task: the task struct | |
312 | * | |
313 | * Get the source object associated with the background | |
937470bb DB |
314 | * task. The caller does not own a reference on the |
315 | * returned Object, and so should call object_ref() | |
316 | * if it wants to keep the object pointer outside the | |
317 | * lifetime of the QIOTask object. | |
b02db2d9 DB |
318 | * |
319 | * Returns: the source object | |
320 | */ | |
321 | Object *qio_task_get_source(QIOTask *task); | |
322 | ||
2a6a4076 | 323 | #endif /* QIO_TASK_H */ |