]>
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 | |
c8198bd5 | 9 | * version 2.1 of the License, or (at your option) any later version. |
b02db2d9 DB |
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 | typedef struct QIOTask QIOTask; |
25 | ||
60e705c5 | 26 | typedef void (*QIOTaskFunc)(QIOTask *task, |
b02db2d9 DB |
27 | gpointer opaque); |
28 | ||
59de517d DB |
29 | typedef void (*QIOTaskWorker)(QIOTask *task, |
30 | gpointer opaque); | |
b02db2d9 DB |
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> | |
60e705c5 | 42 | * <title>Task function signature</title> |
b02db2d9 DB |
43 | * <programlisting> |
44 | * void myobject_operation(QMyObject *obj, | |
45 | * QIOTaskFunc *func, | |
46 | * gpointer opaque, | |
e8c8adec | 47 | * GDestroyNotify notify); |
b02db2d9 DB |
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 | * | |
60e705c5 DB |
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 | |
b02db2d9 DB |
59 | * |
60 | * <example> | |
60e705c5 DB |
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> | |
b02db2d9 DB |
85 | * <programlisting> |
86 | * void myobject_operation(QMyObject *obj, | |
87 | * QIOTaskFunc *func, | |
88 | * gpointer opaque, | |
e8c8adec | 89 | * GDestroyNotify notify) |
b02db2d9 DB |
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 | * NULL); | |
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); | |
e4eb089c | 120 | * Error *err = NULL; |
b02db2d9 DB |
121 | * |
122 | * ...check something important... | |
123 | * if (err) { | |
60e705c5 DB |
124 | * qio_task_set_error(task, err); |
125 | * qio_task_complete(task); | |
b02db2d9 DB |
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 | * | |
60e705c5 DB |
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 | * | |
b02db2d9 DB |
141 | * Once this function returns false, object_unref will be called |
142 | * automatically on the task causing it to be released and the | |
143 | * ref on QMyObject dropped too. | |
144 | * | |
145 | * The QIOTask module can also be used to perform operations | |
146 | * in a background thread context, while still reporting the | |
147 | * results in the main event thread. This allows code which | |
d02d06f8 | 148 | * cannot easily be rewritten to be asynchronous (such as DNS |
b02db2d9 DB |
149 | * lookups) to be easily run non-blocking. Reporting the |
150 | * results in the main thread context means that the caller | |
151 | * typically does not need to be concerned about thread | |
0b2675c4 | 152 | * safety wrt the BQL. |
b02db2d9 DB |
153 | * |
154 | * For example, the socket_listen() method will block the caller | |
155 | * while DNS lookups take place if given a name, instead of IP | |
156 | * address. The C library often do not provide a practical async | |
157 | * DNS API, so the to get non-blocking DNS lookups in a portable | |
158 | * manner requires use of a thread. So achieve a non-blocking | |
159 | * socket listen using QIOTask would require: | |
160 | * | |
161 | * <example> | |
59de517d DB |
162 | * static void myobject_listen_worker(QIOTask *task, |
163 | * gpointer opaque) | |
b02db2d9 DB |
164 | * { |
165 | * QMyObject obj = QMY_OBJECT(qio_task_get_source(task)); | |
166 | * SocketAddress *addr = opaque; | |
59de517d | 167 | * Error *err = NULL; |
b02db2d9 | 168 | * |
59de517d DB |
169 | * obj->fd = socket_listen(addr, &err); |
170 | * | |
171 | qio_task_set_error(task, err); | |
b02db2d9 DB |
172 | * } |
173 | * | |
174 | * void myobject_listen_async(QMyObject *obj, | |
175 | * SocketAddress *addr, | |
176 | * QIOTaskFunc *func, | |
177 | * gpointer opaque, | |
e8c8adec | 178 | * GDestroyNotify notify) |
b02db2d9 DB |
179 | * { |
180 | * QIOTask *task; | |
181 | * SocketAddress *addrCopy; | |
182 | * | |
37f9e0a2 | 183 | * addrCopy = QAPI_CLONE(SocketAddress, addr); |
b02db2d9 DB |
184 | * task = qio_task_new(OBJECT(obj), func, opaque, notify); |
185 | * | |
186 | * qio_task_run_in_thread(task, myobject_listen_worker, | |
187 | * addrCopy, | |
188 | * qapi_free_SocketAddress); | |
189 | * } | |
190 | * </example> | |
191 | * | |
192 | * NB, The 'func' callback passed into myobject_listen_async | |
193 | * will be invoked from the main event thread, despite the | |
194 | * actual operation being performed in a different thread. | |
195 | */ | |
196 | ||
197 | /** | |
198 | * qio_task_new: | |
199 | * @source: the object on which the operation is invoked | |
200 | * @func: the callback to invoke when the task completes | |
201 | * @opaque: opaque data to pass to @func when invoked | |
202 | * @destroy: optional callback to free @opaque | |
203 | * | |
204 | * Creates a new task struct to track completion of a | |
205 | * background operation running on the object @source. | |
206 | * When the operation completes or fails, the callback | |
207 | * @func will be invoked. The callback can access the | |
208 | * 'err' attribute in the task object to determine if | |
209 | * the operation was successful or not. | |
210 | * | |
60e705c5 DB |
211 | * The returned task will be released when qio_task_complete() |
212 | * is invoked. | |
b02db2d9 DB |
213 | * |
214 | * Returns: the task struct | |
215 | */ | |
216 | QIOTask *qio_task_new(Object *source, | |
217 | QIOTaskFunc func, | |
218 | gpointer opaque, | |
219 | GDestroyNotify destroy); | |
220 | ||
221 | /** | |
222 | * qio_task_run_in_thread: | |
223 | * @task: the task struct | |
224 | * @worker: the function to invoke in a thread | |
225 | * @opaque: opaque data to pass to @worker | |
226 | * @destroy: function to free @opaque | |
a17536c5 PX |
227 | * @context: the context to run the complete hook. If %NULL, the |
228 | * default context will be used. | |
b02db2d9 | 229 | * |
60e705c5 DB |
230 | * Run a task in a background thread. When @worker |
231 | * returns it will call qio_task_complete() in | |
dbb44504 DB |
232 | * the thread that is running the main loop associated |
233 | * with @context. | |
b02db2d9 DB |
234 | */ |
235 | void qio_task_run_in_thread(QIOTask *task, | |
236 | QIOTaskWorker worker, | |
237 | gpointer opaque, | |
a17536c5 PX |
238 | GDestroyNotify destroy, |
239 | GMainContext *context); | |
b02db2d9 | 240 | |
dbb44504 DB |
241 | |
242 | /** | |
243 | * qio_task_wait_thread: | |
244 | * @task: the task struct | |
245 | * | |
246 | * Wait for completion of a task that was previously | |
247 | * invoked using qio_task_run_in_thread. This MUST | |
248 | * ONLY be invoked if the task has not already | |
249 | * completed, since after the completion callback | |
250 | * is invoked, @task will have been freed. | |
251 | * | |
252 | * To avoid racing with execution of the completion | |
253 | * callback provided with qio_task_new, this method | |
254 | * MUST ONLY be invoked from the thread that is | |
255 | * running the main loop associated with @context | |
256 | * parameter to qio_task_run_in_thread. | |
257 | * | |
258 | * When the thread has completed, the completion | |
259 | * callback provided to qio_task_new will be invoked. | |
260 | * When that callback returns @task will be freed, | |
261 | * so @task must not be referenced after this | |
262 | * method completes. | |
263 | */ | |
264 | void qio_task_wait_thread(QIOTask *task); | |
265 | ||
266 | ||
b02db2d9 DB |
267 | /** |
268 | * qio_task_complete: | |
269 | * @task: the task struct | |
270 | * | |
60e705c5 DB |
271 | * Invoke the completion callback for @task and |
272 | * then free its memory. | |
b02db2d9 DB |
273 | */ |
274 | void qio_task_complete(QIOTask *task); | |
275 | ||
b02db2d9 | 276 | |
1a447e4f DB |
277 | /** |
278 | * qio_task_set_error: | |
279 | * @task: the task struct | |
280 | * @err: pointer to the error, or NULL | |
281 | * | |
282 | * Associate an error with the task, which can later | |
283 | * be retrieved with the qio_task_propagate_error() | |
284 | * method. This method takes ownership of @err, so | |
285 | * it is not valid to access it after this call | |
286 | * completes. If @err is NULL this is a no-op. If | |
287 | * this is call multiple times, only the first | |
288 | * provided @err will be recorded, later ones will | |
289 | * be discarded and freed. | |
290 | */ | |
291 | void qio_task_set_error(QIOTask *task, | |
292 | Error *err); | |
293 | ||
294 | ||
295 | /** | |
296 | * qio_task_propagate_error: | |
297 | * @task: the task struct | |
298 | * @errp: pointer to a NULL-initialized error object | |
299 | * | |
300 | * Propagate the error associated with @task | |
301 | * into @errp. | |
302 | * | |
303 | * Returns: true if an error was propagated, false otherwise | |
304 | */ | |
305 | bool qio_task_propagate_error(QIOTask *task, | |
306 | Error **errp); | |
307 | ||
308 | ||
52dd99e8 DB |
309 | /** |
310 | * qio_task_set_result_pointer: | |
311 | * @task: the task struct | |
312 | * @result: pointer to the result data | |
313 | * | |
314 | * Associate an opaque result with the task, | |
315 | * which can later be retrieved with the | |
316 | * qio_task_get_result_pointer() method | |
317 | * | |
318 | */ | |
319 | void qio_task_set_result_pointer(QIOTask *task, | |
320 | gpointer result, | |
321 | GDestroyNotify notify); | |
322 | ||
323 | ||
324 | /** | |
325 | * qio_task_get_result_pointer: | |
326 | * @task: the task struct | |
327 | * | |
328 | * Retrieve the opaque result data associated | |
329 | * with the task, if any. | |
330 | * | |
331 | * Returns: the task result, or NULL | |
332 | */ | |
333 | gpointer qio_task_get_result_pointer(QIOTask *task); | |
334 | ||
335 | ||
b02db2d9 DB |
336 | /** |
337 | * qio_task_get_source: | |
338 | * @task: the task struct | |
339 | * | |
340 | * Get the source object associated with the background | |
937470bb DB |
341 | * task. The caller does not own a reference on the |
342 | * returned Object, and so should call object_ref() | |
343 | * if it wants to keep the object pointer outside the | |
344 | * lifetime of the QIOTask object. | |
b02db2d9 DB |
345 | * |
346 | * Returns: the source object | |
347 | */ | |
348 | Object *qio_task_get_source(QIOTask *task); | |
349 | ||
2a6a4076 | 350 | #endif /* QIO_TASK_H */ |