[commit: ghc] master: base: Fix fdReady() returning immediately for pipes on Windows. (66240c9)
git at git.haskell.org
git at git.haskell.org
Tue Sep 19 21:55:37 UTC 2017
Repository : ssh://git@git.haskell.org/ghc
On branch : master
Link : http://ghc.haskell.org/trac/ghc/changeset/66240c9bc77408f841e8cf974d44580434fb1a48/ghc
>---------------------------------------------------------------
commit 66240c9bc77408f841e8cf974d44580434fb1a48
Author: Niklas Hambüchen <mail at nh2.me>
Date: Tue Sep 19 15:11:05 2017 -0400
base: Fix fdReady() returning immediately for pipes on Windows.
See https://ghc.haskell.org/trac/ghc/ticket/13497#comment:17
Until now, the program
import System.IO
main = hWaitForInput stdin (5 * 1000)
didn't wait 5 seconds for input on Winodws, it terminated immediately.
This was because the `PeekNamedPipe()` function introduced in commit
94fee9e7 really only peeks, it doesn't block. So if there's no data,
`fdReady(fd, msec)` would return immediately even when the given `msec`
timeout is not zero.
This commit fixes it by looping around `PeekNamedPipe()` with a `sleep(1
ms)`.
Apparently there's no better way to do this on Windows without switching
to IOCP.
In any case, this change should be strictly better than what was there
before.
Reviewers: bgamari, austin, hvr
Reviewed By: bgamari
Subscribers: Phyx, rwbarton, thomie
Differential Revision: https://phabricator.haskell.org/D3956
>---------------------------------------------------------------
66240c9bc77408f841e8cf974d44580434fb1a48
libraries/base/cbits/inputReady.c | 46 +++++++++++++++++++++++++--------------
1 file changed, 30 insertions(+), 16 deletions(-)
diff --git a/libraries/base/cbits/inputReady.c b/libraries/base/cbits/inputReady.c
index ab2a1c2..ddeee66 100644
--- a/libraries/base/cbits/inputReady.c
+++ b/libraries/base/cbits/inputReady.c
@@ -17,6 +17,9 @@
* descriptor 'fd' within 'msecs' milliseconds (or indefinitely if 'msecs' is
* negative). "Input is available" is defined as 'can I safely read at least a
* *character* from this file object without blocking?'
+ *
+ * This function blocks until either `msecs` have passed, or input is
+ * available.
*/
int
fdReady(int fd, int write, int msecs, int isSock)
@@ -100,7 +103,7 @@ fdReady(int fd, int write, int msecs, int isSock)
} else {
DWORD rc;
HANDLE hFile = (HANDLE)_get_osfhandle(fd);
- DWORD avail;
+ DWORD avail = 0;
Time remaining = MSToTime(msecs);
@@ -187,23 +190,34 @@ fdReady(int fd, int write, int msecs, int isSock)
// WaitForMultipleObjects() doesn't work for pipes (it
// always returns WAIT_OBJECT_0 even when no data is
// available). If the HANDLE is a pipe, therefore, we try
- // PeekNamedPipe:
+ // PeekNamedPipe():
//
- rc = PeekNamedPipe( hFile, NULL, 0, NULL, &avail, NULL );
- if (rc != 0) {
- if (avail != 0) {
- return 1;
+ // PeekNamedPipe() does not block, so if it returns that
+ // there is no new data, we have to sleep and try again.
+ while (avail == 0) {
+ rc = PeekNamedPipe( hFile, NULL, 0, NULL, &avail, NULL );
+ if (rc != 0) {
+ if (avail != 0) {
+ return 1;
+ } else { // no new data
+ if (msecs > 0) {
+ Time now = getProcessElapsedTime();
+ if (now >= endTime) return 0;
+ Sleep(1); // 1 millisecond (smallest possible time on Windows)
+ continue;
+ } else {
+ return 0;
+ }
+ }
} else {
- return 0;
- }
- } else {
- rc = GetLastError();
- if (rc == ERROR_BROKEN_PIPE) {
- return 1; // this is probably what we want
- }
- if (rc != ERROR_INVALID_HANDLE && rc != ERROR_INVALID_FUNCTION) {
- maperrno();
- return -1;
+ rc = GetLastError();
+ if (rc == ERROR_BROKEN_PIPE) {
+ return 1; // this is probably what we want
+ }
+ if (rc != ERROR_INVALID_HANDLE && rc != ERROR_INVALID_FUNCTION) {
+ maperrno();
+ return -1;
+ }
}
}
/* PeekNamedPipe didn't work - fall through to the general case */
More information about the ghc-commits
mailing list