[evolution-data-server] ECalClientView: Make D-Bus signal handlers thread-safe.



commit b255406dd249327efdb133e2c797b4dd496c736b
Author: Matthew Barnes <mbarnes redhat com>
Date:   Sat May 4 09:44:00 2013 -0400

    ECalClientView: Make D-Bus signal handlers thread-safe.
    
    Seeing crashes now where handler functions for D-Bus signals like
    "objects-added" are receiving finalized ECalClientView 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.

 calendar/libecal/e-cal-client-view.c |  293 ++++++++++++++++++----------------
 1 files changed, 152 insertions(+), 141 deletions(-)
---
diff --git a/calendar/libecal/e-cal-client-view.c b/calendar/libecal/e-cal-client-view.c
index c31e9fc..e37f15b 100644
--- a/calendar/libecal/e-cal-client-view.c
+++ b/calendar/libecal/e-cal-client-view.c
@@ -295,203 +295,204 @@ cal_client_view_emit_complete_idle_cb (gpointer user_data)
 static void
 cal_client_view_objects_added_cb (EGdbusCalView *dbus_proxy,
                                   const gchar * const *objects,
-                                  ECalClientView *client_view)
+                                  GWeakRef *client_view_weak_ref)
 {
-       ECalClient *client;
-       GSource *idle_source;
-       GMainContext *main_context;
-       SignalClosure *signal_closure;
+       ECalClientView *client_view;
 
-       if (!client_view->priv->running)
-               return;
+       client_view = g_weak_ref_get (client_view_weak_ref);
 
-       client = e_cal_client_view_ref_client (client_view);
+       if (client_view != NULL) {
+               GSource *idle_source;
+               GMainContext *main_context;
+               SignalClosure *signal_closure;
 
-       /* Suppress any further signal emissions if
-        * our ECalClient has already been finalized. */
-       if (client == NULL)
-               return;
+               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->component_list = build_object_list (objects);
+               signal_closure = g_slice_new0 (SignalClosure);
+               g_weak_ref_set (&signal_closure->client_view, client_view);
+               signal_closure->component_list = build_object_list (objects);
 
-       main_context = cal_client_view_ref_main_context (client_view);
+               main_context = cal_client_view_ref_main_context (client_view);
 
-       idle_source = g_idle_source_new ();
-       g_source_set_callback (
-               idle_source,
-               cal_client_view_emit_objects_added_idle_cb,
-               signal_closure,
-               (GDestroyNotify) signal_closure_free);
-       g_source_attach (idle_source, main_context);
-       g_source_unref (idle_source);
+               idle_source = g_idle_source_new ();
+               g_source_set_callback (
+                       idle_source,
+                       cal_client_view_emit_objects_added_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_main_context_unref (main_context);
 
-       g_object_unref (client);
+               g_object_unref (client_view);
+       }
 }
 
 static void
 cal_client_view_objects_modified_cb (EGdbusCalView *dbus_proxy,
                                      const gchar * const *objects,
-                                     ECalClientView *client_view)
+                                     GWeakRef *client_view_weak_ref)
 {
-       ECalClient *client;
-       GSource *idle_source;
-       GMainContext *main_context;
-       SignalClosure *signal_closure;
+       ECalClientView *client_view;
 
-       if (!client_view->priv->running)
-               return;
+       client_view = g_weak_ref_get (client_view_weak_ref);
 
-       client = e_cal_client_view_ref_client (client_view);
+       if (client_view != NULL) {
+               GSource *idle_source;
+               GMainContext *main_context;
+               SignalClosure *signal_closure;
 
-       /* Suppress any further signal emissions if
-        * our ECalClient has already been finalized. */
-       if (client == NULL)
-               return;
+               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->component_list = build_object_list (objects);
+               signal_closure = g_slice_new0 (SignalClosure);
+               g_weak_ref_set (&signal_closure->client_view, client_view);
+               signal_closure->component_list = build_object_list (objects);
 
-       main_context = cal_client_view_ref_main_context (client_view);
+               main_context = cal_client_view_ref_main_context (client_view);
 
-       idle_source = g_idle_source_new ();
-       g_source_set_callback (
-               idle_source,
-               cal_client_view_emit_objects_modified_idle_cb,
-               signal_closure,
-               (GDestroyNotify) signal_closure_free);
-       g_source_attach (idle_source, main_context);
-       g_source_unref (idle_source);
+               idle_source = g_idle_source_new ();
+               g_source_set_callback (
+                       idle_source,
+                       cal_client_view_emit_objects_modified_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_main_context_unref (main_context);
 
-       g_object_unref (client);
+               g_object_unref (client_view);
+       }
 }
 
 static void
 cal_client_view_objects_removed_cb (EGdbusCalView *dbus_proxy,
                                     const gchar * const *uids,
-                                    ECalClientView *client_view)
+                                    GWeakRef *client_view_weak_ref)
 {
-       ECalClient *client;
-       GSource *idle_source;
-       GMainContext *main_context;
-       SignalClosure *signal_closure;
+       ECalClientView *client_view;
 
-       if (!client_view->priv->running)
-               return;
+       client_view = g_weak_ref_get (client_view_weak_ref);
 
-       client = e_cal_client_view_ref_client (client_view);
+       if (client_view != NULL) {
+               GSource *idle_source;
+               GMainContext *main_context;
+               SignalClosure *signal_closure;
 
-       /* Suppress any further signal emissions if
-        * our ECalClient has already been finalized. */
-       if (client == NULL)
-               return;
+               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->component_id_list = build_id_list (uids);
+               signal_closure = g_slice_new0 (SignalClosure);
+               g_weak_ref_set (&signal_closure->client_view, client_view);
+               signal_closure->component_id_list = build_id_list (uids);
 
-       main_context = cal_client_view_ref_main_context (client_view);
+               main_context = cal_client_view_ref_main_context (client_view);
 
-       idle_source = g_idle_source_new ();
-       g_source_set_callback (
-               idle_source,
-               cal_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);
+               idle_source = g_idle_source_new ();
+               g_source_set_callback (
+                       idle_source,
+                       cal_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_main_context_unref (main_context);
 
-       g_object_unref (client);
+               g_object_unref (client_view);
+       }
 }
 
 static void
 cal_client_view_progress_cb (EGdbusCalView *dbus_proxy,
                              guint percent,
                              const gchar *message,
-                             ECalClientView *client_view)
+                             GWeakRef *client_view_weak_ref)
 {
-       ECalClient *client;
-       GSource *idle_source;
-       GMainContext *main_context;
-       SignalClosure *signal_closure;
+       ECalClientView *client_view;
 
-       if (!client_view->priv->running)
-               return;
+       client_view = g_weak_ref_get (client_view_weak_ref);
 
-       client = e_cal_client_view_ref_client (client_view);
+       if (client_view != NULL) {
+               GSource *idle_source;
+               GMainContext *main_context;
+               SignalClosure *signal_closure;
 
-       /* Suppress any further signal emissions if
-        * our ECalClient has already been finalized. */
-       if (client == NULL)
-               return;
+               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->message = g_strdup (message);
-       signal_closure->percent = percent;
+               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;
 
-       main_context = cal_client_view_ref_main_context (client_view);
+               main_context = cal_client_view_ref_main_context (client_view);
 
-       idle_source = g_idle_source_new ();
-       g_source_set_callback (
-               idle_source,
-               cal_client_view_emit_progress_idle_cb,
-               signal_closure,
-               (GDestroyNotify) signal_closure_free);
-       g_source_attach (idle_source, main_context);
-       g_source_unref (idle_source);
+               idle_source = g_idle_source_new ();
+               g_source_set_callback (
+                       idle_source,
+                       cal_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_main_context_unref (main_context);
 
-       g_object_unref (client);
+               g_object_unref (client_view);
+       }
 }
 
 static void
 cal_client_view_complete_cb (EGdbusCalView *dbus_proxy,
                              const gchar * const *arg_error,
-                             ECalClientView *client_view)
+                             GWeakRef *client_view_weak_ref)
 {
-       ECalClient *client;
-       GSource *idle_source;
-       GMainContext *main_context;
-       SignalClosure *signal_closure;
+       ECalClientView *client_view;
 
-       if (!client_view->priv->running)
-               return;
+       client_view = g_weak_ref_get (client_view_weak_ref);
 
-       client = e_cal_client_view_ref_client (client_view);
+       if (client_view != NULL) {
+               GSource *idle_source;
+               GMainContext *main_context;
+               SignalClosure *signal_closure;
 
-       /* Suppress any further signal emissions if
-        * our ECalClient has already been finalized. */
-       if (client == NULL)
-               return;
+               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);
-       e_gdbus_templates_decode_error (arg_error, &signal_closure->error);
+               signal_closure = g_slice_new0 (SignalClosure);
+               g_weak_ref_set (&signal_closure->client_view, client_view);
+               e_gdbus_templates_decode_error (
+                       arg_error, &signal_closure->error);
 
-       main_context = cal_client_view_ref_main_context (client_view);
+               main_context = cal_client_view_ref_main_context (client_view);
 
-       idle_source = g_idle_source_new ();
-       g_source_set_callback (
-               idle_source,
-               cal_client_view_emit_complete_idle_cb,
-               signal_closure,
-               (GDestroyNotify) signal_closure_free);
-       g_source_attach (idle_source, main_context);
-       g_source_unref (idle_source);
+               idle_source = g_idle_source_new ();
+               g_source_set_callback (
+                       idle_source,
+                       cal_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);
+               g_main_context_unref (main_context);
 
-       g_object_unref (client);
+               g_object_unref (client_view);
+       }
 }
 
 static void
