bug-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: SIGINT handling


From: Stephane Chazelas
Subject: Re: SIGINT handling
Date: Sun, 20 Sep 2015 20:45:42 +0100
User-agent: Mutt/1.5.21 (2010-09-15)

2015-09-20 17:12:45 +0100, Stephane Chazelas:
[...]
> I thought the termsig_handler was being invoked upon SIGINT as
> the SIGINT handler, but it is being called explicitely by
> set_job_status_and_cleanup so the problem is elsewhere.
> 
> child_caught_sigint is 0 while if I understand correctly it
> should be 1 for a cmd that calls exit() upon SIGINT. So that's
> probably probably where we should be looking.
[...]

I had another look.

If we're to beleive gdb, child_caught_sigint is 0 because
waitpid() returns without EINTR even though wait_sigint_received
is 1.

The only reasonable explanation I can think of is that the child
handles its SIGINT first, exits which updates its state and
causes bash the parent to be scheduled, and waitpid() returns
(without EINT) and after that bash's SIGINT handler kicks in too
late.

Anyway, this patch makes the problem go away for me (and
addresses my problem #2 about exit code 130 not being treated
as an interrupted child). It might break things though if there
was a real reason for bash to check for waitpid()'s EINTR.

With that patch applied,

./bash -c 'sh -c "trap exit INT; sleep 120; :"; echo hi'
./bash -c 'mksh -c "sleep 120; :"; echo hi'

Does *not* output "hi" (as mksh or sh do a exit(130) which is
regarded as them being "interrupted by that SIGINT", or at least
reporting that the child they want to report the status of
(sleep) has been killed by a SIGINT).

And 

./bash -c 'sh -c "trap exit\ 0 INT; sleep 120; :"; echo hi'

*consistently* outputs "hi" (the zero exit status cancels the
aborting of bash).

--- jobs.c~     2015-09-20 20:03:14.692119372 +0100
+++ jobs.c      2015-09-20 20:37:01.510892045 +0100
@@ -3257,21 +3257,15 @@ itrace("waitchld: waitpid returns %d blo
       CHECK_TERMSIG;
       CHECK_WAIT_INTR;
 
-      /* If waitpid returns -1/EINTR and the shell saw a SIGINT, then we
-        assume the child has blocked or handled SIGINT.  In that case, we
-        require the child to actually die due to SIGINT to act on the
-        SIGINT we received; otherwise we assume the child handled it and
-        let it go. */
-      if (pid < 0 && errno == EINTR && wait_sigint_received)
-       child_caught_sigint = 1;
-
       if (pid <= 0)
        continue;       /* jumps right to the test */
 
-      /* If the child process did die due to SIGINT, forget our assumption
-        that it caught or otherwise handled it. */
-      if (WIFSIGNALED (status) && WTERMSIG (status) == SIGINT)
-        child_caught_sigint = 0;
+      /* If we received a SIGINT, but the child did not die of a SIGINT and
+         did not report a 128+SIGINT exit status, we assume the child handled
+         it and let it go. */
+      child_caught_sigint = wait_sigint_received &&
+       ! ((WIFSIGNALED (status) && WTERMSIG (status) == SIGINT) ||
+          (WIFEXITED (status) && WEXITSTATUS (status) == 128 + SIGINT));
 
       /* children_exited is used to run traps on SIGCHLD.  We don't want to
          run the trap if a process is just being continued. */

-- 
Stephane



reply via email to

[Prev in Thread] Current Thread [Next in Thread]