From c2a1fa7aec426727be6df79f3db109183e42cfdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20Hamb=C3=BCchen?= Date: Tue, 19 Sep 2017 15:10:00 -0400 Subject: base: Fix fdReady() potentially running forever on Windows. This fixes #13497 for Windows -- at least for the `if (isSock)` part; I haven't investigated the case where it's not a socket yet. Solved by copying the new current-time based waiting logic from the non-Windows implementation above. Reviewers: bgamari, austin, hvr Reviewed By: bgamari Subscribers: rwbarton, thomie Differential Revision: https://phabricator.haskell.org/D3954 --- libraries/base/cbits/inputReady.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) (limited to 'libraries/base/cbits') diff --git a/libraries/base/cbits/inputReady.c b/libraries/base/cbits/inputReady.c index dbfdb28b70..14f1c546c2 100644 --- a/libraries/base/cbits/inputReady.c +++ b/libraries/base/cbits/inputReady.c @@ -21,10 +21,6 @@ int fdReady(int fd, int write, int msecs, int isSock) { - -#if !defined(_WIN32) - struct pollfd fds[1]; - // if we need to track the time then record the end time in case we are // interrupted. Time endTime = 0; @@ -32,6 +28,9 @@ fdReady(int fd, int write, int msecs, int isSock) endTime = getProcessElapsedTime() + MSToTime(msecs); } +#if !defined(_WIN32) + struct pollfd fds[1]; + fds[0].fd = fd; fds[0].events = write ? POLLOUT : POLLIN; fds[0].revents = 0; @@ -59,7 +58,8 @@ fdReady(int fd, int write, int msecs, int isSock) if (isSock) { int maxfd, ready; fd_set rfd, wfd; - struct timeval tv; + struct timeval remaining_tv; + if ((fd >= (int)FD_SETSIZE) || (fd < 0)) { fprintf(stderr, "fdReady: fd is too big"); abort(); @@ -76,12 +76,22 @@ fdReady(int fd, int write, int msecs, int isSock) * (maxfd-1) */ maxfd = fd + 1; - tv.tv_sec = msecs / 1000; - tv.tv_usec = (msecs % 1000) * 1000; - while ((ready = select(maxfd, &rfd, &wfd, NULL, &tv)) < 0 ) { - if (errno != EINTR ) { - return -1; + Time remaining = MSToTime(msecs); + remaining_tv.tv_sec = TimeToMS(remaining) / 1000; + remaining_tv.tv_usec = TimeToUS(remaining) % 1000000; + + while ((ready = select(maxfd, &rfd, &wfd, NULL, &remaining_tv)) < 0 ) { + if (errno == EINTR) { + if (msecs > 0) { + Time now = getProcessElapsedTime(); + if (now >= endTime) return 0; + remaining = endTime - now; + remaining_tv.tv_sec = TimeToMS(remaining) / 1000; + remaining_tv.tv_usec = TimeToUS(remaining) % 1000000; + } + } else { + return (-1); } } -- cgit v1.2.1