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