/src/glib/gio/gasyncinitable.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* GIO - GLib Input, Output and Streaming Library |
2 | | * |
3 | | * Copyright (C) 2009 Red Hat, Inc. |
4 | | * |
5 | | * This library is free software; you can redistribute it and/or |
6 | | * modify it under the terms of the GNU Lesser General Public |
7 | | * License as published by the Free Software Foundation; either |
8 | | * version 2.1 of the License, or (at your option) any later version. |
9 | | * |
10 | | * This library is distributed in the hope that it will be useful, |
11 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | | * Lesser General Public License for more details. |
14 | | * |
15 | | * You should have received a copy of the GNU Lesser General |
16 | | * Public License along with this library; if not, see <http://www.gnu.org/licenses/>. |
17 | | * |
18 | | * Author: Alexander Larsson <alexl@redhat.com> |
19 | | */ |
20 | | |
21 | | #include "config.h" |
22 | | #include "gasyncinitable.h" |
23 | | #include "gasyncresult.h" |
24 | | #include "gsimpleasyncresult.h" |
25 | | #include "gtask.h" |
26 | | #include "glibintl.h" |
27 | | |
28 | | |
29 | | /** |
30 | | * SECTION:gasyncinitable |
31 | | * @short_description: Asynchronously failable object initialization interface |
32 | | * @include: gio/gio.h |
33 | | * @see_also: #GInitable |
34 | | * |
35 | | * This is the asynchronous version of #GInitable; it behaves the same |
36 | | * in all ways except that initialization is asynchronous. For more details |
37 | | * see the descriptions on #GInitable. |
38 | | * |
39 | | * A class may implement both the #GInitable and #GAsyncInitable interfaces. |
40 | | * |
41 | | * Users of objects implementing this are not intended to use the interface |
42 | | * method directly; instead it will be used automatically in various ways. |
43 | | * For C applications you generally just call g_async_initable_new_async() |
44 | | * directly, or indirectly via a foo_thing_new_async() wrapper. This will call |
45 | | * g_async_initable_init_async() under the cover, calling back with %NULL and |
46 | | * a set %GError on failure. |
47 | | * |
48 | | * A typical implementation might look something like this: |
49 | | * |
50 | | * |[<!-- language="C" --> |
51 | | * enum { |
52 | | * NOT_INITIALIZED, |
53 | | * INITIALIZING, |
54 | | * INITIALIZED |
55 | | * }; |
56 | | * |
57 | | * static void |
58 | | * _foo_ready_cb (Foo *self) |
59 | | * { |
60 | | * GList *l; |
61 | | * |
62 | | * self->priv->state = INITIALIZED; |
63 | | * |
64 | | * for (l = self->priv->init_results; l != NULL; l = l->next) |
65 | | * { |
66 | | * GTask *task = l->data; |
67 | | * |
68 | | * if (self->priv->success) |
69 | | * g_task_return_boolean (task, TRUE); |
70 | | * else |
71 | | * g_task_return_new_error (task, ...); |
72 | | * g_object_unref (task); |
73 | | * } |
74 | | * |
75 | | * g_list_free (self->priv->init_results); |
76 | | * self->priv->init_results = NULL; |
77 | | * } |
78 | | * |
79 | | * static void |
80 | | * foo_init_async (GAsyncInitable *initable, |
81 | | * int io_priority, |
82 | | * GCancellable *cancellable, |
83 | | * GAsyncReadyCallback callback, |
84 | | * gpointer user_data) |
85 | | * { |
86 | | * Foo *self = FOO (initable); |
87 | | * GTask *task; |
88 | | * |
89 | | * task = g_task_new (initable, cancellable, callback, user_data); |
90 | | * g_task_set_name (task, G_STRFUNC); |
91 | | * |
92 | | * switch (self->priv->state) |
93 | | * { |
94 | | * case NOT_INITIALIZED: |
95 | | * _foo_get_ready (self); |
96 | | * self->priv->init_results = g_list_append (self->priv->init_results, |
97 | | * task); |
98 | | * self->priv->state = INITIALIZING; |
99 | | * break; |
100 | | * case INITIALIZING: |
101 | | * self->priv->init_results = g_list_append (self->priv->init_results, |
102 | | * task); |
103 | | * break; |
104 | | * case INITIALIZED: |
105 | | * if (!self->priv->success) |
106 | | * g_task_return_new_error (task, ...); |
107 | | * else |
108 | | * g_task_return_boolean (task, TRUE); |
109 | | * g_object_unref (task); |
110 | | * break; |
111 | | * } |
112 | | * } |
113 | | * |
114 | | * static gboolean |
115 | | * foo_init_finish (GAsyncInitable *initable, |
116 | | * GAsyncResult *result, |
117 | | * GError **error) |
118 | | * { |
119 | | * g_return_val_if_fail (g_task_is_valid (result, initable), FALSE); |
120 | | * |
121 | | * return g_task_propagate_boolean (G_TASK (result), error); |
122 | | * } |
123 | | * |
124 | | * static void |
125 | | * foo_async_initable_iface_init (gpointer g_iface, |
126 | | * gpointer data) |
127 | | * { |
128 | | * GAsyncInitableIface *iface = g_iface; |
129 | | * |
130 | | * iface->init_async = foo_init_async; |
131 | | * iface->init_finish = foo_init_finish; |
132 | | * } |
133 | | * ]| |
134 | | */ |
135 | | |
136 | | static void g_async_initable_real_init_async (GAsyncInitable *initable, |
137 | | int io_priority, |
138 | | GCancellable *cancellable, |
139 | | GAsyncReadyCallback callback, |
140 | | gpointer user_data); |
141 | | static gboolean g_async_initable_real_init_finish (GAsyncInitable *initable, |
142 | | GAsyncResult *res, |
143 | | GError **error); |
144 | | |
145 | | |
146 | | typedef GAsyncInitableIface GAsyncInitableInterface; |
147 | | G_DEFINE_INTERFACE (GAsyncInitable, g_async_initable, G_TYPE_OBJECT) |
148 | | |
149 | | |
150 | | static void |
151 | | g_async_initable_default_init (GAsyncInitableInterface *iface) |
152 | 0 | { |
153 | 0 | iface->init_async = g_async_initable_real_init_async; |
154 | 0 | iface->init_finish = g_async_initable_real_init_finish; |
155 | 0 | } |
156 | | |
157 | | /** |
158 | | * g_async_initable_init_async: |
159 | | * @initable: a #GAsyncInitable. |
160 | | * @io_priority: the [I/O priority][io-priority] of the operation |
161 | | * @cancellable: optional #GCancellable object, %NULL to ignore. |
162 | | * @callback: a #GAsyncReadyCallback to call when the request is satisfied |
163 | | * @user_data: the data to pass to callback function |
164 | | * |
165 | | * Starts asynchronous initialization of the object implementing the |
166 | | * interface. This must be done before any real use of the object after |
167 | | * initial construction. If the object also implements #GInitable you can |
168 | | * optionally call g_initable_init() instead. |
169 | | * |
170 | | * This method is intended for language bindings. If writing in C, |
171 | | * g_async_initable_new_async() should typically be used instead. |
172 | | * |
173 | | * When the initialization is finished, @callback will be called. You can |
174 | | * then call g_async_initable_init_finish() to get the result of the |
175 | | * initialization. |
176 | | * |
177 | | * Implementations may also support cancellation. If @cancellable is not |
178 | | * %NULL, then initialization can be cancelled by triggering the cancellable |
179 | | * object from another thread. If the operation was cancelled, the error |
180 | | * %G_IO_ERROR_CANCELLED will be returned. If @cancellable is not %NULL, and |
181 | | * the object doesn't support cancellable initialization, the error |
182 | | * %G_IO_ERROR_NOT_SUPPORTED will be returned. |
183 | | * |
184 | | * As with #GInitable, if the object is not initialized, or initialization |
185 | | * returns with an error, then all operations on the object except |
186 | | * g_object_ref() and g_object_unref() are considered to be invalid, and |
187 | | * have undefined behaviour. They will often fail with g_critical() or |
188 | | * g_warning(), but this must not be relied on. |
189 | | * |
190 | | * Callers should not assume that a class which implements #GAsyncInitable can |
191 | | * be initialized multiple times; for more information, see g_initable_init(). |
192 | | * If a class explicitly supports being initialized multiple times, |
193 | | * implementation requires yielding all subsequent calls to init_async() on the |
194 | | * results of the first call. |
195 | | * |
196 | | * For classes that also support the #GInitable interface, the default |
197 | | * implementation of this method will run the g_initable_init() function |
198 | | * in a thread, so if you want to support asynchronous initialization via |
199 | | * threads, just implement the #GAsyncInitable interface without overriding |
200 | | * any interface methods. |
201 | | * |
202 | | * Since: 2.22 |
203 | | */ |
204 | | void |
205 | | g_async_initable_init_async (GAsyncInitable *initable, |
206 | | int io_priority, |
207 | | GCancellable *cancellable, |
208 | | GAsyncReadyCallback callback, |
209 | | gpointer user_data) |
210 | 0 | { |
211 | 0 | GAsyncInitableIface *iface; |
212 | |
|
213 | 0 | g_return_if_fail (G_IS_ASYNC_INITABLE (initable)); |
214 | | |
215 | 0 | iface = G_ASYNC_INITABLE_GET_IFACE (initable); |
216 | |
|
217 | 0 | (* iface->init_async) (initable, io_priority, cancellable, callback, user_data); |
218 | 0 | } |
219 | | |
220 | | /** |
221 | | * g_async_initable_init_finish: |
222 | | * @initable: a #GAsyncInitable. |
223 | | * @res: a #GAsyncResult. |
224 | | * @error: a #GError location to store the error occurring, or %NULL to |
225 | | * ignore. |
226 | | * |
227 | | * Finishes asynchronous initialization and returns the result. |
228 | | * See g_async_initable_init_async(). |
229 | | * |
230 | | * Returns: %TRUE if successful. If an error has occurred, this function |
231 | | * will return %FALSE and set @error appropriately if present. |
232 | | * |
233 | | * Since: 2.22 |
234 | | */ |
235 | | gboolean |
236 | | g_async_initable_init_finish (GAsyncInitable *initable, |
237 | | GAsyncResult *res, |
238 | | GError **error) |
239 | 0 | { |
240 | 0 | GAsyncInitableIface *iface; |
241 | |
|
242 | 0 | g_return_val_if_fail (G_IS_ASYNC_INITABLE (initable), FALSE); |
243 | 0 | g_return_val_if_fail (G_IS_ASYNC_RESULT (res), FALSE); |
244 | | |
245 | 0 | if (g_async_result_legacy_propagate_error (res, error)) |
246 | 0 | return FALSE; |
247 | | |
248 | 0 | iface = G_ASYNC_INITABLE_GET_IFACE (initable); |
249 | |
|
250 | 0 | return (* iface->init_finish) (initable, res, error); |
251 | 0 | } |
252 | | |
253 | | static void |
254 | | async_init_thread (GTask *task, |
255 | | gpointer source_object, |
256 | | gpointer task_data, |
257 | | GCancellable *cancellable) |
258 | 0 | { |
259 | 0 | GError *error = NULL; |
260 | |
|
261 | 0 | if (g_initable_init (G_INITABLE (source_object), cancellable, &error)) |
262 | 0 | g_task_return_boolean (task, TRUE); |
263 | 0 | else |
264 | 0 | g_task_return_error (task, error); |
265 | 0 | } |
266 | | |
267 | | static void |
268 | | g_async_initable_real_init_async (GAsyncInitable *initable, |
269 | | int io_priority, |
270 | | GCancellable *cancellable, |
271 | | GAsyncReadyCallback callback, |
272 | | gpointer user_data) |
273 | 0 | { |
274 | 0 | GTask *task; |
275 | |
|
276 | 0 | g_return_if_fail (G_IS_INITABLE (initable)); |
277 | | |
278 | 0 | task = g_task_new (initable, cancellable, callback, user_data); |
279 | 0 | g_task_set_source_tag (task, g_async_initable_real_init_async); |
280 | 0 | g_task_set_priority (task, io_priority); |
281 | 0 | g_task_run_in_thread (task, async_init_thread); |
282 | 0 | g_object_unref (task); |
283 | 0 | } |
284 | | |
285 | | static gboolean |
286 | | g_async_initable_real_init_finish (GAsyncInitable *initable, |
287 | | GAsyncResult *res, |
288 | | GError **error) |
289 | 0 | { |
290 | | /* For backward compatibility we have to process GSimpleAsyncResults |
291 | | * even though g_async_initable_real_init_async doesn't generate |
292 | | * them any more. |
293 | | */ |
294 | 0 | G_GNUC_BEGIN_IGNORE_DEPRECATIONS |
295 | 0 | if (G_IS_SIMPLE_ASYNC_RESULT (res)) |
296 | 0 | { |
297 | 0 | GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res); |
298 | 0 | if (g_simple_async_result_propagate_error (simple, error)) |
299 | 0 | return FALSE; |
300 | 0 | else |
301 | 0 | return TRUE; |
302 | 0 | } |
303 | 0 | G_GNUC_END_IGNORE_DEPRECATIONS |
304 | | |
305 | 0 | g_return_val_if_fail (g_task_is_valid (res, initable), FALSE); |
306 | | |
307 | 0 | return g_task_propagate_boolean (G_TASK (res), error); |
308 | 0 | } |
309 | | |
310 | | /** |
311 | | * g_async_initable_new_async: |
312 | | * @object_type: a #GType supporting #GAsyncInitable. |
313 | | * @io_priority: the [I/O priority][io-priority] of the operation |
314 | | * @cancellable: optional #GCancellable object, %NULL to ignore. |
315 | | * @callback: a #GAsyncReadyCallback to call when the initialization is |
316 | | * finished |
317 | | * @user_data: the data to pass to callback function |
318 | | * @first_property_name: (nullable): the name of the first property, or %NULL if no |
319 | | * properties |
320 | | * @...: the value of the first property, followed by other property |
321 | | * value pairs, and ended by %NULL. |
322 | | * |
323 | | * Helper function for constructing #GAsyncInitable object. This is |
324 | | * similar to g_object_new() but also initializes the object asynchronously. |
325 | | * |
326 | | * When the initialization is finished, @callback will be called. You can |
327 | | * then call g_async_initable_new_finish() to get the new object and check |
328 | | * for any errors. |
329 | | * |
330 | | * Since: 2.22 |
331 | | */ |
332 | | void |
333 | | g_async_initable_new_async (GType object_type, |
334 | | int io_priority, |
335 | | GCancellable *cancellable, |
336 | | GAsyncReadyCallback callback, |
337 | | gpointer user_data, |
338 | | const gchar *first_property_name, |
339 | | ...) |
340 | 0 | { |
341 | 0 | va_list var_args; |
342 | |
|
343 | 0 | va_start (var_args, first_property_name); |
344 | 0 | g_async_initable_new_valist_async (object_type, |
345 | 0 | first_property_name, var_args, |
346 | 0 | io_priority, cancellable, |
347 | 0 | callback, user_data); |
348 | 0 | va_end (var_args); |
349 | 0 | } |
350 | | |
351 | | /** |
352 | | * g_async_initable_newv_async: |
353 | | * @object_type: a #GType supporting #GAsyncInitable. |
354 | | * @n_parameters: the number of parameters in @parameters |
355 | | * @parameters: the parameters to use to construct the object |
356 | | * @io_priority: the [I/O priority][io-priority] of the operation |
357 | | * @cancellable: optional #GCancellable object, %NULL to ignore. |
358 | | * @callback: a #GAsyncReadyCallback to call when the initialization is |
359 | | * finished |
360 | | * @user_data: the data to pass to callback function |
361 | | * |
362 | | * Helper function for constructing #GAsyncInitable object. This is |
363 | | * similar to g_object_newv() but also initializes the object asynchronously. |
364 | | * |
365 | | * When the initialization is finished, @callback will be called. You can |
366 | | * then call g_async_initable_new_finish() to get the new object and check |
367 | | * for any errors. |
368 | | * |
369 | | * Since: 2.22 |
370 | | * Deprecated: 2.54: Use g_object_new_with_properties() and |
371 | | * g_async_initable_init_async() instead. See #GParameter for more information. |
372 | | */ |
373 | | G_GNUC_BEGIN_IGNORE_DEPRECATIONS |
374 | | void |
375 | | g_async_initable_newv_async (GType object_type, |
376 | | guint n_parameters, |
377 | | GParameter *parameters, |
378 | | int io_priority, |
379 | | GCancellable *cancellable, |
380 | | GAsyncReadyCallback callback, |
381 | | gpointer user_data) |
382 | 0 | { |
383 | 0 | GObject *obj; |
384 | |
|
385 | 0 | g_return_if_fail (G_TYPE_IS_ASYNC_INITABLE (object_type)); |
386 | | |
387 | 0 | obj = g_object_newv (object_type, n_parameters, parameters); |
388 | |
|
389 | 0 | g_async_initable_init_async (G_ASYNC_INITABLE (obj), |
390 | 0 | io_priority, cancellable, |
391 | 0 | callback, user_data); |
392 | 0 | g_object_unref (obj); /* Passed ownership to async call */ |
393 | 0 | } |
394 | | G_GNUC_END_IGNORE_DEPRECATIONS |
395 | | |
396 | | /** |
397 | | * g_async_initable_new_valist_async: |
398 | | * @object_type: a #GType supporting #GAsyncInitable. |
399 | | * @first_property_name: the name of the first property, followed by |
400 | | * the value, and other property value pairs, and ended by %NULL. |
401 | | * @var_args: The var args list generated from @first_property_name. |
402 | | * @io_priority: the [I/O priority][io-priority] of the operation |
403 | | * @cancellable: optional #GCancellable object, %NULL to ignore. |
404 | | * @callback: a #GAsyncReadyCallback to call when the initialization is |
405 | | * finished |
406 | | * @user_data: the data to pass to callback function |
407 | | * |
408 | | * Helper function for constructing #GAsyncInitable object. This is |
409 | | * similar to g_object_new_valist() but also initializes the object |
410 | | * asynchronously. |
411 | | * |
412 | | * When the initialization is finished, @callback will be called. You can |
413 | | * then call g_async_initable_new_finish() to get the new object and check |
414 | | * for any errors. |
415 | | * |
416 | | * Since: 2.22 |
417 | | */ |
418 | | void |
419 | | g_async_initable_new_valist_async (GType object_type, |
420 | | const gchar *first_property_name, |
421 | | va_list var_args, |
422 | | int io_priority, |
423 | | GCancellable *cancellable, |
424 | | GAsyncReadyCallback callback, |
425 | | gpointer user_data) |
426 | 0 | { |
427 | 0 | GObject *obj; |
428 | |
|
429 | 0 | g_return_if_fail (G_TYPE_IS_ASYNC_INITABLE (object_type)); |
430 | | |
431 | 0 | obj = g_object_new_valist (object_type, |
432 | 0 | first_property_name, |
433 | 0 | var_args); |
434 | |
|
435 | 0 | g_async_initable_init_async (G_ASYNC_INITABLE (obj), |
436 | 0 | io_priority, cancellable, |
437 | 0 | callback, user_data); |
438 | 0 | g_object_unref (obj); /* Passed ownership to async call */ |
439 | 0 | } |
440 | | |
441 | | /** |
442 | | * g_async_initable_new_finish: |
443 | | * @initable: the #GAsyncInitable from the callback |
444 | | * @res: the #GAsyncResult from the callback |
445 | | * @error: return location for errors, or %NULL to ignore |
446 | | * |
447 | | * Finishes the async construction for the various g_async_initable_new |
448 | | * calls, returning the created object or %NULL on error. |
449 | | * |
450 | | * Returns: (type GObject.Object) (transfer full): a newly created #GObject, |
451 | | * or %NULL on error. Free with g_object_unref(). |
452 | | * |
453 | | * Since: 2.22 |
454 | | */ |
455 | | GObject * |
456 | | g_async_initable_new_finish (GAsyncInitable *initable, |
457 | | GAsyncResult *res, |
458 | | GError **error) |
459 | 0 | { |
460 | 0 | if (g_async_initable_init_finish (initable, res, error)) |
461 | 0 | return g_object_ref (G_OBJECT (initable)); |
462 | 0 | else |
463 | 0 | return NULL; |
464 | 0 | } |