base: Fix fdReady() returning immediately for pipes on Windows.
ClosedPublic

Authored by nh2 on Sep 14 2017, 8:50 AM.

Details

Summary

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.

Diff Detail

Repository
rGHC Glasgow Haskell Compiler
Lint
Automatic diff as part of commit; lint not applicable.
Unit
Automatic diff as part of commit; unit tests not applicable.
nh2 created this revision.Sep 14 2017, 8:50 AM
bgamari edited edge metadata.Sep 14 2017, 9:15 AM
bgamari added a subscriber: Phyx.

I wonder if we couldn't rather just switch to IOCPs here. @Phyx has some work on a new IO manager for Windows, so this is in the pipeline, but I suspect we could make the change locally here without much trouble.

bgamari accepted this revision.Sep 14 2017, 9:26 AM

Oh, never mind; I suppose switching to IOCPs would involve carrying HANDLEs all the way down from Haskell to here, which sounds like a considerable amount of platform-specific plumbing. Perhaps this is fine until we have a better IO manager in place.

This revision is now accepted and ready to land.Sep 14 2017, 9:26 AM

Actually, I now see that you can be a HANDLE from an fd, with _get_osfhandle, which we do elsewhere in this very file. Moving to IOCP sounds quite tempting but we can leave this for later.

Phyx added a comment.Sep 14 2017, 10:09 AM

Actually, I now see that you can be a HANDLE from an fd, with _get_osfhandle, which we do elsewhere in this very file. Moving to IOCP sounds quite tempting but we can leave this for later.

The code I have so far side-steps fds entirely (outdated code here https://github.com/Mistuke/ghc-win-io-system/blob/master/cbits/IOUtils.c#L36).
While you can convert fds to HANDLE they have a few nasty limitations, like fds being process local and not inheritable. Which is a problem for say, sharing anonymous pipes. Which is why
ghc-iserv uses (or at least did when I implemented it) Handle instead of fd. The rules around them on Win32 is very undocumented, so I try to avoid them now.

The changes to that weren't that big, Mostly because I have new IODevices that only accept HANDLE. The bigger problem (and one I've been stuck with) is that I want to avoid base from using on Windows UTF-32 but instead UTF-16.
To avoid unnecessarily converting every string back and forth as it does now, this means having to change Handle__ which is not that bad, but if I can't get the typechecker to agree with me on the new Rank2Types then I may have to change Handle itself,
which would be a problem for any project not having treated Handle as an opaque type.

This revision was automatically updated to reflect the committed changes.