ESource: Suppress "changed" emissions during initialization.
authorMatthew Barnes <mbarnes@redhat.com>
Tue, 21 Aug 2012 17:38:17 +0000 (13:38 -0400)
committerMatthew Barnes <mbarnes@redhat.com>
Tue, 21 Aug 2012 17:45:39 +0000 (13:45 -0400)
If an ESource is being instantiated from a worker thread, the change
notifications can possibly be emitted from callbacks on the ESource's
GMainContext before the ESource is fully initialized, which can break
invariants like "all ESources have a non-NULL UID string".

This commit suppresses those change notifications until the ESource
instance is fully initialized.

libedataserver/e-source.c

index 219b4cf..1ed8d25 100644 (file)
@@ -132,6 +132,7 @@ struct _ESourcePrivate {
        GHashTable *extensions;
 
        gboolean enabled;
+       gboolean initialized;
 };
 
 struct _AsyncContext {
@@ -665,6 +666,13 @@ source_idle_changed_cb (gpointer user_data)
 {
        ESource *source = E_SOURCE (user_data);
 
+       /* If the ESource is still initializing itself in a different
+        * thread, skip the signal emission and try again on the next
+        * main loop iteration.  This is a busy wait but it should be
+        * a very short wait. */
+       if (!source->priv->initialized)
+               return TRUE;
+
        g_mutex_lock (source->priv->changed_lock);
        if (source->priv->changed != NULL) {
                g_source_unref (source->priv->changed);
@@ -1303,15 +1311,6 @@ source_initable_init (GInitable *initable,
 
                success = source_parse_dbus_data (source, error);
 
-               /* Avoid a spurious "changed" emission. */
-               g_mutex_lock (source->priv->changed_lock);
-               if (source->priv->changed != NULL) {
-                       g_source_destroy (source->priv->changed);
-                       g_source_unref (source->priv->changed);
-                       source->priv->changed = NULL;
-               }
-               g_mutex_unlock (source->priv->changed_lock);
-
                g_object_unref (dbus_source);
 
        /* No D-Bus object implies we're configuring a new source,
@@ -1320,6 +1319,17 @@ source_initable_init (GInitable *initable,
                source->priv->uid = e_uid_new ();
        }
 
+       /* Try to avoid a spurious "changed" emission. */
+       g_mutex_lock (source->priv->changed_lock);
+       if (source->priv->changed != NULL) {
+               g_source_destroy (source->priv->changed);
+               g_source_unref (source->priv->changed);
+               source->priv->changed = NULL;
+       }
+       g_mutex_unlock (source->priv->changed_lock);
+
+       source->priv->initialized = TRUE;
+
        return success;
 }