Is it an error to call hGetLine on a non-blocking Handle?

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Hi folks: I could really use an expert eye on this. I'm trying to get to the bottom of a very tenacious bug in the GHC Builder. The details of how this happens are documented separately for reference: https://gist.github.com/AlainODea/dc841046524cd7833da8 The Handles involved are returned by System.Process.runInteractiveProcess. They are non-blocking at the Illumos kernel level. It appears that maybeFillReadBuffer (called by hGetLine under the hood) treats EAGAIN as an error: http://hackage.haskell.org/package/base-4.7.0.0/docs/src/GHC-IO-Handle-Text.... Is it expected that runInteractiveProcess would return non-blocking Handles for stdout and stderr? Is it an error to call hGetLine on a non-blocking Handle? Thanks, Alain -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/ iQEcBAEBAgAGBQJTaG1jAAoJEP0rIXJNjNSAxpwH/immeV301FEZx9o6Q0ODCuqK AUBnDHcjS9VBqhJ7XnuwkWXi83qNJhoi9P4RjamL3EGnScHVfa1mnpkX5T1IWCb4 S4lWxICbVH4tmFYOwHmElzi8vzBvgmsCueiU5uMJc66dteR4U2e9FHb9Vaurg222 dDwfIYu7mIEb/Fld4dqN+qFp9ZbVPxjBASVPlIDpZFY95+0hMq/s331B5T6zi/ZZ o63pYR2xkIScIlocEYaYJT67OssYxHScu6F/dOu4F4dllV013cP0x6/6ov4KCpBi fqM5WRid1UyTtCco2dXg7eRkzQxEMoVL0TpEQbDn/iWKJS99+rG3YSt5JYDbhTY= =xtDH -----END PGP SIGNATURE-----

