summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2019-01-13 22:43:52 +0100
committerCorinna Vinschen <corinna@vinschen.de>2019-01-13 22:43:52 +0100
commitb6694df6198102911980af22721a561c7627ea2a (patch)
tree8a5b8f441d096c755b39cbcec27839cc8d1edbbf
parentd31f9f9c1327447a04bdded5b8cd23821789f67d (diff)
downloadcygnal-b6694df6198102911980af22721a561c7627ea2a.tar.gz
cygnal-b6694df6198102911980af22721a561c7627ea2a.tar.bz2
cygnal-b6694df6198102911980af22721a561c7627ea2a.zip
Cygwin: select: fix overwriting fd sets if poll returns no fd
There's a long-standing bug in select. If we have poll-only descriptors in the fd set, select overwrites the incoming fd sets with the polling result. If none of the fds is ready, select has to loop again. But now the fd sets are set to all zero and select hangs. Fix this by utilizing the local fd sets r, w, e as storage for the incoming fd sets and use them to initialize select_stuff. If we have to loop, overwritung the incoming fd sets doesn't matter. While at it, rename r, w, e to readfds_in, writefds_in, exceptfds_in. Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
-rw-r--r--winsup/cygwin/release/2.12.02
-rw-r--r--winsup/cygwin/select.cc15
2 files changed, 11 insertions, 6 deletions
diff --git a/winsup/cygwin/release/2.12.0 b/winsup/cygwin/release/2.12.0
index 15f07e021..dbda7886e 100644
--- a/winsup/cygwin/release/2.12.0
+++ b/winsup/cygwin/release/2.12.0
@@ -65,3 +65,5 @@ Bug Fixes
even if file has been deleted.
Addresses: https://cygwin.com/ml/cygwin/2018-12/msg00125.html
https://cygwin.com/ml/cygwin/2018-12/msg00028.html
+
+- Fix a bug in select(2) when polling HANDLE-less descriptors.
diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc
index 0d82a5914..6ce679acf 100644
--- a/winsup/cygwin/select.cc
+++ b/winsup/cygwin/select.cc
@@ -164,17 +164,20 @@ select (int maxfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
select_stuff sel;
sel.return_on_signal = 0;
- /* Allocate some fd_set structures using the number of fds as a guide. */
- fd_set *r = allocfd_set (maxfds);
- fd_set *w = allocfd_set (maxfds);
- fd_set *e = allocfd_set (maxfds);
+ /* Allocate fd_set structures to store incoming fd sets. */
+ fd_set *readfds_in = allocfd_set (maxfds);
+ fd_set *writefds_in = allocfd_set (maxfds);
+ fd_set *exceptfds_in = allocfd_set (maxfds);
+ memcpy (readfds_in, readfds, sizeof_fd_set (maxfds));
+ memcpy (writefds_in, writefds, sizeof_fd_set (maxfds));
+ memcpy (exceptfds_in, exceptfds, sizeof_fd_set (maxfds));
do
{
/* Build the select record per fd linked list and set state as
needed. */
for (int i = 0; i < maxfds; i++)
- if (!sel.test_and_set (i, readfds, writefds, exceptfds))
+ if (!sel.test_and_set (i, readfds_in, writefds_in, exceptfds_in))
{
select_printf ("aborting due to test_and_set error");
return -1; /* Invalid fd, maybe? */
@@ -186,7 +189,7 @@ select (int maxfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
wait_state = select_stuff::select_ok;
else
/* wait for an fd to become active or time out */
- wait_state = sel.wait (r, w, e, us);
+ wait_state = sel.wait (readfds, writefds, exceptfds, us);
select_printf ("sel.wait returns %d", wait_state);