telepathy-idle: ServerConnection: kill async read when disconnecting

Simon McVittie smcv at kemper.freedesktop.org
Thu Sep 5 05:50:18 PDT 2013


Module: telepathy-idle
Branch: master
Commit: 42fd234c2336718a93993829c4d55c819b172012
URL:    http://cgit.freedesktop.org/telepathy/telepathy-idle/commit/?id=42fd234c2336718a93993829c4d55c819b172012

Author: Lionel Landwerlin <llandwerlin at gmail.com>
Date:   Thu Aug 29 23:48:10 2013 +0100

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.

Bug: https://bugs.freedesktop.org/show_bug.cgi?id=64923
Reviewed-by: Simon McVittie <simon.mcvittie at collabora.co.uk>

---

 src/idle-server-connection.c |   10 +++++++++-
 1 files changed, 9 insertions(+), 1 deletions(-)

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);



More information about the telepathy-commits mailing list