Subject: bug#8938: make timeout and CTRL-C

From: "Alan Curry" <[email-masked]>
Date: Mon, 27 Jun 2011 15:12:45 -0500 (GMT+5)

=?UTF-8?Q?P=C3=A1draig?= Brady writes:
> 
> On 26/06/11 20:20, shay shimony wrote:
> > all:
> >         timeout 12 sleep 10
> > 
> > Note there is a tab before "timeout 12 sleep 10".
> > Then run at same directory where the file is located "make" and try to press
> > CTRL-C.
> > 
> > Notes:
> > CTRL-Z works.
> > When executing timeout without make CTRL-C works.
> > When executing make without timeout CTRL-C works.
> 
> Drats,
> 
> That because SIGINT is sent by the terminal to the foreground group.
> The issue is that `make` and `timeout` use much the same method
> to control their jobs. I.E. they create their own process group
> so they can terminate all sub-processes.

Are you sure? I see no evidence of that. When I run make with the above
makefile, the processes look like this:

 PPID   PID  PGID   SID TTY TPGID  STAT  UID   TIME COMMAND
    1  1451  1451  1451   6 16407  S    1000   0:06 -zsh
 1451 16407 16407  1451   6 16407  S    1000   0:00 make
16407 16408 16408  1451   6 16407  S    1000   0:00 timeout 60 sleep 30
16408 16409 16408  1451   6 16407  S    1000   0:00 sleep 30

The first PGID is the login shell. The second PGID is make, which was put
into its own process group by the shell because the shell has job control
enabled. The last PGID is timeout, which put itself into a process group.
make never noticed any of them.

In the source for GNU make 3.82 there are no calls to setpgrp or setpgid
(unless obfuscated from grep). There is the following comment:

  /* A termination signal won't be sent to the entire
     process group, but it means we want to kill the children.  */

That's above the handling of SIGTERM, which iterates over child processes and
passes along the SIGTERM to them.

After that is the handling of SIGINT, which doesn't kill child processes
(unless they're "remote", which is... news to me that make does remote
things) but just waits for them.

What seems to be happening is that make *doesn't* create a process group,
therefore assumes that when it gets a SIGINT, its children have already
gotten it too, and it just waits for them to die. A child that puts itself
into a new process group screws this up (as would kill -2 `pidof make`).

I think the answer is that timeout should put itself into the foreground.
That way it would get the SIGINT. make wouldn't get it, but wouldn't need to.
timeout would exit quickly after SIGINT and make would proceed or abort
according to the exit code.

-- 
Alan Curry