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