Getting the terminal while in the background.

Pierre A. Humblet
Wed Sep 29 03:33:00 GMT 2004


Under Cygwin, the command below gives rise to a warning:

~: true | `echo true` &
[1] 380723
~: Use "logout" to leave the shell.
[1]+  Done                    true | `echo true`

I found the explanation, please bear with me.

There are 4 processe involved:
the main interactive pid M
a subprocess A evaluating the first true, 
a subprocess B evaluating `echo true', 
  which still has "interactive" = 1,
  and forking a subprocess C that evaluates the second true.

What's happening is that process B has 
subshell_environment 0x18 = SUBSHELL_PIPE | SUBSHELL_FORK
Accordingly in command_substitute() it sees
  if ((subshell_environment & SUBSHELL_PIPE) == 0)
    pipeline_pgrp = shell_pgrp;
and it does NOT set pipeline_pgrp to shell_pgrp.
It then calls make_child() with async_p = 0.

In the child part of make_child(), subprocess C
sees [PGRP_PIPE is not defined on Cygwin] 
              if (async_p == 0 && pipeline_pgrp != shell_pgrp)
                give_terminal_to (pipeline_pgrp, 0);
and it dutifully gives the terminal to the background pipeline_pgrp, 
which isn't right. 
The comment below suggests that we should have pipeline_pgrp == shell_pgrp
for command substitution...
      /* By convention (and assumption above), if
         pipeline_pgrp == shell_pgrp, we are making a child for
         command substitution.

Meanwhile process B does a wait_for(C), which returns 
the terminal to the top shell_pgrp. However toward the end 
of command_substitute() it sees 
if (interactive && pipeline_pgrp != (pid_t)0 && (subshell_environment & SUBSHELL_ASYNC) == 0)
        give_terminal_to (pipeline_pgrp, 0);
and it gives control to the pipeline_pgrp.
This directly contradicts the adjoining comment:
      /* ..
      pipeline was started in the background.  A pipeline started in
      the background should never get the tty back here. */

The error message is produced when a read() fails with EIO because
the main shell does not have the terminal.
getc_with_restart() translates the error to an EOF.

I don't know why the error does not show up on other systems, 
but I don't see anything unusual in Cygwin that explains
the incorrect behavior outlined above.



More information about the Cygwin-developers mailing list