Jason Gunthorpe <jgg@debian.org> writes:
> I've run into the following weird behavior on my system with 2.4.0. I have
> the following code:
Apt I guess ? It has a very strange behavior when backgrounded...
> if (fork() == 0)
> {
> int Flags,dummy;
> if ((Flags = fcntl(STDIN_FILENO,F_GETFL,dummy)) < 0)
> _exit(100);
> if (fcntl(STDIN_FILENO,F_SETFL,Flags | O_NONBLOCK) < 0)
> _exit(100);
> while (read(STDIN_FILENO,&dummy,1) == 1);
> if (fcntl(STDIN_FILENO,F_SETFL,Flags & (~(long)O_NONBLOCK)) < 0)
> _exit(100);
>
> // exec something
> }
>
> Which works fine, unless the parent process was backgrounded by the shell
> (^Z then bg). If that is the case then the O_NONBLOCK seems to be lost. I
> straced this:
>
> fcntl(0, F_GETFL) = 0x2 (flags O_RDWR)
> fcntl(0, F_SETFL, O_RDWR|O_NONBLOCK) = 0
> read(0, 0xbfffea38, 1) = ? ERESTARTSYS (To be restarted)
> --- SIGTTIN (Stopped (tty input)) ---
> --- SIGTTIN (Stopped (tty input)) ---
> read(0, 0xbfffea38, 1) = ? ERESTARTSYS (To be restarted)
> --- SIGTTIN (Stopped (tty input)) ---
> --- SIGTTIN (Stopped (tty input)) ---
> [.. etc, again and again in a tight loop ..]
> --- SIGTTIN (Stopped (tty input)) ---
> --- SIGTTIN (Stopped (tty input)) ---
> read(0,
>
> The last read was after the process was forgrounded. The read waits
> forever, the non-block flag seems to have gone missing. It is also a
> little odd I think that it repeated to get SIGTTIN which was never
> actually delivered to the program.. Shouldn't SIGTTIN suspend the process?
Strace can perturbate signal delivery, especially for terminal-related
signals, I wouldn't trust it...
O_NONBLOCK is not lost... Attempting to read from the controlling tty
even from a O_NONBLOCK descriptor will trigger SIGTTIN.
>From the code, it looks like you're trying to flush stdin before
exec'ing.
Why not use tcflush(STDIN_FILENO, TCIFLUSH) rather than using
O_NONBLOCK ?
This will not prevent SIGGTTIN from getting sent... You could catch it
or just ignore it...
But why would you want to flush stdin if you're in the background ?
Why not using:
if (fork()==0)
{
if (tcgetpgrp(STDIN_FILENO) == getpgrp())
{
/* We're the foreground process of the controlling tty */
tcflush(STDIN_FILENO, TCIFLUSH);
}
exec(...);
}
Here you just don't care flushing stdin if you're not the foreground
process (which is the *right* thing to do).
There's a race condition if the process is backgrounded between the
tcgetgrp() and the tcflush(), but you'll have to leave with it...
Phil.
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
This archive was generated by hypermail 2b29 : Sun Apr 15 2001 - 21:00:20 EST