[evolution-data-server/gnome-3-8] EBookClientView: Make D-Bus signal handlers thread-safe.



commit b5a4cd68cde6d5589325b7525dfc1f2baaecc570
Author: Matthew Barnes <mbarnes redhat com>
Date:   Sat May 4 10:32:36 2013 -0400

    EBookClientView: Make D-Bus signal handlers thread-safe.
    
    Seeing crashes now where handler functions for D-Bus signals like
    "objects-added" are receiving finalized EBookClientView instances.
    Possibly a side-effect of recent changes to GMainContext usage.
    
    Use the trick of passing an allocated GWeakRef along with a suitable
    GClosureNotify to g_signal_connect_data().  The handler function will
    just return quietly if it can't obtain a strong client view reference.
    
    (cherry picked from commit 2df7a66eb535863dc41db446afc67ca4e0268c12)
    
    Conflicts:
        addressbook/libebook/e-book-client-view.c

 addressbook/libebook/e-book-client-view.c |  313 ++++++++++++++++++-----------
 1 files changed, 198 insertions(+), 115 deletions(-)
---
diff --git a/addressbook/libebook/e-book-client-view.c b/addressbook/libebook/e-book-client-view.c
index 25f47c9..275fa00 100644
--- a/addressbook/libebook/e-book-client-view.c
+++ b/addressbook/libebook/e-book-client-view.c
@@ -126,6 +126,24 @@ signal_closure_free (SignalClosure *signal_closure)
        g_slice_free (SignalClosure, signal_closure);
 }
 
