From bd4ffc59a16e2909b70b6844a1f8cbba1d5e4fbf Mon Sep 17 00:00:00 2001 From: Lionel Landwerlin Date: Thu, 29 Aug 2013 23:48:10 +0100 Subject: [PATCH 1/2] ServerConnection: kill async read when disconnecting GSocket creates GSources to provide GInputStream and GOutputStream objects. Interestingly, it doesn't set the GIOCondition on the GSource to handle G_IO_NVAL (ie. your file descriptor is not valid anymore). It means that if your trying to read asynchronously from the socket while someone else closes the socket, you end with an GInputStream that can never complete its asynchronous read operation because the file descriptor isn't valid anymore but that isn't a condition to dispatch the GSource and end the asynchronous read with an error. Alternatively, this wakes up the gmainloop all the time => 100% cpu consumption. https://bugs.freedesktop.org/show_bug.cgi?id=64923 --- src/idle-server-connection.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/idle-server-connection.c b/src/idle-server-connection.c index b593fa3..a921c33 100644 --- a/src/idle-server-connection.c +++ b/src/idle-server-connection.c @@ -71,6 +71,7 @@ struct _IdleServerConnectionPrivate { GSocketClient *socket_client; GIOStream *io_stream; + GCancellable *read_cancellable; GCancellable *cancellable; IdleServerConnectionState state; @@ -245,8 +246,12 @@ static void change_state(IdleServerConnection *conn, IdleServerConnectionState s static void _input_stream_read(IdleServerConnection *conn, GInputStream *input_stream, GAsyncReadyCallback callback) { IdleServerConnectionPrivate *priv = IDLE_SERVER_CONNECTION_GET_PRIVATE(conn); + if (priv->read_cancellable == NULL) + priv->read_cancellable = g_cancellable_new (); + + memset(priv->input_buffer, '\0', sizeof(priv->input_buffer)); - g_input_stream_read_async (input_stream, &priv->input_buffer, sizeof(priv->input_buffer) - 1, G_PRIORITY_DEFAULT, NULL, callback, conn); + g_input_stream_read_async (input_stream, &priv->input_buffer, sizeof(priv->input_buffer) - 1, G_PRIORITY_DEFAULT, priv->read_cancellable, callback, conn); } static void _input_stream_read_ready(GObject *source_object, GAsyncResult *res, gpointer user_data) { @@ -514,6 +519,9 @@ void idle_server_connection_disconnect_full_async(IdleServerConnection *conn, gu priv->reason = reason; + g_cancellable_cancel (priv->read_cancellable); + g_clear_object (&priv->read_cancellable); + result = g_simple_async_result_new(G_OBJECT(conn), callback, user_data, idle_server_connection_disconnect_full_async); g_io_stream_close_async(priv->io_stream, G_PRIORITY_DEFAULT, cancellable, _close_ready, result); g_object_unref(priv->io_stream); -- 1.8.4.rc3