On 30/06/15 02:27, Chet Ramey wrote: > On 6/29/15 3:41 PM, Patrick Plagwitz wrote: > >> Bash Version: 4.3 >> Patch Level: 39 >> Release Status: release >> >> Description: >> There's a bug that happens when waiting for a child process to complete >> (via wait_for in jobs.c) that isn't part of a job, like command >> substitution subshells. If a SIGINT is caught by the >> wait_sigint_handler, the handler sets the wait_sigint_received flag >> which is checked in set_job_status_and_cleanup. But >> set_job_status_and_cleanup is called from waitchld only if the pid >> belongs to a process that is part of a job. The result is that a SIGINT >> trap, if it exists, is not called if a SIGINT is received while waiting >> for a comsub subshell. > > This isn't exactly correct. The SIGINT trap will be called if the process > in the command substitution exits due to SIGINT. For instance, if you > change the assignment to something like: > > foo=$(sleep 20 >&- ) > or > foo=$(exec 2>&- ; sleep 20) > > both of which I think correctly reproduce the python command, the SIGINT > trap will execute. > > This is another case of the scenario most recently described in > > http://lists.gnu.org/archive/html/bug-bash/2014-03/msg00108.html > > In this case, python appears to catch the SIGINT (it looks like a > KeyboardInterrupt exception), print the message, and exit with status 1. > > Chet >
Ok, I see. However, there appears to be some race condition when waiting for a command substitution. I have the attached combination of scripts. When run with $ bash run-until-end-of-loop.sh bash start-subst-loop.sh '2>/dev/null' , the script will try to launch and SIGINT subst-loop.sh repeatedly until the SIGINT trap is once *not* called which will happen in at most 200 repetitions on my machine. The script then ends after printing “end of loop”. The python script execute-with-sigint.py is only there to enable subst-loop.sh to receive a SIGINT at all. subst-loop.sh calls date(1) in a loop; date should have SIGINT set to SIG_DFL other than python initially. I analyzed the execution by inserting some debug output into the bash code. It seems that in the case that the SIGINT trap is not called subst-loop.sh gets the SIGINT while (or shortly before or after) calling waitpid in waitchld:jobs.c which will then return without errno == EINTR. The wait_sigint_handler will be called, though, and so wait_sigint_received will be true. If you try the script often enough, it will sometimes block. I saw that this is because wait_sigint_handler calls itself in an infinite loop. If I understand it correctly, this happens since wait_for:jobs.c calls old_sigint_handler = set_signal_handler (SIGINT, wait_sigint_handler); and if a SIGINT is caught after sigaction in set_signal_handler was called but before old_sigint_handler is set, restore_sigint_handler (); kill (getpid (), SIGINT); in wait_sigint_handler will leave wait_sigint_handler as handler.
run-until-end-of-loop.sh
Description: application/shellscript
start-subst-loop.sh
Description: application/shellscript
import signal import os import sys signal.signal(signal.SIGINT, signal.SIG_DFL) sys.stderr.write(os.environ["SHELL"] + "\n") os.execv(os.environ["SHELL"], [os.environ["SHELL"]] + sys.argv[1:])
subst-loop.sh
Description: application/shellscript