System.Process bugs on Unix
Simon Marlow
simonmarhaskell at gmail.com
Fri Mar 30 05:05:33 EDT 2007
Bryan O'Sullivan wrote:
> Simon Marlow wrote:
>
>> We can't just take a file descriptor out of non-blocking mode, because
>> due to broken POSIX semantics that would screw up GHC's use of the
>> file descriptor (there's no way to set non-blocking mode per-FD).
>
> Are you sure? I'd expect fcntl will do the trick. And you don't have
> to set non-blocking mode until after the fork, in the child, so GHC
> shouldn't see any consequences at all.
I'm sure, yes. The non-blocking flag is part of the "open file description"
(see [1], [2]), not the file descriptor. This is why you use F_SETFL rather
than F_SETFD to set it with fcntl(). When you dup() a file descriptor, the two
FDs share a non-blocking flag, just as they share a file pointer.
A TTY also has a single non-blocking flag, which all FDs (read & write) share.
So when GHC sets its stdin to non-blocking mode, and stdin is the current TTY,
anyone else writing to the TTY also gets non-blocking mode, hence the tee bug.
Just to make sure I wasn't deluded, I just managed to demonstrate this with a
couple of small test programs, which I'll attach - you need to compile them
both, then run "./nonblock1 | ./nonblock2", and hit enter. Notice that the C
program is seeing O_NONBLOCK set on its stdout/stderr descriptors, despite not
having set it.
Fortunately each end of a pipe has a separate non-blocking flag, which is why
runInteractiveProcess doesn't get into difficulties, although runProcess does
(see John's original message).
[1]
http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap03.html#tag_03_253
[2]
http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap03.html#tag_03_240
>> I've just milestoned this bug for 6.6.2, so I promise to at least try
>> to fix it before then...
>
> I've got a patch partially written, which shouldn't take more than an
> hour to finish off and test. So don't worry about this just yet.
neat - is it based on the patch attached to the bug, or did you do something
different?
Cheers,
Simon
-------------- next part --------------
import System.IO
main = do getLine; putStr "Hello World!\n"; hFlush stdout; getLine
-------------- next part --------------
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
main()
{
int r;
char buf[10];
read(0,buf,10);
printf("%c", buf[0]);
r = fcntl(0, F_GETFL);
printf ("%d\n", r & O_NONBLOCK);
r = fcntl(1, F_GETFL);
printf ("%d\n", r & O_NONBLOCK);
r = fcntl(2, F_GETFL);
printf ("%d\n", r & O_NONBLOCK);
}
More information about the Libraries
mailing list