GNU/Linux: Interrupt/Ctrl-C with SIGSTOP instead of SIGINT [PR gdb/9425, PR gdb/14559]
After the "Always put inferiors in their own terminal/session
[gdb/9425, gdb/14559]" change, when a user types "Ctrl-C" while the
inferior is running, GDB is the one who gets the SIGINT, not the
inferior process. GDB then forwards the SIGINT to the inferior with
target_pass_ctrlc.
That was necessary but not not sufficient to fix PRs gdb/9425,
gdb/14559, because if a program blocks SIGINT with e.g. sigprocmask,
then if GDB sends it a SIGINT, the signal isn't ever delivered to the
process, so ptrace does not intercept it. You type Ctrl-C, but
nothing happens. Similarly, if a program uses sigwait to wait for
SIGINT, and the program receives a SIGINT, the SIGINT is _not_
intercepted by ptrace, it goes straight to the inferior.
Now that the Ctrl-C results in a SIGINT sent to GDB instead of the
inferior, we can make GDB interrupt the program any other way we like.
This patch makes non-stop-capable ports interrupt the program with
stop_all_threads / target_stop (i.e., SIGSTOP) instead of
target_pass_ctrlc (i.e., SIGINT), which always works -- SIGSTOP can't
be blocked/ignored. (In the future GDB may even switch to
PTRACE_INTERRUPT on Linux, though that's a project of its own.)
Another advantage here is with multi-target -- currently, because GDB
relies on Ctrl-C stopping one thread, and then stopping all other
threads in reaction to that stop, target_pass_ctrlc tries to find one
inferior with a thread that is running, in any target. If the
selected target for some reason fails to process the Ctrl-C request,
then the Ctrl-C ends up lost. The mechanism implemented in this patch
is different -- we never have to pick a thread, inferior or target --
we're going to stop everything, so we end up in stop_all_threads.
For non-stop, the patch preserves the current behavior of only
stopping one thread in reaction to Ctrl-C, so it can still happen that
the thread that GDB selects to stop disappears and the Ctrl-C ends up
being lost. However, because now GDB always sees the SIGINT first, we
can change how Ctrl-C behaves there too. We could even make it
configurable -- for example, it could be reasonable that Ctrl-C simply
drops the CLI back to the prompt, without stopping anything at all.
That might be interesting for "set observer-mode on", at least.
This commit has a user-visible behavior change in all-stop mode --
when you interrupt the program with Ctrl-C, instead of:
Thread 1 "threads" received signal SIGINT, Interrupt.
You'll get:
Thread 1 "threads" stopped.
Which is what you already got with the "interrupt" command in non-stop
mode.
If you really want to pass a SIGINT to the program, you can then issue:
(gdb) signal SIGINT
This commit also adjusts the testsuite to cope with that output
alternative.
With this change, the gdb.base/sigint-sigwait.exp and
gdb.base/sigint-masked-out.exp testcases now pass cleanly on
GNU/Linux, on both native debugging and gdbserver + "maint set
target-non-stop on", so the kfails are adjusted accordingly.
gdb/ChangeLog:
yyyy-mm-dd Pedro Alves <pedro@palves.net>
PR gdb/9425
PR gdb/14559
* event-top.c (default_quit_handler): Mark infrun event-loop
handler with mark_infrun_async_event_handler_ctrl_c instead of
passing the Ctrl-C to the target directly with target_pass_ctrlc.
* infcmd.c (interrupt_target_1): On non-stop targets, Mark infrun
event-loop handler with
mark_infrun_async_event_handler_interrupt_all instead of using
target_interrupt.
* infrun.c (interrupt_all_requested, switch_to_stop_thread)
(sync_interrupt_all)
(mark_infrun_async_event_handler_interrupt_all)
(mark_infrun_async_event_handler_ctrl_c): New.
(infrun_async_inferior_event_handler): Handle Ctrl-C/interrupt
requests.
* infrun.h (mark_infrun_async_event_handler_interrupt_all)
(mark_infrun_async_event_handler_ctrl_c): Declare.
* linux-nat.c (wait_for_signal): Don't handle Ctrl-C here.
(linux_nat_wait_1): Handle it here, by marking the infrun event
handler, and returning TARGET_WAITKIND_IGNORE with the quit flag
still set.
* target.c (maybe_pass_ctrlc): New.
(target_terminal::inferior, target_terminal::restore_inferior):
Use it.
(target_pass_ctrlc): Ass there's no non-stop target pushed.
gdb/testsuite/ChangeLog:
yyyy-mm-dd Pedro Alves <pedro@palves.net>
PR gdb/9425
PR gdb/14559
* gdb.base/bp-cmds-continue-ctrl-c.exp: Expect "stopped" in
alternative to "signal SIGINT".
* gdb.base/interrupt-daemon-attach.exp: Likewise.
* gdb.base/interrupt-daemon.exp: Likewise.
* gdb.base/interrupt-noterm.exp: Likewise.
* gdb.base/interrupt.exp: Likewise.
* gdb.base/random-signal.exp: Likewise.
* gdb.base/range-stepping.exp: Likewise.
* gdb.gdb/selftest.exp: Likewise.
* gdb.mi/new-ui-mi-sync.exp: Likewise.
* gdb.multi/multi-target-interrupt.exp: Likewise.
* gdb.multi/multi-target-no-resumed.exp: Likewise.
* gdb.multi/multi-term-settings.exp: Likewise.
* gdb.server/reconnect-ctrl-c.exp: Likewise.
* gdb.threads/async.exp: Likewise.
* gdb.threads/continue-pending-status.exp: Likewise.
* gdb.threads/leader-exit.exp: Likewise.
* gdb.threads/manythreads.exp: Likewise.
* gdb.threads/pthreads.exp: Likewise.
* gdb.threads/schedlock.exp: Likewise.
* gdb.threads/sigthread.exp: Likewise.
* lib/gdb.exp (can_interrupt_blocked_sigint): New.
* gdb.base/sigint-masked-out.exp (test_ctrl_c)
(test_interrupt_cmd): Use can_interrupt_blocked_sigint, and don't
kfail if true.
* gdb.base/sigint-sigwait.exp (test_ctrl_c, test_interrupt_cmd):
Likewise.
Change-Id: I83c1b6a20deea1f1909156adde1d60b8f6f2629b
29 files changed