From ac0706aad0ed6799fdae264541ffdfa040c7f15a Mon Sep 17 00:00:00 2001 From: Silvio Lazzeretti Date: Thu, 13 Dec 2018 09:09:34 +0100 Subject: [PATCH 1/3] added stream writability checks in pollable unit test This checks if the stream is writable before writing to it. If the write succeeded with no error, then the stream has to be also writable after the write --- gio/tests/pollable.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gio/tests/pollable.c b/gio/tests/pollable.c index 826eaecad..75dca95ae 100644 --- a/gio/tests/pollable.c +++ b/gio/tests/pollable.c @@ -65,9 +65,13 @@ write_callback (gpointer user_data) gssize nwrote; GError *error = NULL; + g_assert_true (g_pollable_output_stream_is_writable (G_POLLABLE_OUTPUT_STREAM (out))); + nwrote = g_output_stream_write (out, buf, 2, NULL, &error); g_assert_no_error (error); g_assert_cmpint (nwrote, ==, 2); + g_assert_true (g_pollable_output_stream_is_writable (G_POLLABLE_OUTPUT_STREAM (out))); + /* Give the pipe a few ticks to propagate the write for sockets. On my * iMac i7, 40 works, 30 doesn't. */ g_usleep (80L); From 9e89749e524932c585f903f9bc6e9f13d840f430 Mon Sep 17 00:00:00 2001 From: Silvio Lazzeretti Date: Tue, 11 Dec 2018 14:15:24 +0100 Subject: [PATCH 2/3] Partially revert "GSocket: Fix race conditions on Win32 if multiple threads are waiting on conditions for the same socket" This partially reverts commit 799f8dcd46fb40ea206d9f1b5468db62cc00a72e. This patch seems to break the writability status of the server socket: once somebody writes to it with success, then it reports it is not writable anymore. Also, when the client socket has the flag FD_CONNECT set once, it is never cleared and then it reports it is always writable, also when it is not. --- gio/gsocket.c | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/gio/gsocket.c b/gio/gsocket.c index 859e807cb..8ceaa16d3 100644 --- a/gio/gsocket.c +++ b/gio/gsocket.c @@ -2711,8 +2711,6 @@ g_socket_accept (GSocket *socket, while (TRUE) { - win32_unset_event_mask (socket, FD_ACCEPT); - if ((ret = accept (socket->priv->fd, NULL, 0)) < 0) { int errsv = get_socket_errno (); @@ -2727,6 +2725,8 @@ g_socket_accept (GSocket *socket, errsv == EAGAIN) #endif { + win32_unset_event_mask (socket, FD_ACCEPT); + if (socket->priv->blocking) { if (!g_socket_condition_wait (socket, @@ -2743,6 +2743,8 @@ g_socket_accept (GSocket *socket, break; } + win32_unset_event_mask (socket, FD_ACCEPT); + #ifdef G_OS_WIN32 { /* The socket inherits the accepting sockets event mask and even object, @@ -2834,8 +2836,6 @@ g_socket_connect (GSocket *socket, while (1) { - win32_unset_event_mask (socket, FD_CONNECT); - if (connect (socket->priv->fd, &buffer.sa, g_socket_address_get_native_size (address)) < 0) { @@ -2850,6 +2850,8 @@ g_socket_connect (GSocket *socket, if (errsv == WSAEWOULDBLOCK) #endif { + win32_unset_event_mask (socket, FD_CONNECT); + if (socket->priv->blocking) { if (g_socket_condition_wait (socket, G_IO_OUT, cancellable, error)) @@ -2875,6 +2877,8 @@ g_socket_connect (GSocket *socket, break; } + win32_unset_event_mask (socket, FD_CONNECT); + socket->priv->connected_read = TRUE; socket->priv->connected_write = TRUE; @@ -3068,8 +3072,6 @@ g_socket_receive_with_timeout (GSocket *socket, while (1) { - win32_unset_event_mask (socket, FD_READ); - if ((ret = recv (socket->priv->fd, buffer, size, 0)) < 0) { int errsv = get_socket_errno (); @@ -3084,6 +3086,8 @@ g_socket_receive_with_timeout (GSocket *socket, errsv == EAGAIN) #endif { + win32_unset_event_mask (socket, FD_READ); + if (timeout != 0) { if (!block_on_timeout (socket, G_IO_IN, timeout, start_time, @@ -3094,10 +3098,14 @@ g_socket_receive_with_timeout (GSocket *socket, } } + win32_unset_event_mask (socket, FD_READ); + socket_set_error_lazy (error, errsv, _("Error receiving data: %s")); return -1; } + win32_unset_event_mask (socket, FD_READ); + break; } @@ -3263,8 +3271,6 @@ g_socket_send_with_timeout (GSocket *socket, while (1) { - win32_unset_event_mask (socket, FD_WRITE); - if ((ret = send (socket->priv->fd, (const char *)buffer, size, G_SOCKET_DEFAULT_SEND_FLAGS)) < 0) { int errsv = get_socket_errno (); @@ -3279,6 +3285,8 @@ g_socket_send_with_timeout (GSocket *socket, errsv == EAGAIN) #endif { + win32_unset_event_mask (socket, FD_WRITE); + if (timeout != 0) { if (!block_on_timeout (socket, G_IO_OUT, timeout, start_time, @@ -4755,8 +4763,6 @@ g_socket_send_message_with_timeout (GSocket *socket, while (1) { - win32_unset_event_mask (socket, FD_WRITE); - if (address) result = WSASendTo (socket->priv->fd, bufs, num_vectors, @@ -4778,6 +4784,8 @@ g_socket_send_message_with_timeout (GSocket *socket, if (errsv == WSAEWOULDBLOCK) { + win32_unset_event_mask (socket, FD_WRITE); + if (timeout != 0) { if (!block_on_timeout (socket, G_IO_OUT, timeout, @@ -5225,8 +5233,6 @@ g_socket_receive_message_with_timeout (GSocket *socket, /* do it */ while (1) { - win32_unset_event_mask (socket, FD_READ); - addrlen = sizeof addr; if (address) result = WSARecvFrom (socket->priv->fd, @@ -5248,6 +5254,8 @@ g_socket_receive_message_with_timeout (GSocket *socket, if (errsv == WSAEWOULDBLOCK) { + win32_unset_event_mask (socket, FD_READ); + if (timeout != 0) { if (!block_on_timeout (socket, G_IO_IN, timeout, @@ -5261,6 +5269,7 @@ g_socket_receive_message_with_timeout (GSocket *socket, socket_set_error_lazy (error, errsv, _("Error receiving message: %s")); return -1; } + win32_unset_event_mask (socket, FD_READ); break; } From e1e5fa0600bc1e38a04106127ccc6f501cdc3384 Mon Sep 17 00:00:00 2001 From: Silvio Lazzeretti Date: Fri, 14 Dec 2018 17:07:22 +0100 Subject: [PATCH 3/3] added more g_pollable_input_stream_is_readable checks --- gio/tests/pollable.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gio/tests/pollable.c b/gio/tests/pollable.c index 75dca95ae..b8c8710bb 100644 --- a/gio/tests/pollable.c +++ b/gio/tests/pollable.c @@ -38,10 +38,13 @@ poll_source_callback (GPollableInputStream *in, gssize nread; gboolean *success = user_data; + g_assert_true (g_pollable_input_stream_is_readable (G_POLLABLE_INPUT_STREAM (in))); + nread = g_pollable_input_stream_read_nonblocking (in, buf, 2, NULL, &error); g_assert_no_error (error); g_assert_cmpint (nread, ==, 2); g_assert_cmpstr (buf, ==, "x"); + g_assert_false (g_pollable_input_stream_is_readable (G_POLLABLE_INPUT_STREAM (in))); *success = TRUE; return G_SOURCE_REMOVE;