Change sigTTOU/TTIN to IGNORE by default
Michael Weber
michael.weber at post.rwth-aachen.de
Mon Jan 15 18:00:05 EST 2001
* Simon Marlow <simonmar at microsoft.com> [2001-01-15T04:52-0800]:
> Volker previously wrote:
> [SIGTTOU when background process writes to terminal]
> This is truly bizarre. I've tracked it down to a tcgetattr/tcsetattr
> pair in setBuffering.
[...]
> What's weird is that the tcsetattr doesn't affect the TOSTOP flag at all
> (which is the flag that tells the OS whether the process should be
> stopped on background TTY output), and the TOSTOP flag starts off unset.
Nope, TOSTOP tells the OS, whether a SIGTTOU should be sent on
background TTY output, and SIGTTOU makes the process stop.
[C program to produce the problem]
> running "./a.out &" suspends the process. If you comment out the
> tcsetattr line, then it doesn't get suspended. But we're not changing
> any of the terminal flags, simply setting the same ones again.
>
> I'm totally stumped! I can't see any reason why this should happen. It
> happens on both Linux & Solaris.
>
> Any ideas, anyone?
* Malcolm previously wrote:
> So it seems that there is possibly a feature/bug in the C library
> such that calling tcsetattr() always suspends a backgrounded process,
> regardless of the setting of TOSTOP. As yet, I haven't been able to
> find a workaround. :-(
You're right. ``tcsetattr'' doesn't affect the ``TOSTOP'' flag, but it
sends a SIGTTOU, when invoked from a background process. This, in
turn, causes the process to suspend unless SIGTTOU is blocked or
ignored!
SUSv2 says, this is the correct behaviour:
http://www.opennc.org/onlinepubs/007908799/xsh/tcsetattr.html:
[...]
Attempts to use tcsetattr() from a process which is a member
of a background process group on a fildes associated with its
controlling terminal, will cause the process group to be sent
a SIGTTOU signal. If the calling process is blocking or
ignoring SIGTTOU signals, the process is allowed to perform
the operation, and no signal is sent.
[...]
So, a solution seems to be, to block SIGTTOU during the call of
tcsetattr (which Volker did unknowingly in the first place).
--------------------------------------------------
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <signal.h>
int main(void) {
struct termios tio;
sigset_t block_ttou;
sigemptyset (&block_ttou);
sigaddset (&block_ttou, SIGTTOU);
if (tcgetattr(1, &tio) < 0) { exit(1); }
sigprocmask (SIG_BLOCK, &block_ttou, NULL);
if (tcsetattr(1, TCSANOW, &tio) < 0) { exit(1); }
sigprocmask (SIG_UNBLOCK, &block_ttou, NULL);
printf("hello world\n");
exit(0);
}
--------------------------------------------------
It seems to work:
--------------------------------------------------
[584]$ ./terminaltest
hello world
[585]$ ./terminaltest &
[1] 9185
[586]$ hello world
[1]+ Done ./terminaltest
[586]$ stty tostop
[587]$ ./terminaltest &
[1] 9187
[588]$
[1]+ Stopped ./terminaltest
[588]$ fg
./terminaltest
hello world
[589]$
--------------------------------------------------
BTW: SIGTTIN is /not/ affected, AFAICT.
Cheers,
M/
--
/~\ ASCII ribbon | beta test, v: To voluntarily entrust one's data, one's
\ / campaign | livelihood and one's sanity to hardware or software
X against | intended to destroy all three. In earlier days,
/ \ HTML mail | virgins were often selected to beta test volcanos.
More information about the Glasgow-haskell-bugs
mailing list