From 9232ac29b40f8a317afd9cb68f7d68dd7aac8950 Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Wed, 29 May 2013 12:18:31 -0400 Subject: Bug 700277 - EClientCache allocates memory ad infinity Remove a ClientData entry on "source-removed" or "source-disabled" signals from the ESourceRegistry. (cherry picked from commit d845222a117a665f25e4d6e110760c8908182336) --- e-util/e-client-cache.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) (limited to 'e-util') diff --git a/e-util/e-client-cache.c b/e-util/e-client-cache.c index 4b48db875a..94530951e0 100644 --- a/e-util/e-client-cache.c +++ b/e-util/e-client-cache.c @@ -49,6 +49,8 @@ typedef struct _SignalClosure SignalClosure; struct _EClientCachePrivate { ESourceRegistry *registry; + gulong source_removed_handler_id; + gulong source_disabled_handler_id; GHashTable *client_ht; GMutex client_ht_lock; @@ -225,6 +227,31 @@ client_ht_lookup (EClientCache *client_cache, return client_data; } +static gboolean +client_ht_remove (EClientCache *client_cache, + ESource *source) +{ + GHashTable *client_ht; + GHashTableIter client_ht_iter; + gpointer inner_ht; + gboolean removed = FALSE; + + g_return_val_if_fail (E_IS_SOURCE (source), FALSE); + + client_ht = client_cache->priv->client_ht; + + g_mutex_lock (&client_cache->priv->client_ht_lock); + + g_hash_table_iter_init (&client_ht_iter, client_ht); + + while (g_hash_table_iter_next (&client_ht_iter, NULL, &inner_ht)) + removed |= g_hash_table_remove (inner_ht, source); + + g_mutex_unlock (&client_cache->priv->client_ht_lock); + + return removed; +} + static gboolean client_cache_emit_backend_died_idle_cb (gpointer user_data) { @@ -626,6 +653,36 @@ client_cache_cal_connect_cb (GObject *source_object, client_data_unref (client_data); } +static void +client_cache_source_removed_cb (ESourceRegistry *registry, + ESource *source, + GWeakRef *weak_ref) +{ + EClientCache *client_cache; + + client_cache = g_weak_ref_get (weak_ref); + + if (client_cache != NULL) { + client_ht_remove (client_cache, source); + g_object_unref (client_cache); + } +} + +static void +client_cache_source_disabled_cb (ESourceRegistry *registry, + ESource *source, + GWeakRef *weak_ref) +{ + EClientCache *client_cache; + + client_cache = g_weak_ref_get (weak_ref); + + if (client_cache != NULL) { + client_ht_remove (client_cache, source); + g_object_unref (client_cache); + } +} + static void client_cache_set_registry (EClientCache *client_cache, ESourceRegistry *registry) @@ -678,6 +735,20 @@ client_cache_dispose (GObject *object) priv = E_CLIENT_CACHE_GET_PRIVATE (object); + if (priv->source_removed_handler_id > 0) { + g_signal_handler_disconnect ( + priv->registry, + priv->source_removed_handler_id); + priv->source_removed_handler_id = 0; + } + + if (priv->source_disabled_handler_id > 0) { + g_signal_handler_disconnect ( + priv->registry, + priv->source_disabled_handler_id); + priv->source_disabled_handler_id = 0; + } + g_clear_object (&priv->registry); g_hash_table_remove_all (priv->client_ht); @@ -708,9 +779,33 @@ client_cache_finalize (GObject *object) static void client_cache_constructed (GObject *object) { + EClientCache *client_cache; + ESourceRegistry *registry; + gulong handler_id; + + client_cache = E_CLIENT_CACHE (object); + /* Chain up to parent's constructed() method. */ G_OBJECT_CLASS (e_client_cache_parent_class)->constructed (object); + registry = e_client_cache_ref_registry (client_cache); + + handler_id = g_signal_connect_data ( + registry, "source-removed", + G_CALLBACK (client_cache_source_removed_cb), + e_weak_ref_new (client_cache), + (GClosureNotify) e_weak_ref_free, 0); + client_cache->priv->source_removed_handler_id = handler_id; + + handler_id = g_signal_connect_data ( + registry, "source-disabled", + G_CALLBACK (client_cache_source_disabled_cb), + e_weak_ref_new (client_cache), + (GClosureNotify) e_weak_ref_free, 0); + client_cache->priv->source_disabled_handler_id = handler_id; + + g_object_unref (registry); + e_extensible_load_extensions (E_EXTENSIBLE (object)); } -- cgit v1.2.3