From deab64365166fd3367a928306df0987b176fc3f7 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Wed, 15 Jun 2016 11:25:19 -0400 Subject: [PATCH] ginitable: Relax idempotency requirements on init() and init_async() The previously documented requirements for implementing init() and init_async() as completely idempotent were really quite hard to achieve, and brought a lot of pain for very little gain. Many implementations of GInitable and GAsyncInitable did not actually follow the requirements, or did not correctly handle concurrent init_async() calls. Relax those requirements so that classes can decide whether their init() or init_async() implementations need to be idempotent. https://bugzilla.gnome.org/show_bug.cgi?id=766660 --- gio/gasyncinitable.c | 13 ++++++++----- gio/ginitable.c | 26 +++++++++++++++++++++----- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/gio/gasyncinitable.c b/gio/gasyncinitable.c index 827bffcf7..299432918 100644 --- a/gio/gasyncinitable.c +++ b/gio/gasyncinitable.c @@ -166,6 +166,9 @@ g_async_initable_default_init (GAsyncInitableInterface *iface) * initial construction. If the object also implements #GInitable you can * optionally call g_initable_init() instead. * + * This method is intended for language bindings. If writing in C, + * g_async_initable_new_async() should typically be used instead. + * * When the initialization is finished, @callback will be called. You can * then call g_async_initable_init_finish() to get the result of the * initialization. @@ -183,11 +186,11 @@ g_async_initable_default_init (GAsyncInitableInterface *iface) * have undefined behaviour. They will often fail with g_critical() or * g_warning(), but this must not be relied on. * - * Implementations of this method must be idempotent: i.e. multiple calls - * to this function with the same argument should return the same results. - * Only the first call initializes the object; further calls return the result - * of the first call. This is so that it's safe to implement the singleton - * pattern in the GObject constructor function. + * Callers should not assume that a class which implements #GAsyncInitable can + * be initialized multiple times; for more information, see g_initable_init(). + * If a class explicitly supports being initialized multiple times, + * implementation requires yielding all subsequent calls to init_async() on the + * results of the first call. * * For classes that also support the #GInitable interface, the default * implementation of this method will run the g_initable_init() function diff --git a/gio/ginitable.c b/gio/ginitable.c index 92cf3ff01..f52046b4e 100644 --- a/gio/ginitable.c +++ b/gio/ginitable.c @@ -72,6 +72,9 @@ g_initable_default_init (GInitableInterface *iface) * * Initializes the object implementing the interface. * + * This method is intended for language bindings. If writing in C, + * g_initable_new() should typically be used instead. + * * The object must be initialized before any real use after initial * construction, either with this function or g_async_initable_init_async(). * @@ -87,11 +90,24 @@ g_initable_default_init (GInitableInterface *iface) * g_object_unref() are considered to be invalid, and have undefined * behaviour. See the [introduction][ginitable] for more details. * - * Implementations of this method must be idempotent, i.e. multiple calls - * to this function with the same argument should return the same results. - * Only the first call initializes the object, further calls return the result - * of the first call. This is so that it's safe to implement the singleton - * pattern in the GObject constructor function. + * Callers should not assume that a class which implements #GInitable can be + * initialized multiple times, unless the class explicitly documents itself as + * supporting this. Generally, a class’ implementation of init() can assume + * (and assert) that it will only be called once. Previously, this documentation + * recommended all #GInitable implementations should be idempotent; that + * recommendation was relaxed in GLib 2.54. + * + * If a class explicitly supports being initialized multiple times, it is + * recommended that the method is idempotent: multiple calls with the same + * arguments should return the same results. Only the first call initializes + * the object; further calls return the result of the first call. + * + * One reason why a class might need to support idempotent initialization is if + * it is designed to be used via the singleton pattern, with a + * #GObjectClass.constructor that sometimes returns an existing instance. + * In this pattern, a caller would expect to be able to call g_initable_init() + * on the result of g_object_new(), regardless of whether it is in fact a new + * instance. * * Returns: %TRUE if successful. If an error has occurred, this function will * return %FALSE and set @error appropriately if present.