@@ -688,29 +689,39 @@ cal_client_view_initable_init (GInitable *initable,
 
        priv->dbus_proxy = G_DBUS_PROXY (gdbus_calview);
 
-       handler_id = g_signal_connect (
+       handler_id = g_signal_connect_data (
                priv->dbus_proxy, "objects-added",
-               G_CALLBACK (cal_client_view_objects_added_cb), initable);
+               G_CALLBACK (cal_client_view_objects_added_cb),
+               e_weak_ref_new (initable),
+               (GClosureNotify) e_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 (cal_client_view_objects_modified_cb), initable);
+               G_CALLBACK (cal_client_view_objects_modified_cb),
+               e_weak_ref_new (initable),
+               (GClosureNotify) e_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 (cal_client_view_objects_removed_cb), initable);
+               G_CALLBACK (cal_client_view_objects_removed_cb),
+               e_weak_ref_new (initable),
+               (GClosureNotify) e_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 (cal_client_view_progress_cb), initable);
+               G_CALLBACK (cal_client_view_progress_cb),
+               e_weak_ref_new (initable),
+               (GClosureNotify) e_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 (cal_client_view_complete_cb), initable);
+               G_CALLBACK (cal_client_view_complete_cb),
+               e_weak_ref_new (initable),
+               (GClosureNotify) e_weak_ref_free, 0);
        priv->complete_handler_id = handler_id;
 
        return TRUE;


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