[glib] GSocketInput/OutputStream: fix non-blocking on Windows



commit e0ff84e68817d12ebf4cde9433c4e1ed703d1eb4
Author: Dan Winship <danw gnome org>
Date:   Fri Apr 23 08:21:41 2010 -0400

    GSocketInput/OutputStream: fix non-blocking on Windows
    
    The GSocket docs point out that g_socket_send/g_socket_receive may
    return G_IO_ERROR_WOULD_BLOCK even if g_socket_condition_check claimed
    that they wouldn't. Fix the socket streams to check for that.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=603309

 gio/gsocket.c             |    8 +++++++
 gio/gsocketinputstream.c  |   46 +++++++++++++++++---------------------------
 gio/gsocketoutputstream.c |   46 +++++++++++++++++---------------------------
 3 files changed, 44 insertions(+), 56 deletions(-)
---
diff --git a/gio/gsocket.c b/gio/gsocket.c
index 54282c6..b635f9f 100644
--- a/gio/gsocket.c
+++ b/gio/gsocket.c
@@ -2489,6 +2489,14 @@ g_socket_create_source (GSocket      *socket,
  * against the currently-satisfied conditions on @socket. The result
  * is returned.
  *
+ * Note that on Windows, it is possible for an operation to return
+ * %G_IO_ERROR_WOULD_BLOCK even immediately after
+ * g_socket_condition_check() has claimed that the socket is ready for
+ * writing. Rather than calling g_socket_condition_check() and then
+ * writing to the socket if it succeeds, it is generally better to
+ * simply try writing to the socket right away, and try again later if
+ * the initial attempt returns %G_IO_ERROR_WOULD_BLOCK.
+ *
  * It is meaningless to specify %G_IO_ERR or %G_IO_HUP in condition;
  * these conditions will always be set in the output if they are true.
  *
diff --git a/gio/gsocketinputstream.c b/gio/gsocketinputstream.c
index 046970f..1c3dbbc 100644
--- a/gio/gsocketinputstream.c
+++ b/gio/gsocketinputstream.c
@@ -29,6 +29,7 @@
 
 #include <gio/gsimpleasyncresult.h>
 #include <gio/gcancellable.h>
+#include <gio/gioerror.h>
 
 #include "gioalias.h"
 
@@ -48,7 +49,6 @@ struct _GSocketInputStreamPrivate
   /* pending operation metadata */
   GSimpleAsyncResult *result;
   GCancellable *cancellable;
-  gboolean from_mainloop;
   gpointer buffer;
   gsize count;
 };
