Pádraig Brady <[email protected]> writes:

> * src/timeout.c (main): Use PR_SET_PDEATHSIG to ensure the
> child is terminated even if the parent terminates abnormally.
> * tests/timeout/timeout-group.sh: Add a case to ensure sending
> SIGKILL results in the termination of the monitored command.
> * NEWS: Mention the improvement.
> ---
>  NEWS                           |  3 +++
>  src/timeout.c                  |  8 ++++++++
>  tests/timeout/timeout-group.sh | 20 +++++++++++++++++++-
>  3 files changed, 30 insertions(+), 1 deletion(-)
>
> diff --git a/NEWS b/NEWS
> index 019451d32..3ce4004a8 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -43,6 +43,9 @@ GNU coreutils NEWS                                    -*- 
> outline -*-
>  
>    csplit, ls, and sort, now handle a more complete set of terminating 
> signals.
>  
> +  'timeout' on Linux will always terminate the child in the case where the
> +  timeout process itself dies, like when it receives a KILL signal for 
> example.
> +
>  ** Build-related
>  
>    'kill' and 'uptime' are no longer built by default.  These programs can be
> diff --git a/src/timeout.c b/src/timeout.c
> index 68ddfd5d6..7634323d4 100644
> --- a/src/timeout.c
> +++ b/src/timeout.c
> @@ -592,6 +592,14 @@ main (int argc, char **argv)
>      }
>    else if (monitored_pid == 0)  /* child */
>      {
> +#if HAVE_PRCTL
> +      /* Add protection if the parent dies without signalling child.  */
> +      prctl (PR_SET_PDEATHSIG, term_signal);
> +#endif
> +      /* If we're already reparented to init, don't proceed.  */
> +      if (getppid () == 1)
> +        return EXIT_CANCELED;
> +
>        /* Restore signal mask for child.  */
>        if (sigprocmask (SIG_SETMASK, &orig_set, nullptr) != 0)
>          {
> diff --git a/tests/timeout/timeout-group.sh b/tests/timeout/timeout-group.sh
> index 81dadcf9d..ebe299f30 100755
> --- a/tests/timeout/timeout-group.sh
> +++ b/tests/timeout/timeout-group.sh
> @@ -76,6 +76,13 @@ check_timeout_cmd_running()
>      { sleep $delay; return 1; }
>  }
>  
> +check_timeout_cmd_exiting()
> +{
> +  local delay="$1"
> +  test -e sig.received ||
> +    { sleep $delay; return 1; }
> +}
> +
>  # Terminate any background processes
>  cleanup_() { kill $pid 2>/dev/null && wait $pid; }
>  
> @@ -88,9 +95,20 @@ retry_delay_ check_timeout_cmd_running .1 6 || fail=1
>  kill -USR1 -- -$pid
>  wait
>  test -e sig.received || fail=1
> -
>  rm -f sig.received timeout.running
>  
> +# On Linux ensure we kill the monitored command
> +# even if we're terminated abnormally (e.g., get SIGKILL).
> +if grep '^#define HAVE_PRCTL 1' "$CONFIG_HEADER" >/dev/null; then
> +  timeout -sUSR1 25 ./timeout.cmd 20 & pid=$!
> +  # Wait 6.3s for timeout.cmd to start
> +  retry_delay_ check_timeout_cmd_running .1 6 || fail=1
> +  kill -KILL -- $pid
> +  wait
> +  # Wait 6.3s for timeout.cmd to exit
> +  retry_delay_ check_timeout_cmd_exiting .1 6 || fail=1
> +  rm -f sig.received timeout.running
> +fi
>  
>  # Ensure cascaded timeouts work
>  # or more generally, ensure we timeout

Patch looks good.

It looks like PR_SET_PDEATHSIG was introduced at the same time as prctl,
so no need to check that both exist. The man pages say Linux 2.1.57 for
both at least (1997).

Collin

Reply via email to