<LJ-CUT text=" --More--(33%) ">
/* gcc test.c -lutil */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <util.h>
static int
do_fork(void)
{
int fd = -1;
pid_t pid;
if ((pid = forkpty(&fd, NULL, NULL, NULL)) < 0)
perror("forkpty");
else if (!pid)
{
printf ("0123456789\n");
/* #### Uncommenting this makes it work! */
/* sleep(20); */
exit (0);
}
return fd;
}
int
main (int argc, char **argv)
{
char s[1024];
int n;
int fd = do_fork();
/* On 10.4, this prints the whole 10 character line, 1 char per second.
On 10.5, it prints 1 character and stops.
*/
do {
n = read (fd, s, 1);
if (n > 0) fprintf (stderr, "%c", *s);
sleep (1);
} while (n > 0);
return 0;
}
Update, 2 Sep 2009: Still broken in exactly the same way in 10.6.
(And also 10.7.)
It's a pty, really.
I wonder if it's one of those cases like on old modem-based BBS' where the hang-up signal of the remote modem could be delivered before some of the type-ahe^D
Doubtless you've done this test already, but it does what you want it to under Linux. Well, under Ubuntu Gutsy anyway.
For some reason, it works just fine on 10.5 when running under dtruss. I don't even claim to understand this.
FWIW, here's an even more minimal test case that doesn't depend on forking:
Wow, that test does something horrible under 10.4.11 as well. With your code, the read() blocks. But if I comment out the close(), then it hangs after printing "read returned 1", and by "hangs" I mean "kill -9 doesn't work". WTF.
Yikes. Apparently the problem runs deeper than expected.
This works fine for my 10.5.1 install (changing last argument to read to 4 returns whole string).
Shades of an old old SunOS 4 bug. When the writing end of a pty would close the reader only had a limitted length of time to read the buffer before the kernel would flush it. Annoying. Dunno if Sun ever did fix it. Haven't tested under Solaris 2 'cos I didn't need to do the same sort of work there.
SIGCHILD being interpreted as SIGINT perhaps? SIGDEF'ing SIGCHILD might prove interesting. Python Popen* does this to me sometimes and it really winds me up.
That would kill the parent, which isn't happening. The pty is getting flushed.
Perhaps you have exceeded your errant punctuation quota.

Feel free to pay me in Basil Hayden my next visit to the bay.
BTW I was joking. I see the bug and am sufficiently bored at work to poke at it. Sec...
Try this:
It also works fine if you don't per-byte reads. I'm still not convinced they haven't sinned on this one...
(keeping the same do_fork()):
int main (int argc, char **argv) {
char s[1024];
int fd = do_fork();
if(read(fd, s , 1024) != -1) {
fprintf(stderr,"child wrote to fd #%d:\n%s",fd, s);
} else {
perror("read from child borked");
}
close(fd);
return 0;
}
Are you sure this happens on pipes? Your code uses PTYs.
Are you sure that data on PTYs is supposed to hang around indefinitely, according to POSIX, or is that an implementation detail on the other systems?
10.4 has some broken behavior in this area as well. I had hoped 10.5 would fix it, not break it more.
Here's a unit test which *intermittently* reproduces the problem:
http://twistedmatrix.com/trac/browser/trunk/twisted/test/test_stdio.py?rev=21558#L125
I never managed to produce the behavior with a simple C program. I'm glad you figured it out and reported a bug.