[evolution-data-server] EDataFactory: Free backend when no client connects to it
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server] EDataFactory: Free backend when no client connects to it
- Date: Wed, 7 Aug 2019 11:53:09 +0000 (UTC)
commit b4fb065d191c5da3bd19cf7952ddef26b10a4949
Author: Milan Crha <mcrha redhat com>
Date: Wed Aug 7 13:49:32 2019 +0200
EDataFactory: Free backend when no client connects to it
This did not work properly with backend-per-process disabled, thus backends
could be left running even when no client had them opened, which could
prevent auto-close of the factory process.
The fix contains also a change no avoid circular reference between the backend
and its view, where view added its own reference to the associated backend and
the backend added a reference to the view when it had been added into
the backend. This could prevent free of the backend when any view was not
properly freed by the client.
.../backends/ldap/e-book-backend-ldap.c | 12 ++-
src/addressbook/libedata-book/e-book-backend.c | 8 +-
.../libedata-book/e-data-book-factory.c | 2 +-
src/addressbook/libedata-book/e-data-book-view.c | 86 +++++++++++++---
src/addressbook/libedata-book/e-data-book-view.h | 4 +
src/calendar/libedata-cal/e-cal-backend.c | 6 +-
src/calendar/libedata-cal/e-data-cal-factory.c | 2 +-
src/calendar/libedata-cal/e-data-cal-view.c | 111 +++++++++++++++-----
src/calendar/libedata-cal/e-data-cal-view.h | 4 +
src/libebackend/e-data-factory.c | 114 ++++++++++++++++++++-
src/libebackend/e-data-factory.h | 4 +
11 files changed, 299 insertions(+), 54 deletions(-)
---
diff --git a/src/addressbook/backends/ldap/e-book-backend-ldap.c
b/src/addressbook/backends/ldap/e-book-backend-ldap.c
index 9ea955b83..90500b633 100644
--- a/src/addressbook/backends/ldap/e-book-backend-ldap.c
+++ b/src/addressbook/backends/ldap/e-book-backend-ldap.c
@@ -4398,22 +4398,28 @@ ldap_search_handler (LDAPOp *op,
static void
ldap_search_dtor (LDAPOp *op)
{
+ EBookBackend *backend;
EBookBackendLDAP *bl;
LDAPSearchOp *search_op = (LDAPSearchOp *) op;
d (printf ("ldap_search_dtor (%p)\n", search_op->view));
- bl = E_BOOK_BACKEND_LDAP (e_data_book_view_get_backend (op->view));
+ backend = e_data_book_view_ref_backend (op->view);
+ bl = backend ? E_BOOK_BACKEND_LDAP (backend) : NULL;
/* unhook us from our EDataBookView */
- g_mutex_lock (&bl->priv->view_mutex);
+ if (bl)
+ g_mutex_lock (&bl->priv->view_mutex);
g_object_set_data (G_OBJECT (search_op->view), LDAP_SEARCH_OP_IDENT, NULL);
- g_mutex_unlock (&bl->priv->view_mutex);
+ if (bl)
+ g_mutex_unlock (&bl->priv->view_mutex);
g_object_unref (search_op->view);
if (!search_op->aborted)
g_free (search_op);
+
+ g_clear_object (&backend);
}
static void
diff --git a/src/addressbook/libedata-book/e-book-backend.c b/src/addressbook/libedata-book/e-book-backend.c
index a8639c86d..f2fb21ab1 100644
--- a/src/addressbook/libedata-book/e-book-backend.c
+++ b/src/addressbook/libedata-book/e-book-backend.c
@@ -515,10 +515,10 @@ book_backend_dispose (GObject *object)
g_clear_object (&priv->proxy_resolver);
g_clear_object (&priv->authentication_source);
- if (priv->views != NULL) {
- g_list_free (priv->views);
- priv->views = NULL;
- }
+ g_mutex_lock (&priv->views_mutex);
+ g_list_free_full (priv->views, g_object_unref);
+ priv->views = NULL;
+ g_mutex_unlock (&priv->views_mutex);
g_hash_table_remove_all (priv->operation_ids);
diff --git a/src/addressbook/libedata-book/e-data-book-factory.c
b/src/addressbook/libedata-book/e-data-book-factory.c
index 5527d58d8..35850f2bb 100644
--- a/src/addressbook/libedata-book/e-data-book-factory.c
+++ b/src/addressbook/libedata-book/e-data-book-factory.c
@@ -121,7 +121,7 @@ data_book_factory_backend_closed_cb (EBackend *backend,
const gchar *sender,
EDataFactory *data_factory)
{
- e_data_factory_backend_closed (data_factory, backend);
+ e_data_factory_backend_closed_by_sender (data_factory, backend, sender);
}
static EBackend *
diff --git a/src/addressbook/libedata-book/e-data-book-view.c
b/src/addressbook/libedata-book/e-data-book-view.c
index ee259f865..fbf0f9c28 100644
--- a/src/addressbook/libedata-book/e-data-book-view.c
+++ b/src/addressbook/libedata-book/e-data-book-view.c
@@ -57,7 +57,7 @@ struct _EDataBookViewPrivate {
EDBusAddressBookView *dbus_object;
gchar *object_path;
- EBookBackend *backend;
+ GWeakRef backend_weakref; /* EBookBackend * */
EBookBackendSExp *sexp;
EBookClientViewFlags flags;
@@ -224,13 +224,19 @@ bookview_start_thread (gpointer data)
EDataBookView *view = data;
if (view->priv->running) {
- /* To avoid race condition when one thread is starting the view, while
- another thread wants to notify about created/modified/removed objects. */
- e_book_backend_sexp_lock (view->priv->sexp);
+ EBookBackend *backend = e_data_book_view_ref_backend (view);
+
+ if (backend) {
+ /* To avoid race condition when one thread is starting the view, while
+ another thread wants to notify about created/modified/removed objects. */
+ e_book_backend_sexp_lock (view->priv->sexp);
+
+ e_book_backend_start_view (backend, view);
- e_book_backend_start_view (view->priv->backend, view);
+ e_book_backend_sexp_unlock (view->priv->sexp);
- e_book_backend_sexp_unlock (view->priv->sexp);
+ g_object_unref (backend);
+ }
}
g_object_unref (view);
@@ -262,8 +268,14 @@ bookview_stop_thread (gpointer data)
{
EDataBookView *view = data;
- if (!view->priv->running)
- e_book_backend_stop_view (view->priv->backend, view);
+ if (!view->priv->running) {
+ EBookBackend *backend = e_data_book_view_ref_backend (view);
+
+ if (backend) {
+ e_book_backend_stop_view (backend, view);
+ g_object_unref (backend);
+ }
+ }
g_object_unref (view);
return NULL;
@@ -306,11 +318,21 @@ impl_DataBookView_dispose (EDBusAddressBookView *object,
GDBusMethodInvocation *invocation,
EDataBookView *view)
{
+ EBookBackend *backend;
+
e_dbus_address_book_view_complete_dispose (object, invocation);
- e_book_backend_stop_view (view->priv->backend, view);
- view->priv->running = FALSE;
- e_book_backend_remove_view (view->priv->backend, view);
+ backend = e_data_book_view_ref_backend (view);
+
+ if (backend) {
+ e_book_backend_stop_view (backend, view);
+ view->priv->running = FALSE;
+ e_book_backend_remove_view (backend, view);
+
+ g_object_unref (backend);
+ } else {
+ view->priv->running = FALSE;
+ }
return TRUE;
}
@@ -366,9 +388,8 @@ data_book_view_set_backend (EDataBookView *view,
EBookBackend *backend)
{
g_return_if_fail (E_IS_BOOK_BACKEND (backend));
- g_return_if_fail (view->priv->backend == NULL);
- view->priv->backend = g_object_ref (backend);
+ g_weak_ref_set (&view->priv->backend_weakref, backend);
}
static void
@@ -444,9 +465,9 @@ data_book_view_get_property (GObject *object,
{
switch (property_id) {
case PROP_BACKEND:
- g_value_set_object (
+ g_value_take_object (
value,
- e_data_book_view_get_backend (
+ e_data_book_view_ref_backend (
E_DATA_BOOK_VIEW (object)));
return;
@@ -493,9 +514,10 @@ data_book_view_dispose (GObject *object)
g_clear_object (&priv->connection);
g_clear_object (&priv->dbus_object);
- g_clear_object (&priv->backend);
g_clear_object (&priv->sexp);
+ g_weak_ref_set (&priv->backend_weakref, NULL);
+
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (e_data_book_view_parent_class)->dispose (object);
}
@@ -520,6 +542,7 @@ data_book_view_finalize (GObject *object)
g_hash_table_destroy (priv->fields_of_interest);
g_mutex_clear (&priv->pending_mutex);
+ g_weak_ref_clear (&priv->backend_weakref);
g_hash_table_destroy (priv->ids);
@@ -618,6 +641,8 @@ e_data_book_view_init (EDataBookView *view)
{
view->priv = E_DATA_BOOK_VIEW_GET_PRIVATE (view);
+ g_weak_ref_init (&view->priv->backend_weakref, NULL);
+
view->priv->flags = E_BOOK_CLIENT_VIEW_FLAGS_NOTIFY_INITIAL;
view->priv->dbus_object = e_dbus_address_book_view_skeleton_new ();
@@ -693,6 +718,25 @@ e_data_book_view_new (EBookBackend *backend,
"sexp", sexp, NULL);
}
+/**
+ * e_data_book_view_ref_backend:
+ * @view: an #EDataBookView
+ *
+ * Refs the backend that @view is querying. Unref the returned backend,
+ * if not %NULL, with g_object_unref(), when no longer needed.
+ *
+ * Returns: (type EBookBackend) (transfer full) (nullable): The associated #EBookBackend.
+ *
+ * Since: 3.34
+ **/
+EBookBackend *
+e_data_book_view_ref_backend (EDataBookView *view)
+{
+ g_return_val_if_fail (E_IS_DATA_BOOK_VIEW (view), NULL);
+
+ return g_weak_ref_get (&view->priv->backend_weakref);
+}
+
/**
* e_data_book_view_get_backend:
* @view: an #EDataBookView
@@ -700,13 +744,21 @@ e_data_book_view_new (EBookBackend *backend,
* Gets the backend that @view is querying.
*
* Returns: (type EBookBackend) (transfer none): The associated #EBookBackend.
+ *
+ * Deprecated: 3.34: Use e_data_book_view_ref_backend() instead.
**/
EBookBackend *
e_data_book_view_get_backend (EDataBookView *view)
{
+ EBookBackend *backend;
+
g_return_val_if_fail (E_IS_DATA_BOOK_VIEW (view), NULL);
- return view->priv->backend;
+ backend = e_data_book_view_ref_backend (view);
+ if (backend)
+ g_object_unref (backend);
+
+ return backend;
}
/**
diff --git a/src/addressbook/libedata-book/e-data-book-view.h
b/src/addressbook/libedata-book/e-data-book-view.h
index de24ca717..887b8dc48 100644
--- a/src/addressbook/libedata-book/e-data-book-view.h
+++ b/src/addressbook/libedata-book/e-data-book-view.h
@@ -73,8 +73,12 @@ EDataBookView * e_data_book_view_new (struct _EBookBackend *backend,
GDBusConnection *connection,
const gchar *object_path,
GError **error);
+struct _EBookBackend *
+ e_data_book_view_ref_backend (EDataBookView *view);
+#ifndef EDS_DISABLE_DEPRECATED
struct _EBookBackend *
e_data_book_view_get_backend (EDataBookView *view);
+#endif /* EDS_DISABLE_DEPRECATED */
GDBusConnection *
e_data_book_view_get_connection (EDataBookView *view);
const gchar * e_data_book_view_get_object_path
diff --git a/src/calendar/libedata-cal/e-cal-backend.c b/src/calendar/libedata-cal/e-cal-backend.c
index 77ca1eb36..3c94401c0 100644
--- a/src/calendar/libedata-cal/e-cal-backend.c
+++ b/src/calendar/libedata-cal/e-cal-backend.c
@@ -649,6 +649,11 @@ cal_backend_dispose (GObject *object)
g_clear_object (&priv->proxy_resolver);
g_clear_object (&priv->authentication_source);
+ g_mutex_lock (&priv->views_mutex);
+ g_list_free_full (priv->views, g_object_unref);
+ priv->views = NULL;
+ g_mutex_unlock (&priv->views_mutex);
+
g_hash_table_remove_all (priv->operation_ids);
while (!g_queue_is_empty (&priv->pending_operations))
@@ -667,7 +672,6 @@ cal_backend_finalize (GObject *object)
priv = E_CAL_BACKEND_GET_PRIVATE (object);
- g_list_free (priv->views);
g_mutex_clear (&priv->views_mutex);
g_mutex_clear (&priv->property_lock);
diff --git a/src/calendar/libedata-cal/e-data-cal-factory.c b/src/calendar/libedata-cal/e-data-cal-factory.c
index 5a4de310a..efb0d745d 100644
--- a/src/calendar/libedata-cal/e-data-cal-factory.c
+++ b/src/calendar/libedata-cal/e-data-cal-factory.c
@@ -149,7 +149,7 @@ data_cal_factory_backend_closed_cb (EBackend *backend,
const gchar *sender,
EDataFactory *data_factory)
{
- e_data_factory_backend_closed (data_factory, backend);
+ e_data_factory_backend_closed_by_sender (data_factory, backend, sender);
}
static EBackend *
diff --git a/src/calendar/libedata-cal/e-data-cal-view.c b/src/calendar/libedata-cal/e-data-cal-view.c
index 1c8edb77f..6452b5d31 100644
--- a/src/calendar/libedata-cal/e-data-cal-view.c
+++ b/src/calendar/libedata-cal/e-data-cal-view.c
@@ -57,7 +57,7 @@ struct _EDataCalViewPrivate {
gchar *object_path;
/* The backend we are monitoring */
- ECalBackend *backend;
+ GWeakRef backend_weakref; /* ECalBackend * */
gboolean started;
gboolean stopped;
@@ -161,13 +161,19 @@ calview_start_thread (gpointer data)
EDataCalView *view = data;
if (view->priv->started && !view->priv->stopped) {
- /* To avoid race condition when one thread is starting the view, while
- another thread wants to notify about created/modified/removed objects. */
- e_cal_backend_sexp_lock (view->priv->sexp);
+ ECalBackend *backend = e_data_cal_view_ref_backend (view);
+
+ if (backend) {
+ /* To avoid race condition when one thread is starting the view, while
+ another thread wants to notify about created/modified/removed objects. */
+ e_cal_backend_sexp_lock (view->priv->sexp);
+
+ e_cal_backend_start_view (backend, view);
- e_cal_backend_start_view (view->priv->backend, view);
+ e_cal_backend_sexp_unlock (view->priv->sexp);
- e_cal_backend_sexp_unlock (view->priv->sexp);
+ g_object_unref (backend);
+ }
}
g_object_unref (view);
@@ -181,6 +187,7 @@ impl_DataCalView_start (EDBusCalendarView *object,
EDataCalView *view)
{
if (!view->priv->started) {
+ ECalBackend *backend = e_data_cal_view_ref_backend (view);
GThread *thread;
view->priv->started = TRUE;
@@ -188,7 +195,9 @@ impl_DataCalView_start (EDBusCalendarView *object,
FALSE, E_DEBUG_LOG_DOMAIN_CAL_QUERIES,
"---;%p;VIEW-START;%s;%s", view,
e_cal_backend_sexp_text (view->priv->sexp),
- G_OBJECT_TYPE_NAME (view->priv->backend));
+ backend ? G_OBJECT_TYPE_NAME (backend) : "null backend");
+
+ g_clear_object (&backend);
thread = g_thread_new (
NULL, calview_start_thread, g_object_ref (view));
@@ -205,8 +214,14 @@ calview_stop_thread (gpointer data)
{
EDataCalView *view = data;
- if (view->priv->stopped)
- e_cal_backend_stop_view (view->priv->backend, view);
+ if (view->priv->stopped) {
+ ECalBackend *backend = e_data_cal_view_ref_backend (view);
+
+ if (backend) {
+ e_cal_backend_stop_view (backend, view);
+ g_object_unref (backend);
+ }
+ }
g_object_unref (view);
return NULL;
@@ -247,11 +262,21 @@ impl_DataCalView_dispose (EDBusCalendarView *object,
GDBusMethodInvocation *invocation,
EDataCalView *view)
{
+ ECalBackend *backend;
+
e_dbus_calendar_view_complete_dispose (object, invocation);
- e_cal_backend_stop_view (view->priv->backend, view);
- view->priv->stopped = TRUE;
- e_cal_backend_remove_view (view->priv->backend, view);
+ backend = e_data_cal_view_ref_backend (view);
+
+ if (backend) {
+ e_cal_backend_stop_view (backend, view);
+ view->priv->stopped = TRUE;
+ e_cal_backend_remove_view (backend, view);
+
+ g_object_unref (backend);
+ } else {
+ view->priv->stopped = TRUE;
+ }
return TRUE;
}
@@ -300,9 +325,8 @@ data_cal_view_set_backend (EDataCalView *view,
ECalBackend *backend)
{
g_return_if_fail (E_IS_CAL_BACKEND (backend));
- g_return_if_fail (view->priv->backend == NULL);
- view->priv->backend = g_object_ref (backend);
+ g_weak_ref_set (&view->priv->backend_weakref, backend);
}
static void
@@ -378,9 +402,9 @@ data_cal_view_get_property (GObject *object,
{
switch (property_id) {
case PROP_BACKEND:
- g_value_set_object (
+ g_value_take_object (
value,
- e_data_cal_view_get_backend (
+ e_data_cal_view_ref_backend (
E_DATA_CAL_VIEW (object)));
return;
@@ -427,9 +451,10 @@ data_cal_view_dispose (GObject *object)
g_clear_object (&priv->connection);
g_clear_object (&priv->dbus_object);
- g_clear_object (&priv->backend);
g_clear_object (&priv->sexp);
+ g_weak_ref_set (&priv->backend_weakref, NULL);
+
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (e_data_cal_view_parent_class)->dispose (object);
}
@@ -457,6 +482,7 @@ data_cal_view_finalize (GObject *object)
g_hash_table_destroy (priv->fields_of_interest);
g_mutex_clear (&priv->pending_mutex);
+ g_weak_ref_clear (&priv->backend_weakref);
/* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (e_data_cal_view_parent_class)->finalize (object);
@@ -572,7 +598,7 @@ e_data_cal_view_init (EDataCalView *view)
view->priv->dbus_object, "handle-set-fields-of-interest",
G_CALLBACK (impl_DataCalView_set_fields_of_interest), view);
- view->priv->backend = NULL;
+ g_weak_ref_init (&view->priv->backend_weakref, NULL);
view->priv->started = FALSE;
view->priv->stopped = FALSE;
view->priv->complete = FALSE;
@@ -811,6 +837,25 @@ notify_remove (EDataCalView *view,
ensure_pending_flush_timeout (view);
}
+/**
+ * e_data_cal_view_ref_backend:
+ * @view: an #EDataCalView
+ *
+ * Refs the backend that @view is querying. Unref the returned backend,
+ * if not %NULL, with g_object_unref(), when no longer needed.
+ *
+ * Returns: (type ECalBackend) (transfer full) (nullable): The associated #ECalBackend.
+ *
+ * Since: 3.34
+ **/
+ECalBackend *
+e_data_cal_view_ref_backend (EDataCalView *view)
+{
+ g_return_val_if_fail (E_IS_DATA_CAL_VIEW (view), NULL);
+
+ return g_weak_ref_get (&view->priv->backend_weakref);
+}
+
/**
* e_data_cal_view_get_backend:
* @view: an #EDataCalView
@@ -820,13 +865,21 @@ notify_remove (EDataCalView *view,
* Returns: (transfer none): The associated #ECalBackend.
*
* Since: 3.8
+ *
+ * Deprecated: 3.34: Use e_data_cal_view_ref_backend() instead.
**/
ECalBackend *
e_data_cal_view_get_backend (EDataCalView *view)
{
+ ECalBackend *backend;
+
g_return_val_if_fail (E_IS_DATA_CAL_VIEW (view), NULL);
- return view->priv->backend;
+ backend = e_data_cal_view_ref_backend (view);
+ if (backend)
+ g_object_unref (backend);
+
+ return backend;
}
/**
@@ -901,15 +954,19 @@ e_data_cal_view_object_matches (EDataCalView *view,
{
ECalBackend *backend;
ECalBackendSExp *sexp;
+ gboolean res;
g_return_val_if_fail (E_IS_DATA_CAL_VIEW (view), FALSE);
g_return_val_if_fail (object != NULL, FALSE);
sexp = e_data_cal_view_get_sexp (view);
- backend = e_data_cal_view_get_backend (view);
+ backend = e_data_cal_view_ref_backend (view);
+
+ res = e_cal_backend_sexp_match_object (sexp, object, backend ? E_TIMEZONE_CACHE (backend) : NULL);
+
+ g_clear_object (&backend);
- return e_cal_backend_sexp_match_object (
- sexp, object, E_TIMEZONE_CACHE (backend));
+ return res;
}
/**
@@ -930,15 +987,19 @@ e_data_cal_view_component_matches (EDataCalView *view,
{
ECalBackend *backend;
ECalBackendSExp *sexp;
+ gboolean res;
g_return_val_if_fail (E_IS_DATA_CAL_VIEW (view), FALSE);
g_return_val_if_fail (E_IS_CAL_COMPONENT (component), FALSE);
sexp = e_data_cal_view_get_sexp (view);
- backend = e_data_cal_view_get_backend (view);
+ backend = e_data_cal_view_ref_backend (view);
+
+ res = e_cal_backend_sexp_match_comp (sexp, component, backend ? E_TIMEZONE_CACHE (backend) : NULL);
- return e_cal_backend_sexp_match_comp (
- sexp, component, E_TIMEZONE_CACHE (backend));
+ g_clear_object (&backend);
+
+ return res;
}
/**
diff --git a/src/calendar/libedata-cal/e-data-cal-view.h b/src/calendar/libedata-cal/e-data-cal-view.h
index bf25ec37b..177427baa 100644
--- a/src/calendar/libedata-cal/e-data-cal-view.h
+++ b/src/calendar/libedata-cal/e-data-cal-view.h
@@ -69,8 +69,12 @@ EDataCalView * e_data_cal_view_new (struct _ECalBackend *backend,
GDBusConnection *connection,
const gchar *object_path,
GError **error);
+struct _ECalBackend *
+ e_data_cal_view_ref_backend (EDataCalView *view);
+#ifndef EDS_DISABLE_DEPRECATED
struct _ECalBackend *
e_data_cal_view_get_backend (EDataCalView *view);
+#endif /* EDS_DISABLE_DEPRECATED */
GDBusConnection *
e_data_cal_view_get_connection (EDataCalView *view);
const gchar * e_data_cal_view_get_object_path (EDataCalView *view);
diff --git a/src/libebackend/e-data-factory.c b/src/libebackend/e-data-factory.c
index 865773430..68b2970b5 100644
--- a/src/libebackend/e-data-factory.c
+++ b/src/libebackend/e-data-factory.c
@@ -69,6 +69,11 @@ struct _EDataFactoryPrivate {
GHashTable *connections;
GRecMutex connections_lock;
+ /* Holds array of opened backends for each client.
+ Used only when not using backend-per-process.
+ Reuses the 'connections_lock'. */
+ GHashTable *backend_clients; /* gchar *sender ~> GPtrArray { GWeakRef { EBackend }} */
+
/* This is a hash table of client bus names being watched.
* The value is the watcher ID for g_bus_unwatch_name(). */
GHashTable *watched_names;
@@ -340,6 +345,78 @@ data_factory_dup_subprocess_helper_hash_key (const gchar *factory_name,
return helper_hash_key;
}
+static void
+data_factory_add_backend_client (EDataFactory *data_factory,
+ EBackend *backend,
+ const gchar *sender)
+{
+ GPtrArray *array;
+
+ g_return_if_fail (E_IS_DATA_FACTORY (data_factory));
+ g_return_if_fail (E_IS_BACKEND (backend));
+ g_return_if_fail (sender != NULL);
+
+ g_rec_mutex_lock (&data_factory->priv->connections_lock);
+
+ array = g_hash_table_lookup (data_factory->priv->backend_clients, sender);
+ if (!array) {
+ array = g_ptr_array_new_with_free_func ((GDestroyNotify) e_weak_ref_free);
+ g_hash_table_insert (data_factory->priv->backend_clients, g_strdup (sender), array);
+ }
+
+ g_ptr_array_add (array, e_weak_ref_new (backend));
+
+ g_rec_mutex_unlock (&data_factory->priv->connections_lock);
+}
+
+static void
+data_factory_remove_backend_client (EDataFactory *data_factory,
+ EBackend *backend,
+ const gchar *sender)
+{
+ GPtrArray *array;
+ guint ii;
+
+ g_return_if_fail (E_IS_DATA_FACTORY (data_factory));
+ if (backend)
+ g_return_if_fail (E_IS_BACKEND (backend));
+ g_return_if_fail (sender != NULL);
+
+ g_rec_mutex_lock (&data_factory->priv->connections_lock);
+
+ array = g_hash_table_lookup (data_factory->priv->backend_clients, sender);
+ if (array) {
+ for (ii = 0; ii < array->len; ii++) {
+ GWeakRef *weakref;
+ EBackend *stored_backend;
+
+ weakref = g_ptr_array_index (array, ii);
+ stored_backend = g_weak_ref_get (weakref);
+
+ if (backend) {
+ if (stored_backend == backend) {
+ g_ptr_array_remove_index (array, ii);
+ /* One client can connect to one backend multiple times, thus
+ remove only one item from the array. */
+ g_clear_object (&stored_backend);
+ break;
+ }
+ } else if (stored_backend) {
+ /* Do not provide 'sender', because it would call this function again,
+ causing unnecessary recursion. */
+ e_data_factory_backend_closed_by_sender (data_factory, stored_backend, NULL);
+ }
+
+ g_clear_object (&stored_backend);
+ }
+
+ if (!array->len)
+ g_hash_table_remove (data_factory->priv->backend_clients, sender);
+ }
+
+ g_rec_mutex_unlock (&data_factory->priv->connections_lock);
+}
+
static gboolean
data_factory_verify_subprocess_backend_proxy_is_used (EDataFactory *data_factory,
const gchar *except_bus_name,
@@ -470,6 +547,8 @@ data_factory_name_vanished_cb (GDBusConnection *connection,
if (data_factory != NULL) {
data_factory_connections_remove (data_factory, name, NULL);
+ data_factory_remove_backend_client (data_factory, NULL, name);
+
/* Unwatching the bus name from here will corrupt the
* 'name' argument, and possibly also the 'user_data'.
*
@@ -955,6 +1034,7 @@ data_factory_dispose (GObject *object)
g_clear_object (&priv->registry);
g_hash_table_remove_all (priv->connections);
+ g_hash_table_remove_all (priv->backend_clients);
g_hash_table_remove_all (priv->watched_names);
/* Chain up to parent's dispose() method. */
@@ -981,6 +1061,8 @@ data_factory_finalize (GObject *object)
g_hash_table_destroy (priv->connections);
g_rec_mutex_clear (&priv->connections_lock);
+ g_hash_table_destroy (priv->backend_clients);
+
g_hash_table_destroy (priv->watched_names);
g_mutex_clear (&priv->watched_names_lock);
@@ -1147,6 +1229,8 @@ e_data_factory_init (EDataFactory *data_factory)
(GDestroyNotify) g_free,
(GDestroyNotify) g_ptr_array_unref);
+ data_factory->priv->backend_clients = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
(GDestroyNotify) g_ptr_array_unref);
+
data_factory->priv->watched_names = g_hash_table_new_full (
(GHashFunc) g_str_hash,
(GEqualFunc) g_str_equal,
@@ -1366,6 +1450,7 @@ data_factory_spawn_subprocess_backend (EDataFactory *data_factory,
if (!backend_per_process && backend_factory) {
gchar *object_path = NULL, *backend_key;
OpenedBackendData *obd;
+ EBackend *backend = NULL;
backend_key = g_strconcat (backend_name, "\n", uid, "\n", extension_name, NULL);
@@ -1374,6 +1459,7 @@ data_factory_spawn_subprocess_backend (EDataFactory *data_factory,
if (obd) {
object_path = g_strdup (obd->object_path);
g_object_ref (obd->backend);
+ backend = obd->backend;
/* Also drop the "reference" on the data_factory, it's held by the obj->backend
already */
e_dbus_server_release (E_DBUS_SERVER (data_factory));
@@ -1381,8 +1467,6 @@ data_factory_spawn_subprocess_backend (EDataFactory *data_factory,
g_mutex_unlock (&data_factory->priv->mutex);
if (!object_path) {
- EBackend *backend;
-
backend = e_data_factory_create_backend (data_factory, backend_factory, source);
object_path = e_data_factory_open_backend (data_factory, backend,
g_dbus_method_invocation_get_connection (invocation), NULL, &error);
if (object_path) {
@@ -1407,8 +1491,18 @@ data_factory_spawn_subprocess_backend (EDataFactory *data_factory,
}
if (object_path) {
+ GDBusConnection *connection;
+ const gchar *sender;
+
class->complete_open (data_factory, invocation, object_path, server_class->bus_name,
extension_name);
+ connection = g_dbus_method_invocation_get_connection (invocation);
+ sender = g_dbus_method_invocation_get_sender (invocation);
+
+ data_factory_watched_names_add (data_factory, connection, sender);
+
+ data_factory_add_backend_client (data_factory, backend, sender);
+
g_mutex_lock (&priv->spawn_subprocess_lock);
priv->spawn_subprocess_state = DATA_FACTORY_SPAWN_SUBPROCESS_NONE;
g_cond_signal (&priv->spawn_subprocess_cond);
@@ -1692,6 +1786,22 @@ e_data_factory_backend_closed (EDataFactory *data_factory,
g_return_if_fail (E_IS_DATA_FACTORY (data_factory));
g_return_if_fail (E_IS_BACKEND (backend));
+ e_data_factory_backend_closed_by_sender (data_factory, backend, NULL);
+}
+
+void
+e_data_factory_backend_closed_by_sender (EDataFactory *data_factory,
+ EBackend *backend,
+ const gchar *sender)
+{
+ g_return_if_fail (E_IS_DATA_FACTORY (data_factory));
+ g_return_if_fail (E_IS_BACKEND (backend));
+
+ /* Call only when 'sender' is not NULL, to avoid recursion when
+ data_factory_remove_backend_client() calls this function on its own. */
+ if (sender)
+ data_factory_remove_backend_client (data_factory, backend, sender);
+
g_object_unref (backend);
}
diff --git a/src/libebackend/e-data-factory.h b/src/libebackend/e-data-factory.h
index 7255f56a8..f80e5a15d 100644
--- a/src/libebackend/e-data-factory.h
+++ b/src/libebackend/e-data-factory.h
@@ -128,6 +128,10 @@ gchar * e_data_factory_open_backend (EDataFactory *data_factory,
GError **error);
void e_data_factory_backend_closed (EDataFactory *data_factory,
EBackend *backend);
+void e_data_factory_backend_closed_by_sender
+ (EDataFactory *data_factory,
+ EBackend *backend,
+ const gchar *sender);
GSList * e_data_factory_list_opened_backends /* EBackend * */
(EDataFactory *data_factory);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]