+static GWeakRef *
+weak_ref_new (gpointer object)
+{
+       GWeakRef *weak_ref;
+
+       weak_ref = g_slice_new0 (GWeakRef);
+       g_weak_ref_set (weak_ref, object);
+
+       return weak_ref;
+}
+
+static void
+weak_ref_free (GWeakRef *weak_ref)
+{
+       g_weak_ref_set (weak_ref, NULL);
+       g_slice_free (GWeakRef, weak_ref);
+}
+
 static GMainContext *
 book_client_view_ref_main_context (EBookClientView *client_view)
 {
@@ -423,166 +441,221 @@ direct_contacts_fetch (EBookClientView *view,
 static void
 book_client_view_objects_added_cb (EGdbusBookView *object,
                                    const gchar * const *vcards,
-                                   EBookClientView *client_view)
+                                   GWeakRef *client_view_weak_ref)
 {
-       GSList *list = NULL;
-       gint ii;
+       EBookClientView *client_view;
 
-       if (!client_view->priv->running)
-               return;
+       client_view = g_weak_ref_get (client_view_weak_ref);
 
-       /* array contains UIDs only */
-       if (client_view->priv->direct_book != NULL) {
-               direct_contacts_fetch (client_view, vcards, OBJECTS_ADDED);
-               return;
-       }
+       if (client_view != NULL) {
+               GSList *list = NULL;
+               gint ii;
 
-       /* array contains both UID and vcard */
-       for (ii = 0; vcards[ii] != NULL && vcards[ii + 1] != NULL; ii += 2) {
-               EContact *contact;
-               const gchar *vcard = vcards[ii];
-               const gchar *uid = vcards[ii + 1];
+               if (!client_view->priv->running) {
+                       g_object_unref (client_view);
+                       return;
+               }
 
-               contact = e_contact_new_from_vcard_with_uid (vcard, uid);
-               list = g_slist_prepend (list, contact);
-       }
+               /* array contains UIDs only */
+               if (client_view->priv->direct_book != NULL) {
+                       direct_contacts_fetch (
+                               client_view, vcards, OBJECTS_ADDED);
+                       g_object_unref (client_view);
+                       return;
+               }
 
-       list = g_slist_reverse (list);
+               /* array contains both UID and vcard */
+               for (ii = 0; vcards[ii] != NULL && vcards[ii + 1] != NULL; ii += 2) {
+                       EContact *contact;
+                       const gchar *vcard = vcards[ii];
+                       const gchar *uid = vcards[ii + 1];
 
-       /* Takes ownership of the linked list. */
-       book_client_view_emit_objects_added (client_view, list);
+                       contact = e_contact_new_from_vcard_with_uid (vcard, uid);
+                       list = g_slist_prepend (list, contact);
+               }
+
+               list = g_slist_reverse (list);
+
+               /* Takes ownership of the linked list. */
+               book_client_view_emit_objects_added (client_view, list);
+
+               g_object_unref (client_view);
+       }
 }
 
 static void
 book_client_view_objects_modified_cb (EGdbusBookView *object,
                                       const gchar * const *vcards,
-                                      EBookClientView *client_view)
+                                      GWeakRef *client_view_weak_ref)
 {
-       GSList *list = NULL;
-       gint ii;
+       EBookClientView *client_view;
 
-       if (!client_view->priv->running)
-               return;
+       client_view = g_weak_ref_get (client_view_weak_ref);
 
-       /* array contains UIDs only */
-       if (client_view->priv->direct_book != NULL) {
-               direct_contacts_fetch (client_view, vcards, OBJECTS_MODIFIED);
-               return;
-       }
+       if (client_view != NULL) {
+               GSList *list = NULL;
+               gint ii;
 
-       /* array contains both UID and vcard */
-       for (ii = 0; vcards[ii] != NULL && vcards[ii + 1] != NULL; ii += 2) {
-               EContact *contact;
-               const gchar *vcard = vcards[ii];
-               const gchar *uid = vcards[ii + 1];
+               if (!client_view->priv->running) {
+                       g_object_unref (client_view);
+                       return;
+               }
 
-               contact = e_contact_new_from_vcard_with_uid (vcard, uid);
-               list = g_slist_prepend (list, contact);
-       }
+               /* array contains UIDs only */
+               if (client_view->priv->direct_book != NULL) {
+                       direct_contacts_fetch (
+                               client_view, vcards, OBJECTS_MODIFIED);
+                       g_object_unref (client_view);
+                       return;
+               }
+
+               /* array contains both UID and vcard */
+               for (ii = 0; vcards[ii] != NULL && vcards[ii + 1] != NULL; ii += 2) {
+                       EContact *contact;
+                       const gchar *vcard = vcards[ii];
+                       const gchar *uid = vcards[ii + 1];
+
+                       contact = e_contact_new_from_vcard_with_uid (vcard, uid);
+                       list = g_slist_prepend (list, contact);
+               }
+
+               list = g_slist_reverse (list);
 
-       list = g_slist_reverse (list);
+               /* Takes ownership of the linked list. */
+               book_client_view_emit_objects_modified (client_view, list);
 
-       /* Takes ownership of the linked list. */
-       book_client_view_emit_objects_modified (client_view, list);
+               g_object_unref (client_view);
+       }
 }
 
 static void
 book_client_view_objects_removed_cb (EGdbusBookView *object,
                                      const gchar * const *ids,
-                                     EBookClientView *client_view)
+                                     GWeakRef *client_view_weak_ref)
 {
-       GSource *idle_source;
-       GMainContext *main_context;
-       SignalClosure *signal_closure;
-       GSList *list = NULL;
-       gint ii;
+       EBookClientView *client_view;
 
-       if (!client_view->priv->running)
-               return;
+       client_view = g_weak_ref_get (client_view_weak_ref);
 
-       for (ii = 0; ids[ii] != NULL; ii++)
-               list = g_slist_prepend (list, g_strdup (ids[ii]));
+       if (client_view != NULL) {
+               GSource *idle_source;
+               GMainContext *main_context;
+               SignalClosure *signal_closure;
+               GSList *list = NULL;
+               gint ii;
+
+               if (!client_view->priv->running) {
+                       g_object_unref (client_view);
+                       return;
+               }
 
-       signal_closure = g_slice_new0 (SignalClosure);
-       g_weak_ref_set (&signal_closure->client_view, client_view);
-       signal_closure->string_list = g_slist_reverse (list);
+               for (ii = 0; ids[ii] != NULL; ii++)
+                       list = g_slist_prepend (list, g_strdup (ids[ii]));
 
-       main_context = book_client_view_ref_main_context (client_view);
+               signal_closure = g_slice_new0 (SignalClosure);
+               g_weak_ref_set (&signal_closure->client_view, client_view);
+               signal_closure->string_list = g_slist_reverse (list);
 
-       idle_source = g_idle_source_new ();
-       g_source_set_callback (
-               idle_source,
-               book_client_view_emit_objects_removed_idle_cb,
-               signal_closure,
-               (GDestroyNotify) signal_closure_free);
-       g_source_attach (idle_source, main_context);
-       g_source_unref (idle_source);
+               main_context = book_client_view_ref_main_context (client_view);
 
-       g_main_context_unref (main_context);
+               idle_source = g_idle_source_new ();
+               g_source_set_callback (
+                       idle_source,
+                       book_client_view_emit_objects_removed_idle_cb,
+                       signal_closure,
+                       (GDestroyNotify) signal_closure_free);
+               g_source_attach (idle_source, main_context);
+               g_source_unref (idle_source);
+
+               g_main_context_unref (main_context);
+
+               g_object_unref (client_view);
+       }
 }
 
 static void
 book_client_view_progress_cb (EGdbusBookView *object,
                               guint percent,
                               const gchar *message,
-                              EBookClientView *client_view)
+                              GWeakRef *client_view_weak_ref)
 {
-       GSource *idle_source;
-       GMainContext *main_context;
-       SignalClosure *signal_closure;
+       EBookClientView *client_view;
 
-       if (!client_view->priv->running)
-               return;
+       client_view = g_weak_ref_get (client_view_weak_ref);
 
-       signal_closure = g_slice_new0 (SignalClosure);
-       g_weak_ref_set (&signal_closure->client_view, client_view);
-       signal_closure->message = g_strdup (message);
-       signal_closure->percent = percent;
+       if (client_view != NULL) {
+               GSource *idle_source;
+               GMainContext *main_context;
+               SignalClosure *signal_closure;
 
-       main_context = book_client_view_ref_main_context (client_view);
+               if (!client_view->priv->running) {
+                       g_object_unref (client_view);
+                       return;
+               }
 
-       idle_source = g_idle_source_new ();
-       g_source_set_callback (
-               idle_source,
-               book_client_view_emit_progress_idle_cb,
-               signal_closure,
-               (GDestroyNotify) signal_closure_free);
-       g_source_attach (idle_source, main_context);
-       g_source_unref (idle_source);
+               signal_closure = g_slice_new0 (SignalClosure);
+               g_weak_ref_set (&signal_closure->client_view, client_view);
+               signal_closure->message = g_strdup (message);
+               signal_closure->percent = percent;
 
-       g_main_context_unref (main_context);
+               main_context = book_client_view_ref_main_context (client_view);
+
+               idle_source = g_idle_source_new ();
+               g_source_set_callback (
+                       idle_source,
+                       book_client_view_emit_progress_idle_cb,
+                       signal_closure,
+                       (GDestroyNotify) signal_closure_free);
+               g_source_attach (idle_source, main_context);
+               g_source_unref (idle_source);
+
+               g_main_context_unref (main_context);
+
+               g_object_unref (client_view);
+       }
 }
 
 static void
 book_client_view_complete_cb (EGdbusBookView *object,
                               const gchar * const *in_error_strv,
-                              EBookClientView *client_view)
+                              GWeakRef *client_view_weak_ref)
 {
-       GSource *idle_source;
-       GMainContext *main_context;
-       SignalClosure *signal_closure;
+       EBookClientView *client_view;
 
-       if (!client_view->priv->running)
-               return;
+       client_view = g_weak_ref_get (client_view_weak_ref);
 
-       signal_closure = g_slice_new0 (SignalClosure);
-       g_weak_ref_set (&signal_closure->client_view, client_view);
-       e_gdbus_templates_decode_error (in_error_strv, &signal_closure->error);
+       if (client_view != NULL) {
+               GSource *idle_source;
+               GMainContext *main_context;
+               SignalClosure *signal_closure;
 
-       main_context = book_client_view_ref_main_context (client_view);
+               if (!client_view->priv->running) {
+                       g_object_unref (client_view);
+                       return;
+               }
 
-       idle_source = g_idle_source_new ();
-       g_source_set_callback (
-               idle_source,
-               book_client_view_emit_complete_idle_cb,
-               signal_closure,
-               (GDestroyNotify) signal_closure_free);
-       g_source_attach (idle_source, main_context);
-       g_source_unref (idle_source);
+               signal_closure = g_slice_new0 (SignalClosure);
+               g_weak_ref_set (&signal_closure->client_view, client_view);
+               e_gdbus_templates_decode_error (
+                       in_error_strv, &signal_closure->error);
 
-       g_main_context_unref (main_context);
+               main_context = book_client_view_ref_main_context (client_view);
+
+               idle_source = g_idle_source_new ();
+               g_source_set_callback (
+                       idle_source,
+                       book_client_view_emit_complete_idle_cb,
+                       signal_closure,
+                       (GDestroyNotify) signal_closure_free);
+               g_source_attach (idle_source, main_context);
+               g_source_unref (idle_source);
+
+               g_main_context_unref (main_context);
 
-       client_view->priv->complete = TRUE;
+               client_view->priv->complete = TRUE;
+
+               g_object_unref (client_view);
+       }
 }
 
 static void