@@ -125,14 +125,18 @@ g_socket_input_stream_read_ready (GSocket *socket,
   GError *error = NULL;
   gssize result;
 
-  simple = stream->priv->result;
-  stream->priv->result = NULL;
-
   result = g_socket_receive (stream->priv->socket,
 			     stream->priv->buffer,
 			     stream->priv->count,
 			     stream->priv->cancellable,
 			     &error);
+
+  if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
+    return TRUE;
+
+  simple = stream->priv->result;
+  stream->priv->result = NULL;
+
   if (result >= 0)
     g_simple_async_result_set_op_res_gssize (simple, result);
 
@@ -145,11 +149,7 @@ g_socket_input_stream_read_ready (GSocket *socket,
   if (stream->priv->cancellable)
     g_object_unref (stream->priv->cancellable);
 
-  if (stream->priv->from_mainloop)
-    g_simple_async_result_complete (simple);
-  else
-    g_simple_async_result_complete_in_idle (simple);
-
+  g_simple_async_result_complete (simple);
   g_object_unref (simple);
 
   return FALSE;
@@ -165,6 +165,7 @@ g_socket_input_stream_read_async (GInputStream        *stream,
                                   gpointer             user_data)
 {
   GSocketInputStream *input_stream = G_SOCKET_INPUT_STREAM (stream);
+  GSource *source;
 
   g_assert (input_stream->priv->result == NULL);
 
@@ -177,25 +178,14 @@ g_socket_input_stream_read_async (GInputStream        *stream,
   input_stream->priv->buffer = buffer;
   input_stream->priv->count = count;
 
-  if (!g_socket_condition_check (input_stream->priv->socket, G_IO_IN))
-    {
-      GSource *source;
-
-      input_stream->priv->from_mainloop = TRUE;
-      source = g_socket_create_source (input_stream->priv->socket,
-                                       G_IO_IN | G_IO_HUP | G_IO_ERR,
-                                       cancellable);
-      g_source_set_callback (source,
-                             (GSourceFunc) g_socket_input_stream_read_ready,
-                             g_object_ref (input_stream), g_object_unref);
-      g_source_attach (source, g_main_context_get_thread_default ());
-      g_source_unref (source);
-    }
-  else
-    {
-      input_stream->priv->from_mainloop = FALSE;
-      g_socket_input_stream_read_ready (input_stream->priv->socket, G_IO_IN, input_stream);
-    }
+  source = g_socket_create_source (input_stream->priv->socket,
+				   G_IO_IN | G_IO_HUP | G_IO_ERR,
+				   cancellable);
+  g_source_set_callback (source,
+			 (GSourceFunc) g_socket_input_stream_read_ready,
+			 g_object_ref (input_stream), g_object_unref);
+  g_source_attach (source, g_main_context_get_thread_default ());
+  g_source_unref (source);
 }
 
 static gssize
diff --git a/gio/gsocketoutputstream.c b/gio/gsocketoutputstream.c
index 7aa9680..bf4ee78 100644
--- a/gio/gsocketoutputstream.c
+++ b/gio/gsocketoutputstream.c
@@ -30,6 +30,7 @@
 
 #include <gio/gsimpleasyncresult.h>
 #include <gio/gcancellable.h>
+#include <gio/gioerror.h>
 #include "glibintl.h"
 
 #include "gioalias.h"
@@ -50,7 +51,6 @@ struct _GSocketOutputStreamPrivate
   /* pending operation metadata */
   GSimpleAsyncResult *result;
   GCancellable *cancellable;
-  gboolean from_mainloop;
   gconstpointer buffer;
   gsize count;
 };
@@ -127,14 +127,18 @@ g_socket_output_stream_write_ready (GSocket *socket,
   GError *error = NULL;
   gssize result;
 
-  simple = stream->priv->result;
-  stream->priv->result = NULL;
-
   result = g_socket_send (stream->priv->socket,
 			  stream->priv->buffer,
 			  stream->priv->count,
 			  stream->priv->cancellable,
 			  &error);
+
+  if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
+    return TRUE;
+
+  simple = stream->priv->result;
+  stream->priv->result = NULL;
+
   if (result >= 0)
     g_simple_async_result_set_op_res_gssize (simple, result);
 
@@ -147,11 +151,7 @@ g_socket_output_stream_write_ready (GSocket *socket,
   if (stream->priv->cancellable)
     g_object_unref (stream->priv->cancellable);
 
-  if (stream->priv->from_mainloop)
-    g_simple_async_result_complete (simple);
-  else
-    g_simple_async_result_complete_in_idle (simple);
-
+  g_simple_async_result_complete (simple);
   g_object_unref (simple);
 
   return FALSE;
@@ -167,6 +167,7 @@ g_socket_output_stream_write_async (GOutputStream        *stream,
                                     gpointer              user_data)
 {
   GSocketOutputStream *output_stream = G_SOCKET_OUTPUT_STREAM (stream);
+  GSource *source;
 
   g_assert (output_stream->priv->result == NULL);
 
@@ -179,25 +180,14 @@ g_socket_output_stream_write_async (GOutputStream        *stream,
   output_stream->priv->buffer = buffer;
   output_stream->priv->count = count;
 
-  if (!g_socket_condition_check (output_stream->priv->socket, G_IO_OUT))
-    {
-      GSource *source;
-
-      output_stream->priv->from_mainloop = TRUE;
-      source = g_socket_create_source (output_stream->priv->socket,
-                                       G_IO_OUT | G_IO_HUP | G_IO_ERR,
-                                       cancellable);
-      g_source_set_callback (source,
-                             (GSourceFunc) g_socket_output_stream_write_ready,
-                             g_object_ref (output_stream), g_object_unref);
-      g_source_attach (source, g_main_context_get_thread_default ());
-      g_source_unref (source);
-    }
-  else
-    {
-      output_stream->priv->from_mainloop = FALSE;
-      g_socket_output_stream_write_ready (output_stream->priv->socket, G_IO_OUT, output_stream);
-    }
+  source = g_socket_create_source (output_stream->priv->socket,
+				   G_IO_OUT | G_IO_HUP | G_IO_ERR,
+				   cancellable);
+  g_source_set_callback (source,
+			 (GSourceFunc) g_socket_output_stream_write_ready,
+			 g_object_ref (output_stream), g_object_unref);
+  g_source_attach (source, g_main_context_get_thread_default ());
+  g_source_unref (source);
 }
 
 static gssize



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]