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 | { |
153 | iface->init_async = g_async_initable_real_init_async; |
154 | iface->init_finish = g_async_initable_real_init_finish; |
155 | } |
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 | { |
211 | GAsyncInitableIface *iface; |
212 | |
213 | g_return_if_fail (G_IS_ASYNC_INITABLE (initable)); |
214 | |
215 | iface = G_ASYNC_INITABLE_GET_IFACE (initable); |
216 | |
217 | (* iface->init_async) (initable, io_priority, cancellable, callback, user_data); |
218 | } |
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 | { |
240 | GAsyncInitableIface *iface; |
241 | |
242 | g_return_val_if_fail (G_IS_ASYNC_INITABLE (initable), FALSE); |
243 | g_return_val_if_fail (G_IS_ASYNC_RESULT (res), FALSE); |
244 | |
245 | if (g_async_result_legacy_propagate_error (res, error)) |
246 | return FALSE; |
247 | |
248 | iface = G_ASYNC_INITABLE_GET_IFACE (initable); |
249 | |
250 | return (* iface->init_finish) (initable, res, error); |
251 | } |
252 | |
253 | static void |
254 | async_init_thread (GTask *task, |
255 | gpointer source_object, |
256 | gpointer task_data, |
257 | GCancellable *cancellable) |
258 | { |
259 | GError *error = NULL; |
260 | |
261 | if (g_initable_init (G_INITABLE (source_object), cancellable, error: &error)) |
262 | g_task_return_boolean (task, TRUE); |
263 | else |
264 | g_task_return_error (task, error); |
265 | } |
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 | { |
274 | GTask *task; |
275 | |
276 | g_return_if_fail (G_IS_INITABLE (initable)); |
277 | |
278 | task = g_task_new (source_object: initable, cancellable, callback, callback_data: user_data); |
279 | g_task_set_source_tag (task, g_async_initable_real_init_async); |
280 | g_task_set_priority (task, priority: io_priority); |
281 | g_task_run_in_thread (task, task_func: async_init_thread); |
282 | g_object_unref (object: task); |
283 | } |
284 | |
285 | static gboolean |
286 | g_async_initable_real_init_finish (GAsyncInitable *initable, |
287 | GAsyncResult *res, |
288 | GError **error) |
289 | { |
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 | G_GNUC_BEGIN_IGNORE_DEPRECATIONS |
295 | if (G_IS_SIMPLE_ASYNC_RESULT (res)) |
296 | { |
297 | GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res); |
298 | if (g_simple_async_result_propagate_error (simple, dest: error)) |
299 | return FALSE; |
300 | else |
301 | return TRUE; |
302 | } |
303 | G_GNUC_END_IGNORE_DEPRECATIONS |
304 | |
305 | g_return_val_if_fail (g_task_is_valid (res, initable), FALSE); |
306 | |
307 | return g_task_propagate_boolean (G_TASK (res), error); |
308 | } |
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 | { |
341 | va_list var_args; |
342 | |
343 | va_start (var_args, first_property_name); |
344 | g_async_initable_new_valist_async (object_type, |
345 | first_property_name, var_args, |
346 | io_priority, cancellable, |
347 | callback, user_data); |
348 | va_end (var_args); |
349 | } |
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 | { |
383 | GObject *obj; |
384 | |
385 | g_return_if_fail (G_TYPE_IS_ASYNC_INITABLE (object_type)); |
386 | |
387 | obj = g_object_newv (object_type, n_parameters, parameters); |
388 | |
389 | g_async_initable_init_async (G_ASYNC_INITABLE (obj), |
390 | io_priority, cancellable, |
391 | callback, user_data); |
392 | g_object_unref (object: obj); /* Passed ownership to async call */ |
393 | } |
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 | { |
427 | GObject *obj; |
428 | |
429 | g_return_if_fail (G_TYPE_IS_ASYNC_INITABLE (object_type)); |
430 | |
431 | obj = g_object_new_valist (object_type, |
432 | first_property_name, |
433 | var_args); |
434 | |
435 | g_async_initable_init_async (G_ASYNC_INITABLE (obj), |
436 | io_priority, cancellable, |
437 | callback, user_data); |
438 | g_object_unref (object: obj); /* Passed ownership to async call */ |
439 | } |
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 | { |
460 | if (g_async_initable_init_finish (initable, res, error)) |
461 | return g_object_ref (G_OBJECT (initable)); |
462 | else |
463 | return NULL; |
464 | } |
465 | |