From: Simon Marlow Date: Wed, 15 Sep 2010 14:26:18 +0000 (+0000) Subject: Windows: map ERROR_NO_DATA to EPIPE, rather than EINVAL X-Git-Url: http://git.megacz.com/?a=commitdiff_plain;h=1f35ed03ae66a8a3dcc689a7bdea02b935077d44;p=ghc-base.git Windows: map ERROR_NO_DATA to EPIPE, rather than EINVAL WriteFile() returns ERROR_NO_DATA when writing to a pipe that is "closing", however by default the write() wrapper in the CRT maps this to EINVAL so we get confusing things like hPutChar: invalid argument (Invalid Argumnet) when piping the output of a Haskell program into something that closes the pipe early. This was happening in the testsuite in a few place. The solution is to map ERROR_NO_DATA to EPIPE correctly, as we explicitly check for EPIPE on stdout (in GHC.TopHandler) so we can exit without an error in this case. --- diff --git a/GHC/IO/FD.hs b/GHC/IO/FD.hs index c67615d..2242ee6 100644 --- a/GHC/IO/FD.hs +++ b/GHC/IO/FD.hs @@ -582,7 +582,19 @@ blockingWriteRawBufferPtr loc fd buf off len = fmap fromIntegral $ throwErrnoIfMinus1Retry loc $ if fdIsSocket fd then c_safe_send (fdFD fd) (buf `plusPtr` off) len 0 - else c_safe_write (fdFD fd) (buf `plusPtr` off) len + else do + r <- c_safe_write (fdFD fd) (buf `plusPtr` off) len + when (r == -1) c_maperrno + return r + -- we don't trust write() to give us the correct errno, and + -- instead do the errno conversion from GetLastError() + -- ourselves. The main reason is that we treat ERROR_NO_DATA + -- (pipe is closing) as EPIPE, whereas write() returns EINVAL + -- for this case. We need to detect EPIPE correctly, because it + -- shouldn't be reported as an error when it happens on stdout. + +foreign import ccall unsafe "maperrno" -- in Win32Utils.c + c_maperrno :: IO () -- NOTE: "safe" versions of the read/write calls for use by the threaded RTS. -- These calls may block, but that's ok. diff --git a/cbits/Win32Utils.c b/cbits/Win32Utils.c index 0f4eb52..fd4d1eb 100644 --- a/cbits/Win32Utils.c +++ b/cbits/Win32Utils.c @@ -61,7 +61,10 @@ static struct errentry errtable[] = { { ERROR_ALREADY_EXISTS, EEXIST }, /* 183 */ { ERROR_FILENAME_EXCED_RANGE, ENOENT }, /* 206 */ { ERROR_NESTING_NOT_ALLOWED, EAGAIN }, /* 215 */ - { ERROR_NOT_ENOUGH_QUOTA, ENOMEM } /* 1816 */ + /* Windows returns this when the read end of a pipe is + * closed (or closing) and we write to it. */ + { ERROR_NO_DATA, EPIPE }, /* 232 */ + { ERROR_NOT_ENOUGH_QUOTA, ENOMEM } /* 1816 */ }; /* size of the table */