Bug 324234 - Using g_io_add_watch_full() to wait for connect() to return
authorTor Lillqvist <tml@novell.com>
Tue, 19 Aug 2008 23:48:16 +0000 (23:48 +0000)
committerTor Lillqvist <tml@src.gnome.org>
Tue, 19 Aug 2008 23:48:16 +0000 (23:48 +0000)
2008-08-20  Tor Lillqvist  <tml@novell.com>

Bug 324234 - Using g_io_add_watch_full() to wait for connect() to
return on a non-blocking socket returns prematurely

Bug 548278 - Async GETs connections are always terminated
unexpectedly on Windows

* glib/giowin32.c: Add one more state variable to the
GIOWin32Channel struct, ever_writable. Initialise it to FALSE, set
to TRUE when the WSAEventSelect() indicates FD_WRITE, and never
reset to FALSE.

Don't do the WSASetEvent() in g_io_win32_prepare() unless
ever_writable is TRUE. Don't automatically indicate G_IO_OUT in
g_io_win32_check() unless ever_writable is TRUE.

This fixes the behaviour of the test case program in bug #548278,
and the "Testcase for the spurious OUT event bug" in bug
#324234. It also doesn't seem to break anything. Not that there is
any exhaustive test suite...

Add a comment with a list of bugs that are related to the code in
this file.

svn path=/trunk/; revision=7372

ChangeLog
glib/giowin32.c

index 31adb38ce9926d8d6b5317d3bb9857eb7e515718..2b46e5460671ec6879f1856efeb23bfd92e4368e 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,28 @@
+2008-08-20  Tor Lillqvist  <tml@novell.com>
+
+       Bug 324234 - Using g_io_add_watch_full() to wait for connect() to
+       return on a non-blocking socket returns prematurely
+
+       Bug 548278 - Async GETs connections are always terminated
+       unexpectedly on Windows
+
+       * glib/giowin32.c: Add one more state variable to the
+       GIOWin32Channel struct, ever_writable. Initialise it to FALSE, set
+       to TRUE when the WSAEventSelect() indicates FD_WRITE, and never
+       reset to FALSE.
+
+       Don't do the WSASetEvent() in g_io_win32_prepare() unless
+       ever_writable is TRUE. Don't automatically indicate G_IO_OUT in
+       g_io_win32_check() unless ever_writable is TRUE.
+
+       This fixes the behaviour of the test case program in bug #548278,
+       and the "Testcase for the spurious OUT event bug" in bug
+       #324234. It also doesn't seem to break anything. Not that there is
+       any exhaustive test suite...
+
+       Add a comment with a list of bugs that are related to the code in
+       this file.
+
 2008-08-18  Matthias Clasen  <mclasen@redhat.com>
 
        * configure.in: Bump version
index 7f00572dae9ecf8341f887f277c1f55759555e3e..4793ad5d7f8a158e4742610b6718842baf0374fe 100644 (file)
  * GLib at ftp://ftp.gtk.org/pub/gtk/.
  */
 
+/*
+ * Bugs that are related to the code in this file:
+ *
+ * Bug 137968 - Sometimes a GIOFunc on Win32 is called with zero condition
+ * http://bugzilla.gnome.org/show_bug.cgi?id=137968
+ *
+ * Bug 324234 - Using g_io_add_watch_full() to wait for connect() to return on a non-blocking socket returns prematurely
+ * http://bugzilla.gnome.org/show_bug.cgi?id=324234
+ *
+ * Bug 331214 - g_io_channel async socket io stalls
+ * http://bugzilla.gnome.org/show_bug.cgi?id=331214
+ *
+ * Bug 338943 - Multiple watches on the same socket
+ * http://bugzilla.gnome.org/show_bug.cgi?id=338943
+ *
+ * Bug 357674 - 2 serious bugs in giowin32.c making glib iochannels useless
+ * http://bugzilla.gnome.org/show_bug.cgi?id=357674
+ *
+ * Bug 425156 - GIOChannel deadlocks on a win32 socket
+ * http://bugzilla.gnome.org/show_bug.cgi?id=425156
+ *
+ * Bug 468910 - giofunc condition=0
+ * http://bugzilla.gnome.org/show_bug.cgi?id=468910
+ *
+ * Bug 500246 - Bug fixes for giowin32
+ * http://bugzilla.gnome.org/show_bug.cgi?id=500246
+ *
+ * Bug 548278 - Async GETs connections are always terminated unexpectedly on windows
+ * http://bugzilla.gnome.org/show_bug.cgi?id=548278
+ *
+ * Bug 548536 - giowin32 problem when adding and removing watches
+ * http://bugzilla.gnome.org/show_bug.cgi?id=548536
+ *
+ * When fixing bugs related to the code in this file, either the above
+ * bugs or others, make sure that the test programs attached to the
+ * above bugs continue to work.
+ */
+
 #include "config.h"
 
 #include "glib.h"
@@ -116,6 +154,7 @@ struct _GIOWin32Channel {
   int last_events;
   HANDLE event;
   gboolean write_would_have_blocked;
+  gboolean ever_writable;
 };
 
 #define LOCK(mutex) EnterCriticalSection (&mutex)
@@ -242,6 +281,7 @@ g_io_channel_win32_init (GIOWin32Channel *channel)
   channel->last_events = 0;
   channel->event = NULL;
   channel->write_would_have_blocked = FALSE;
+  channel->ever_writable = FALSE;
   InitializeCriticalSection (&channel->mutex);
 }
 
@@ -734,7 +774,9 @@ g_io_win32_prepare (GSource *source,
            g_print ("\n  setting last_events=0");
          channel->last_events = 0;
 
-         if ((event_mask & FD_WRITE) && !channel->write_would_have_blocked)
+         if ((event_mask & FD_WRITE) &&
+             channel->ever_writable &&
+             !channel->write_would_have_blocked)
            {
              if (channel->debug)
                g_print (" WSASetEvent(%p)", (WSAEVENT) watch->pollfd.fd);
@@ -845,11 +887,15 @@ g_io_win32_check (GSource *source)
                         (HANDLE) watch->pollfd.fd);
              ResetEvent ((HANDLE) watch->pollfd.fd);
            }
+         else if (events.lNetworkEvents & FD_WRITE)
+           channel->ever_writable = TRUE;
          channel->last_events = events.lNetworkEvents;
        }
+
       watch->pollfd.revents = 0;
       if (channel->last_events & (FD_READ | FD_ACCEPT))
        watch->pollfd.revents |= G_IO_IN;
+
       if (channel->last_events & FD_WRITE)
        watch->pollfd.revents |= G_IO_OUT;
       else
@@ -869,10 +915,12 @@ g_io_win32_check (GSource *source)
        }
 
       /* Regardless of WSAEnumNetworkEvents() result, if watching for
-       * writability, unless last write would have blocked set
-       * G_IO_OUT. But never set both G_IO_OUT and G_IO_HUP.
+       * writability, and if we have ever got a FD_WRITE event, and
+       * unless last write would have blocked, set G_IO_OUT. But never
+       * set both G_IO_OUT and G_IO_HUP.
        */
       if (!(watch->pollfd.revents & G_IO_HUP) &&
+         channel->ever_writable &&
          !channel->write_would_have_blocked &&
          (channel->event_mask & FD_WRITE))
        watch->pollfd.revents |= G_IO_OUT;