On Mon, May 5, 2014 at 10:04 PM, Alain O'Dea
I'm trying to get to the bottom of a very tenacious bug in the GHC Builder.
The details of how this happens are documented separately for reference: https://gist.github.com/AlainODea/dc841046524cd7833da8
The Handles involved are returned by System.Process.runInteractiveProcess. They are non-blocking at the Illumos kernel level.
It appears that maybeFillReadBuffer (called by hGetLine under the hood) treats EAGAIN as an error:
http://hackage.haskell.org/package/base-4.7.0.0/docs/src/GHC-IO-Handle-Text....
Is it expected that runInteractiveProcess would return non-blocking Handles for stdout and stderr?
The non-blockingness should be hidden. Your attempt to follow EAGAIN down the programmatic rabbit hole hasn't gotten you nearly far enough, I'm afraid. You stopped at a layer where the underlying non-blocking nature of the IO shouldn't be visible, so it would be inappropriate to check for EAGAIN there. As you'll notice if you follow the breadcrumbs further, it becomes quite difficult to spelunk through the various vtables to see what's really going on. I *think* that you should be looking at GHC.IO.FD.readRawBufferPtr, as that's where the IO is ultimately happening. The trouble is, it calls throwErrnoIfMinus1RetryMayBlock, which should already be doing the right thing with EAGAIN. Sadly, I don't know what's going wrong here, but I'm sure you will need to go down a level or two of abstraction from where you are now before you'll find the source of the problem.

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On Tue 06 May 2014 04:39:19 PM UTC, Bryan O'Sullivan wrote:
On Mon, May 5, 2014 at 10:04 PM, Alain O'Dea
mailto:alain.odea@gmail.com> wrote: I'm trying to get to the bottom of a very tenacious bug in the GHC Builder.
The details of how this happens are documented separately for reference: https://gist.github.com/AlainODea/dc841046524cd7833da8
The Handles involved are returned by System.Process.runInteractiveProcess. They are non-blocking at the Illumos kernel level.
It appears that maybeFillReadBuffer (called by hGetLine under the hood) treats EAGAIN as an error:
http://hackage.haskell.org/package/base-4.7.0.0/docs/src/GHC-IO-Handle-Text....
Is it expected that runInteractiveProcess would return non-blocking Handles for stdout and stderr?
The non-blockingness should be hidden.
Your attempt to follow EAGAIN down the programmatic rabbit hole hasn't gotten you nearly far enough, I'm afraid. You stopped at a layer where the underlying non-blocking nature of the IO shouldn't be visible, so it would be inappropriate to check for EAGAIN there. As you'll notice if you follow the breadcrumbs further, it becomes quite difficult to spelunk through the various vtables to see what's really going on.
I /think/ that you should be looking at GHC.IO.FD.readRawBufferPtr, as that's where the IO is ultimately happening. The trouble is, it calls throwErrnoIfMinus1RetryMayBlock, which should already be doing the right thing with EAGAIN. Sadly, I don't know what's going wrong here, but I'm sure you will need to go down a level or two of abstraction from where you are now before you'll find the source of the problem.
Thank you Bryan. I'm probably too low-level with my current DTrace of syscalls and definitely too high-level in the GHC sources as you have identified. I'll find my way to the middle here. I'll take a look at GHC.IO.FD.readRawBufferPtr and throwErrorIfMinus1RetryMayBlock. It appears to be working normally for most of the operations, but hits a gap somewhere that allows the ResourceExhausted IOError to leak out. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/ iQEcBAEBAgAGBQJTaR1TAAoJEP0rIXJNjNSA2UsH/3DrAO9e1TTqwqNUIaBI49Oi /Aigcq+4DGGC5KjhNHwuISDkjdCsOzoXVrgdS5ujl5ZQkJW9S6Lm6L9TMU5b0vxW u21r5n2FmZCG6ENDUUxbb9V8/pN6rYgtNB0mXojXnhccDVqwboo5d6ivjjx3jdoC IkvmnPe0YOtHGHx44RX0U1Q33moa2kDE1+nCalnu80k8zmIK9QvdTD8DDx2aGnIg A4sZXty5pjO9jVYu02IoCvCIYwLtPoSye681TnMDoplY+UHtrV1eIeDl0fs6HgaV lfRzEnfnRObvkLOb7sCjLCZ5l8M8mgXZaefAumTLuuRwSYSj2gsAzWvSe88PyTE= =dqzc -----END PGP SIGNATURE-----

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On Tue 06 May 2014 05:35:15 PM UTC, Alain O'Dea wrote:
On Tue 06 May 2014 04:39:19 PM UTC, Bryan O'Sullivan wrote:
On Mon, May 5, 2014 at 10:04 PM, Alain O'Dea
mailto:alain.odea@gmail.com> wrote: I'm trying to get to the bottom of a very tenacious bug in the GHC Builder.
The details of how this happens are documented separately for reference: https://gist.github.com/AlainODea/dc841046524cd7833da8
The Handles involved are returned by System.Process.runInteractiveProcess. They are non-blocking at the Illumos kernel level.
It appears that maybeFillReadBuffer (called by hGetLine under the hood) treats EAGAIN as an error:
http://hackage.haskell.org/package/base-4.7.0.0/docs/src/GHC-IO-Handle-Text....
Is it expected that runInteractiveProcess would return non-blocking Handles for stdout and stderr?
The non-blockingness should be hidden.
Your attempt to follow EAGAIN down the programmatic rabbit hole hasn't gotten you nearly far enough, I'm afraid. You stopped at a layer where the underlying non-blocking nature of the IO shouldn't be visible, so it would be inappropriate to check for EAGAIN there. As you'll notice if you follow the breadcrumbs further, it becomes quite difficult to spelunk through the various vtables to see what's really going on.
I /think/ that you should be looking at GHC.IO.FD.readRawBufferPtr, as that's where the IO is ultimately happening. The trouble is, it calls throwErrnoIfMinus1RetryMayBlock, which should already be doing the right thing with EAGAIN. Sadly, I don't know what's going wrong here, but I'm sure you will need to go down a level or two of abstraction from where you are now before you'll find the source of the problem.
Thank you Bryan. I'm probably too low-level with my current DTrace of syscalls and definitely too high-level in the GHC sources as you have identified. I'll find my way to the middle here.
I'll take a look at GHC.IO.FD.readRawBufferPtr and throwErrorIfMinus1RetryMayBlock. It appears to be working normally for most of the operations, but hits a gap somewhere that allows the ResourceExhausted IOError to leak out.
I looked through he readRawBufferPtr and friends and could not see any obvious gaps for EAGAIN to slip through. I didn't look as hard as I'd like, but I was getting a bit lost after a few hours of constructing possible code paths. On a whim I tried setting LC_ALL to en_US.UTF-8 and the problem disappeared. Does hGetLine have undefined behavior if locale environment variables (LANG, LC_*) are unset? -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/ iQEcBAEBAgAGBQJTelh6AAoJEP0rIXJNjNSAxAwH/1iKbSyDK8RChSTSrVUFE7UU KLU9e1g7bU31CGcvwdMG4MfEKT1LgGf9YNoOJCLdimT3RxdnExx/zTuQlfaa/PSo Bb8bcagJvau62RjGgDebIOxarUUzZ+vhNditopsmV5lNnvn600ryORmyBQOI6+Pw SCU83BYMNGdjzSm4/C0KIz5lfaX+OA4UiE1JuIS4/I83/mmnniY59dAiQ8SNzkRD XbrOtdbsrbdoYG48OWy1auQTim+zzzpXVvuzn4vxx/oQ7A1k8kkrfl+UJJNClkAo MLXUZY6CC8pl5nACWlnPsM+WswEpRBDEr9BQ1ZX5psNB+4j4NL76xR28+glek5Y= =0Kkg -----END PGP SIGNATURE-----

On Mon, May 19, 2014 at 3:16 PM, Alain O'Dea
On a whim I tried setting LC_ALL to en_US.UTF-8 and the problem disappeared. Does hGetLine have undefined behavior if locale environment variables (LANG, LC_*) are unset?
This makes me wonder if it's actually throwing an encoding error which somehow gets overwritten or mis-recorded (similar to the C newcomer's mistake in trusting errno when an error was not indicated). -- brandon s allbery kf8nh sine nomine associates allbery.b@gmail.com ballbery@sinenomine.net unix, openafs, kerberos, infrastructure, xmonad http://sinenomine.net
participants (3)
-
Alain O'Dea
-
Brandon Allbery
-
Bryan O'Sullivan