summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBeniamino Galvani <bgalvani@redhat.com>2015-09-30 16:26:38 +0200
committerBeniamino Galvani <bgalvani@redhat.com>2015-10-03 09:51:32 +0200
commit7c5518ac8d8c173bbf74489d292aa6f4c979b3a0 (patch)
tree767e1db877fd9cc7d5f12782658f39f0f2f439e6
parent18b20c4f6f9f2961ea79c96b9a56116d556103c9 (diff)
downloadNetworkManager-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.c53
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