@@ -805,29 +878,39 @@ book_client_view_initable_init (GInitable *initable,
 
        priv->dbus_proxy = G_DBUS_PROXY (gdbus_bookview);
 
-       handler_id = g_signal_connect (
+       handler_id = g_signal_connect_data (
                priv->dbus_proxy, "objects-added",
-               G_CALLBACK (book_client_view_objects_added_cb), initable);
+               G_CALLBACK (book_client_view_objects_added_cb),
+               weak_ref_new (initable),
+               (GClosureNotify) weak_ref_free, 0);
        priv->objects_added_handler_id = handler_id;
 
-       handler_id = g_signal_connect (
+       handler_id = g_signal_connect_data (
                priv->dbus_proxy, "objects-modified",
-               G_CALLBACK (book_client_view_objects_modified_cb), initable);
+               G_CALLBACK (book_client_view_objects_modified_cb),
+               weak_ref_new (initable),
+               (GClosureNotify) weak_ref_free, 0);
        priv->objects_modified_handler_id = handler_id;
 
-       handler_id = g_signal_connect (
+       handler_id = g_signal_connect_data (
                priv->dbus_proxy, "objects-removed",
-               G_CALLBACK (book_client_view_objects_removed_cb), initable);
+               G_CALLBACK (book_client_view_objects_removed_cb),
+               weak_ref_new (initable),
+               (GClosureNotify) weak_ref_free, 0);
        priv->objects_removed_handler_id = handler_id;
 
-       handler_id = g_signal_connect (
+       handler_id = g_signal_connect_data (
                priv->dbus_proxy, "progress",
-               G_CALLBACK (book_client_view_progress_cb), initable);
+               G_CALLBACK (book_client_view_progress_cb),
+               weak_ref_new (initable),
+               (GClosureNotify) weak_ref_free, 0);
        priv->progress_handler_id = handler_id;
 
-       handler_id = g_signal_connect (
+       handler_id = g_signal_connect_data (
                priv->dbus_proxy, "complete",
-               G_CALLBACK (book_client_view_complete_cb), initable);
+               G_CALLBACK (book_client_view_complete_cb),
+               weak_ref_new (initable),
+               (GClosureNotify) weak_ref_free, 0);
        priv->complete_handler_id = handler_id;
 
        /* When in direct read access mode, we add a special field


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]