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