diff options
author | Beniamino Galvani <bgalvani@redhat.com> | 2015-09-30 16:26:38 +0200 |
---|---|---|
committer | Beniamino Galvani <bgalvani@redhat.com> | 2015-10-03 09:51:32 +0200 |
commit | 7c5518ac8d8c173bbf74489d292aa6f4c979b3a0 (patch) | |
tree | 767e1db877fd9cc7d5f12782658f39f0f2f439e6 | |
parent | 18b20c4f6f9f2961ea79c96b9a56116d556103c9 (diff) | |
download | NetworkManager-7c5518ac8d8c173bbf74489d292aa6f4c979b3a0.tar.gz |
bus-manager: fix handling of incoming signals
The 'new-connection' signal of a GDBusServer is emitted by default
through an idle source and the actual message processing starts only
after a signal handler returns TRUE.
Thus, before the signal handler has the chance to run, the GDBus
worker thread may detect that the connection is closed and schedule
the delivery of the 'closed' signal through another idle source.
After the termination of the 'new-connection' handler, the 'closed'
handler is executed, which cancels the subscription to GDBus signals
before any message has been processed.
This looks like a bug in GDBusServer; to work around it, just delay
the close of connection to let the signal dispatch run first.
https://bugzilla.gnome.org/show_bug.cgi?id=755170
-rw-r--r-- | src/nm-bus-manager.c | 53 |
1 files changed, 41 insertions, 12 deletions
diff --git a/src/nm-bus-manager.c b/src/nm-bus-manager.c index c573f2fcd1..22a1c98098 100644 --- a/src/nm-bus-manager.c +++ b/src/nm-bus-manager.c @@ -166,6 +166,38 @@ struct _PrivateServer { NMBusManager *manager; }; +typedef struct { + GDBusConnection *connection; + PrivateServer *server; + gboolean remote_peer_vanished; +} CloseConnectionInfo; + +static gboolean +close_connection_in_idle (gpointer user_data) +{ + CloseConnectionInfo *info = user_data; + PrivateServer *server = info->server; + + /* Emit this for the manager */ + g_signal_emit (server->manager, + signals[PRIVATE_CONNECTION_DISCONNECTED], + server->detail, + info->connection); + + /* FIXME: there's a bug (754730) in GLib for which the connection + * is marked as closed when the remote peer vanishes but its + * resources are not cleaned up. Work around it by explicitly + * closing the connection in that case. */ + if (info->remote_peer_vanished) + g_dbus_connection_close (info->connection, NULL, NULL, NULL); + + g_hash_table_remove (server->connections, info->connection); + g_object_unref (server->manager); + g_slice_free (CloseConnectionInfo, info); + + return G_SOURCE_REMOVE; +} + static void private_server_closed (GDBusConnection *conn, gboolean remote_peer_vanished, @@ -173,25 +205,22 @@ private_server_closed (GDBusConnection *conn, gpointer user_data) { PrivateServer *s = user_data; + CloseConnectionInfo *info; /* Clean up after the connection */ nm_log_dbg (LOGD_CORE, "(%s) closed connection %p on private socket.", s->tag, conn); - /* Emit this for the manager */ - g_signal_emit (s->manager, - signals[PRIVATE_CONNECTION_DISCONNECTED], - s->detail, - conn); + info = g_slice_new0 (CloseConnectionInfo); + info->connection = conn; + info->server = s; + info->remote_peer_vanished = remote_peer_vanished; - /* FIXME: there's a bug (754730) in GLib for which the connection - * is marked as closed when the remote peer vanishes but its - * resources are not cleaned up. Work around it by explicitly - * closing the connection in that case. */ - if (remote_peer_vanished) - g_dbus_connection_close (conn, NULL, NULL, NULL); + g_object_ref (s->manager); - g_hash_table_remove (s->connections, conn); + /* Delay the close of connection to ensure that D-Bus signals + * are handled */ + g_idle_add (close_connection_in_idle, info); } static gboolean |