From: Pedro Alves <pedro@palves.net>
To: gdb-patches@sourceware.org
Subject: [PATCH v2 15/16] GNU/Linux: Interrupt/Ctrl-C with SIGSTOP instead of SIGINT [PR gdb/9425, PR gdb/14559]
Date: Mon, 14 Jun 2021 22:24:09 +0100 [thread overview]
Message-ID: <20210614212410.1612666-16-pedro@palves.net> (raw)
In-Reply-To: <20210614212410.1612666-1-pedro@palves.net>
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
---
gdb/event-top.c | 10 +-
gdb/infcmd.c | 34 +++-
gdb/infrun.c | 149 +++++++++++++++++-
gdb/infrun.h | 12 ++
gdb/linux-nat.c | 39 +++--
gdb/target.c | 24 ++-
.../gdb.base/bp-cmds-continue-ctrl-c.exp | 3 +
.../gdb.base/interrupt-daemon-attach.exp | 2 +-
gdb/testsuite/gdb.base/interrupt-daemon.exp | 4 +-
gdb/testsuite/gdb.base/interrupt-noterm.exp | 2 +-
gdb/testsuite/gdb.base/interrupt.exp | 4 +-
gdb/testsuite/gdb.base/random-signal.exp | 3 +-
gdb/testsuite/gdb.base/range-stepping.exp | 2 +-
gdb/testsuite/gdb.base/sigint-masked-out.exp | 12 +-
gdb/testsuite/gdb.base/sigint-sigwait.exp | 12 +-
gdb/testsuite/gdb.gdb/selftest.exp | 4 +-
gdb/testsuite/gdb.mi/new-ui-mi-sync.exp | 2 +-
.../gdb.multi/multi-target-interrupt.exp | 2 +-
.../gdb.multi/multi-target-no-resumed.exp | 2 +-
.../gdb.multi/multi-term-settings.exp | 2 +-
gdb/testsuite/gdb.server/reconnect-ctrl-c.exp | 4 +-
gdb/testsuite/gdb.threads/async.exp | 2 +-
.../gdb.threads/continue-pending-status.exp | 2 +-
gdb/testsuite/gdb.threads/leader-exit.exp | 2 +-
gdb/testsuite/gdb.threads/manythreads.exp | 4 +-
gdb/testsuite/gdb.threads/pthreads.exp | 2 +-
gdb/testsuite/gdb.threads/schedlock.exp | 11 +-
gdb/testsuite/gdb.threads/sigthread.exp | 2 +-
gdb/testsuite/lib/gdb.exp | 19 +++
29 files changed, 315 insertions(+), 57 deletions(-)
diff --git a/gdb/event-top.c b/gdb/event-top.c
index 002a7dc95e0..9741b23576a 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -1002,7 +1002,15 @@ default_quit_handler (void)
if (target_terminal::is_ours ())
quit ();
else
- target_pass_ctrlc ();
+ {
+ /* Let the even loop handle the quit/interrupt. In some
+ modes (e.g., "set non-stop off" + "maint set
+ target-non-stop on"), it's not safe to request an
+ interrupt right now, as we may be in the middle of
+ handling some other event, and target_stop changes infrun
+ state. */
+ mark_infrun_async_event_handler_ctrl_c ();
+ }
}
}
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 99ce0ec78fa..72051bdc095 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -2846,7 +2846,39 @@ interrupt_target_1 (bool all_threads)
stop_current_target_threads_ns (inferior_ptid);
}
else
- target_interrupt ();
+ {
+ if (exists_non_stop_target ())
+ {
+ /* Ignore the interrupt request if everything is already
+ stopped. */
+ auto any_resumed = [] ()
+ {
+ for (thread_info *thr : all_non_exited_threads ())
+ {
+ if (thr->executing)
+ return true;
+ if (thr->suspend.waitstatus_pending_p)
+ return true;
+ }
+ return false;
+ };
+
+ if (any_resumed ())
+ {
+ /* Stop all threads, and report one single stop for all
+ threads. Since the "interrupt" command works
+ asynchronously on all other modes (non-stop or true
+ all-stop + stopping with SIGINT), i.e., the command
+ finishes and GDB prints the prompt before the target
+ actually stops, make this mode work the same, by
+ deferring the actual synchronous stopping work to the
+ event loop. */
+ mark_infrun_async_event_handler_interrupt_all ();
+ }
+ }
+ else
+ target_interrupt ();
+ }
disable_commit_resumed.reset_and_commit ();
}
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 3f40fa39b5a..f3f24839f32 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -9440,13 +9440,158 @@ static const struct internalvar_funcs siginfo_funcs =
NULL
};
-/* Callback for infrun's target events source. This is marked when a
- thread has a pending status to process. */
+/* True if the user used the "interrupt" command and we want to handle
+ the interruption via the event loop instead of immediately. This
+ is so that "interrupt" always stops the program asynchronously in
+ all the different execution modes. In particular, in "set non-stop
+ off" + "maint set target-non-stop on" mode, we want to
+ synchronously stop all threads with stop_all_threads, so we delay
+ doing that to the event loop, so that "interrupt" presents a prompt
+ immediately, and then presents the stop afterwards, just like what
+ happens in non-stop mode, or if the target is in true all-stop mode
+ and the interrupting is done by sending a SIGINT to the inferior
+ process. */
+static bool interrupt_all_requested = false;
+
+/* Pick the thread to report the stop on and to switch to it. */
+
+static void
+switch_to_stop_thread ()
+{
+ thread_info *stop_thr = nullptr;
+
+ if (previous_thread != nullptr && previous_thread->state == THREAD_RUNNING)
+ stop_thr = previous_thread.get ();
+ else
+ {
+ for (thread_info *thr : all_non_exited_threads ())
+ if (thr->state == THREAD_RUNNING)
+ {
+ stop_thr = thr;
+ break;
+ }
+ }
+
+ gdb_assert (stop_thr != nullptr);
+
+ switch_to_thread (stop_thr);
+}
+
+/* Synchronously stop all threads, saving interesting events as
+ pending events, and present a normal stop on one of the threads.
+ Preference is given to the "previous thread", which was the thread
+ that the user last resumed. This is used in "set non-stop off" +
+ "maint set target-non-stop on" mode to stop the target in response
+ to Ctrl-C or the "interrupt" command. */
+
+static void
+sync_interrupt_all ()
+{
+ /* Events are always processed with the main UI as current UI. This
+ way, warnings, debug output, etc. are always consistently sent to
+ the main console. */
+ scoped_restore save_ui = make_scoped_restore (¤t_ui, main_ui);
+
+ /* Exposed by gdb.base/paginate-after-ctrl-c-running.exp. */
+
+ /* Temporarily disable pagination. Otherwise, the user would be
+ given an option to press 'q' to quit, which would cause an early
+ exit and could leave GDB in a half-baked state. */
+ scoped_restore save_pagination
+ = make_scoped_restore (&pagination_enabled, false);
+
+ scoped_disable_commit_resumed disable_commit_resumed ("stopping for ctrl-c");
+
+ gdb_assert (!non_stop);
+
+ /* Stop all threads before picking which one to present the stop on
+ -- this is safer than the other way around because otherwise the
+ thread we pick could exit just while we try to stop it. */
+ stop_all_threads ();
+
+ switch_to_stop_thread ();
+
+ target_waitstatus ws;
+ ws.kind = TARGET_WAITKIND_STOPPED;
+ ws.value.sig = GDB_SIGNAL_0;
+ set_last_target_status (current_inferior ()->process_target (),
+ inferior_ptid, ws);
+ stopped_by_random_signal = true;
+ stop_print_frame = true;
+ normal_stop ();
+
+ inferior_event_handler (INF_EXEC_COMPLETE);
+
+ /* If a UI was in sync execution mode, and now isn't, restore its
+ prompt (a synchronous execution command has finished, and we're
+ ready for input). */
+ all_uis_check_sync_execution_done ();
+}
+
+/* See infrun.h. */
+
+void
+mark_infrun_async_event_handler_interrupt_all ()
+{
+ mark_infrun_async_event_handler ();
+ interrupt_all_requested = true;
+}
+
+/* See infrun.h. */
+
+void
+mark_infrun_async_event_handler_ctrl_c ()
+{
+ mark_infrun_async_event_handler ();
+ set_quit_flag ();
+}
+
+/* Callback for infrun's target events source. This is marked either
+ when a thread has a pending status to process, or a target
+ interrupt was requested, either with Ctrl-C or the "interrupt"
+ command and target is in non-stop mode. */
static void
infrun_async_inferior_event_handler (gdb_client_data data)
{
+ /* Handle a Ctrl-C while the inferior has the terminal, or an
+ "interrupt" cmd request. */
+ if ((!target_terminal::is_ours () && check_quit_flag ())
+ || interrupt_all_requested)
+ {
+ interrupt_all_requested = false;
+
+ if (exists_non_stop_target ())
+ {
+ if (non_stop)
+ {
+ /* Stop one thread, like it would happen if we were
+ stopping with SIGINT sent to the foreground
+ process. */
+ switch_to_stop_thread ();
+ interrupt_target_1 (false);
+ }
+ else
+ {
+ /* Stop all threads, and report one single stop for all
+ threads. */
+ sync_interrupt_all ();
+ }
+ }
+ else
+ {
+ /* Pass a Ctrl-C request to the target. Usually this means
+ sending a SIGINT to the inferior process. */
+ target_pass_ctrlc ();
+ }
+
+ /* Don't clear the event handler yet -- there may be pending
+ events to process. */
+ return;
+ }
+
clear_async_event_handler (infrun_async_inferior_event_token);
+
inferior_event_handler (INF_REG_EVENT);
}
diff --git a/gdb/infrun.h b/gdb/infrun.h
index 5d791bdc5b4..64fdfc7ab60 100644
--- a/gdb/infrun.h
+++ b/gdb/infrun.h
@@ -255,6 +255,18 @@ extern void infrun_async (int enable);
loop. */
extern void mark_infrun_async_event_handler (void);
+/* Like mark_infrun_async_event_handler, and ask the event loop to
+ stop all threads, in response to an "interrupt" command. */
+extern void mark_infrun_async_event_handler_interrupt_all ();
+
+/* Like mark_infrun_async_event_handler, and ask the event loop to
+ handle a "Ctrl-C" interruption request. In some modes (e.g., "set
+ non-stop off" + "maint set target-non-stop on"), we interrupt the
+ target with target_stop, and it's not safe to use that right away,
+ as we may be in the middle of handling some other event, and
+ target_stop changes infrun state. */
+extern void mark_infrun_async_event_handler_ctrl_c ();
+
/* The global chain of threads that need to do a step-over operation
to get past e.g., a breakpoint. */
extern struct thread_info *global_thread_step_over_chain_head;
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index d31bcd98e84..a40b3c30012 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -2142,19 +2142,6 @@ wait_for_signal ()
{
linux_nat_debug_printf ("about to sigsuspend");
sigsuspend (&suspend_mask);
-
- /* If the quit flag is set, it means that the user pressed Ctrl-C
- and we're debugging a process that is running on a separate
- terminal, so we must forward the Ctrl-C to the inferior. (If the
- inferior is sharing GDB's terminal, then the Ctrl-C reaches the
- inferior directly.) We must do this here because functions that
- need to block waiting for a signal loop forever until there's an
- event to report before returning back to the event loop. */
- if (!target_terminal::is_ours ())
- {
- if (check_quit_flag ())
- target_pass_ctrlc ();
- }
}
/* Wait for LP to stop. Returns the wait status, or 0 if the LWP has
@@ -3317,8 +3304,32 @@ linux_nat_wait_1 (ptid_t ptid, struct target_waitstatus *ourstatus,
/* We shouldn't end up here unless we want to try again. */
gdb_assert (lp == NULL);
- /* Block until we get an event reported with SIGCHLD. */
+ /* Block until we get an event reported with SIGCHLD or a SIGINT
+ interrupt. */
wait_for_signal ();
+
+ /* If the quit flag is set, it means that the user pressed
+ Ctrl-C and we're debugging a process that is running on a
+ separate terminal, so we must forward the Ctrl-C to the
+ inferior. (If the inferior is sharing GDB's terminal, then
+ the Ctrl-C reaches the inferior directly.) If we were
+ interrupted by Ctrl-C, return back to the event loop and let
+ it handle interrupting the target (or targets). */
+
+ if (!target_terminal::is_ours () && check_quit_flag ())
+ {
+ mark_infrun_async_event_handler_ctrl_c ();
+
+ linux_nat_debug_printf ("exit (quit flag)");
+
+ /* If we got a SIGCHLD, need to end up here again. */
+ async_file_mark ();
+
+ ourstatus->kind = TARGET_WAITKIND_IGNORE;
+
+ restore_child_signals_mask (&prev_mask);
+ return minus_one_ptid;
+ }
}
gdb_assert (lp);
diff --git a/gdb/target.c b/gdb/target.c
index 68d7e7c12d7..ab4dc7bd5dd 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -927,6 +927,21 @@ target_terminal::init (void)
m_terminal_state = target_terminal_state::is_ours;
}
+/* Called after switching the terminal to the inferior. If the user
+ hit C-c before, pretend that it was hit right here. Non-stop
+ targets however are more complicated though, as interruption with
+ "set non-stop off" + "maint set target-non-stop on" wants to stop
+ all threads individually with target_stop (and synchronously wait
+ for the stops), so we let the event loop handle it, when it's
+ recursion-safe to do so. */
+
+static void
+maybe_pass_ctrlc ()
+{
+ if (!exists_non_stop_target () && check_quit_flag ())
+ target_pass_ctrlc ();
+}
+
/* See target/target.h. */
void
@@ -961,8 +976,7 @@ target_terminal::inferior (void)
/* If the user hit C-c before, pretend that it was hit right
here. */
- if (check_quit_flag ())
- target_pass_ctrlc ();
+ maybe_pass_ctrlc ();
}
/* See target/target.h. */
@@ -998,8 +1012,7 @@ target_terminal::restore_inferior (void)
/* If the user hit C-c before, pretend that it was hit right
here. */
- if (check_quit_flag ())
- target_pass_ctrlc ();
+ maybe_pass_ctrlc ();
}
/* Switch terminal state to DESIRED_STATE, either is_ours, or
@@ -3797,6 +3810,9 @@ target_interrupt ()
void
target_pass_ctrlc (void)
{
+ /* Non-stop targets interrupt programs with target_stop instead. */
+ gdb_assert (!exists_non_stop_target ());
+
/* Pass the Ctrl-C to the first target that has a thread
running. */
for (inferior *inf : all_inferiors ())
diff --git a/gdb/testsuite/gdb.base/bp-cmds-continue-ctrl-c.exp b/gdb/testsuite/gdb.base/bp-cmds-continue-ctrl-c.exp
index d21f580af87..e7e7a4c43a6 100644
--- a/gdb/testsuite/gdb.base/bp-cmds-continue-ctrl-c.exp
+++ b/gdb/testsuite/gdb.base/bp-cmds-continue-ctrl-c.exp
@@ -87,6 +87,9 @@ proc do_test {} {
-re "Program received signal SIGINT.*\r\n$gdb_prompt $" {
send_log "$internal_pass (SIGINT)\n"
}
+ -re "Program stopped.*\r\n$gdb_prompt $" {
+ send_log "$internal_pass (stopped)\n"
+ }
-re "Quit\r\n$gdb_prompt $" {
send_log "$internal_pass (Quit)\n"
diff --git a/gdb/testsuite/gdb.base/interrupt-daemon-attach.exp b/gdb/testsuite/gdb.base/interrupt-daemon-attach.exp
index e43bfe4f4ad..840bbec2dc1 100644
--- a/gdb/testsuite/gdb.base/interrupt-daemon-attach.exp
+++ b/gdb/testsuite/gdb.base/interrupt-daemon-attach.exp
@@ -81,7 +81,7 @@ proc do_test {} {
}
after 500 {send_gdb "\003"}
- gdb_test "" "(Program|Thread .*) received signal SIGINT.*" \
+ gdb_test "" "(Program|Thread .*) (received signal SIGINT|stopped).*" \
"stop with control-c"
remote_exec host "kill -9 $child_pid"
diff --git a/gdb/testsuite/gdb.base/interrupt-daemon.exp b/gdb/testsuite/gdb.base/interrupt-daemon.exp
index 2270ab0cbc2..0b0b6dc3e80 100644
--- a/gdb/testsuite/gdb.base/interrupt-daemon.exp
+++ b/gdb/testsuite/gdb.base/interrupt-daemon.exp
@@ -53,7 +53,7 @@ proc do_test {} {
set test "ctrl-c stops process"
gdb_test_multiple "" $test {
- -re "received signal SIGINT.*\r\n$gdb_prompt $" {
+ -re "(received signal SIGINT|stopped).*\r\n$gdb_prompt $" {
pass $test
}
}
@@ -79,7 +79,7 @@ proc do_test {} {
set test "interrupt cmd stops process"
gdb_test_multiple "" $test {
- -re "received signal SIGINT" {
+ -re "(received signal SIGINT|stopped)" {
pass $test
}
}
diff --git a/gdb/testsuite/gdb.base/interrupt-noterm.exp b/gdb/testsuite/gdb.base/interrupt-noterm.exp
index 5cfc6171dd4..089b43305fe 100644
--- a/gdb/testsuite/gdb.base/interrupt-noterm.exp
+++ b/gdb/testsuite/gdb.base/interrupt-noterm.exp
@@ -67,7 +67,7 @@ gdb_test_multiple $test $test {
set test "inferior received SIGINT"
gdb_test_multiple "" $test {
- -re "\r\nProgram received signal SIGINT.*" {
+ -re "\r\nProgram (received signal SIGINT|stopped).*" {
# This appears after the prompt, which was already consumed
# above.
pass $test
diff --git a/gdb/testsuite/gdb.base/interrupt.exp b/gdb/testsuite/gdb.base/interrupt.exp
index 41788ccade2..30ca6d44285 100644
--- a/gdb/testsuite/gdb.base/interrupt.exp
+++ b/gdb/testsuite/gdb.base/interrupt.exp
@@ -82,7 +82,7 @@ if ![file exists $binfile] then {
send_gdb "\003"
set msg "send_gdb control C"
gdb_test_multiple "" $msg {
- -re "Program received signal SIGINT.*$gdb_prompt $" {
+ -re "Program (received signal SIGINT|stopped).*$gdb_prompt $" {
pass $msg
}
}
@@ -166,7 +166,7 @@ if ![file exists $binfile] then {
set msg "Send Control-C, second time"
send_gdb "\003"
gdb_test_multiple "" "$msg" {
- -re "Program received signal SIGINT.*$gdb_prompt $" {
+ -re "Program (received signal SIGINT|stopped).*$gdb_prompt $" {
pass "$msg"
}
}
diff --git a/gdb/testsuite/gdb.base/random-signal.exp b/gdb/testsuite/gdb.base/random-signal.exp
index 8511e83fce5..4c8806ce367 100644
--- a/gdb/testsuite/gdb.base/random-signal.exp
+++ b/gdb/testsuite/gdb.base/random-signal.exp
@@ -47,7 +47,8 @@ proc do_test {} {
# For this to work we must be sure to consume the "Continuing."
# message first, or GDB's signal handler may not be in place.
after 500 {send_gdb "\003"}
- gdb_test "" "Program received signal SIGINT.*" "stop with control-c"
+ gdb_test "" "Program (received signal SIGINT|stopped).*" \
+ "stop with control-c"
}
# With native debugging and "run" (with job control), the ctrl-c
diff --git a/gdb/testsuite/gdb.base/range-stepping.exp b/gdb/testsuite/gdb.base/range-stepping.exp
index c1ba8ef71cb..21bd7326370 100644
--- a/gdb/testsuite/gdb.base/range-stepping.exp
+++ b/gdb/testsuite/gdb.base/range-stepping.exp
@@ -193,7 +193,7 @@ if ![target_info exists gdb,nointerrupts] {
incr vcont_r_counter
exp_continue
}
- -re "Program received signal SIGINT.*$gdb_prompt $" {
+ -re "Program (received signal SIGINT|stopped).*$gdb_prompt $" {
pass $test
}
}
diff --git a/gdb/testsuite/gdb.base/sigint-masked-out.exp b/gdb/testsuite/gdb.base/sigint-masked-out.exp
index 0391152e93a..77a599d12ef 100644
--- a/gdb/testsuite/gdb.base/sigint-masked-out.exp
+++ b/gdb/testsuite/gdb.base/sigint-masked-out.exp
@@ -36,6 +36,8 @@ proc_with_prefix test_ctrl_c {} {
return
}
+ set can_interrupt [can_interrupt_blocked_sigint]
+
gdb_test_multiple "continue" "" {
-re "Continuing" {
pass $gdb_test_name
@@ -52,7 +54,9 @@ proc_with_prefix test_ctrl_c {} {
pass $gdb_test_name
}
timeout {
- setup_kfail "gdb/9425" *-*-*
+ if {!$can_interrupt} {
+ setup_kfail "gdb/9425" *-*-*
+ }
fail "$gdb_test_name (timeout)"
}
}
@@ -71,6 +75,8 @@ proc_with_prefix test_interrupt_cmd {} {
return
}
+ set can_interrupt [can_interrupt_blocked_sigint]
+
gdb_test_multiple "continue&" "" {
-re "Continuing\\.\r\n$gdb_prompt " {
pass $gdb_test_name
@@ -91,7 +97,9 @@ proc_with_prefix test_interrupt_cmd {} {
pass $gdb_test_name
}
timeout {
- setup_kfail "gdb/14559" *-*-*
+ if {!$can_interrupt} {
+ setup_kfail "gdb/14559" *-*-*
+ }
fail "$gdb_test_name (timeout)"
}
}
diff --git a/gdb/testsuite/gdb.base/sigint-sigwait.exp b/gdb/testsuite/gdb.base/sigint-sigwait.exp
index 1dd706fc1a4..e37a2d2cbef 100644
--- a/gdb/testsuite/gdb.base/sigint-sigwait.exp
+++ b/gdb/testsuite/gdb.base/sigint-sigwait.exp
@@ -37,6 +37,8 @@ proc_with_prefix test_ctrl_c {} {
return
}
+ set can_interrupt [can_interrupt_blocked_sigint]
+
gdb_test_multiple "continue" "" {
-re "Continuing" {
pass $gdb_test_name
@@ -54,7 +56,9 @@ proc_with_prefix test_ctrl_c {} {
pass $gdb_test_name
}
-re -wrap "Inferior.*exited normally.*" {
- setup_kfail "gdb/9425" *-*-*
+ if {!$can_interrupt} {
+ setup_kfail "gdb/9425" *-*-*
+ }
fail "$gdb_test_name (the program exited)"
}
}
@@ -73,6 +77,8 @@ proc_with_prefix test_interrupt_cmd {} {
return
}
+ set can_interrupt [can_interrupt_blocked_sigint]
+
gdb_test_multiple "continue&" "" {
-re "Continuing\\.\r\n$gdb_prompt " {
pass $gdb_test_name
@@ -95,7 +101,9 @@ proc_with_prefix test_interrupt_cmd {} {
pass $gdb_test_name
}
-re "Inferior.*exited normally" {
- setup_kfail "gdb/14559" *-*-*
+ if {!$can_interrupt} {
+ setup_kfail "gdb/14559" *-*-*
+ }
fail "$gdb_test_name (the program exited)"
}
}
diff --git a/gdb/testsuite/gdb.gdb/selftest.exp b/gdb/testsuite/gdb.gdb/selftest.exp
index bee3010bca1..7679131b8e7 100644
--- a/gdb/testsuite/gdb.gdb/selftest.exp
+++ b/gdb/testsuite/gdb.gdb/selftest.exp
@@ -97,7 +97,7 @@ proc test_with_self { } {
send_gdb "\003"
# "Thread 1" is displayed iff Guile support is linked in.
gdb_expect {
- -re "(Thread .*|Program) received signal SIGINT.*$gdb_prompt $" {
+ -re "(Thread .*|Program) (received signal SIGINT|stopped).*$gdb_prompt $" {
pass "$description"
}
-re ".*$gdb_prompt $" {
@@ -119,7 +119,7 @@ proc test_with_self { } {
set description "send ^C to child process again"
send_gdb "\003"
gdb_expect {
- -re "(Thread .*|Program) received signal SIGINT.*$gdb_prompt $" {
+ -re "(Thread .*|Program) (received signal SIGINT|stopped).*$gdb_prompt $" {
pass "$description"
}
-re ".*$gdb_prompt $" {
diff --git a/gdb/testsuite/gdb.mi/new-ui-mi-sync.exp b/gdb/testsuite/gdb.mi/new-ui-mi-sync.exp
index 887bd60abcd..8eadc2f6f22 100644
--- a/gdb/testsuite/gdb.mi/new-ui-mi-sync.exp
+++ b/gdb/testsuite/gdb.mi/new-ui-mi-sync.exp
@@ -92,7 +92,7 @@ proc do_test {sync_command} {
gdb_test_multiple "interrupt" "$message" {
-re "$gdb_prompt " {
gdb_test_multiple "" "$message" {
- -re "received signal SIGINT" {
+ -re "(received signal SIGINT|stopped)" {
pass $message
}
}
diff --git a/gdb/testsuite/gdb.multi/multi-target-interrupt.exp b/gdb/testsuite/gdb.multi/multi-target-interrupt.exp
index cafd60d31b1..36b47a40c1a 100644
--- a/gdb/testsuite/gdb.multi/multi-target-interrupt.exp
+++ b/gdb/testsuite/gdb.multi/multi-target-interrupt.exp
@@ -46,7 +46,7 @@ proc test_ctrlc {} {
set msg "send_gdb control C"
gdb_test_multiple "" $msg {
- -re "received signal SIGINT.*$gdb_prompt $" {
+ -re "(received signal SIGINT|stopped).*$gdb_prompt $" {
pass $msg
}
}
diff --git a/gdb/testsuite/gdb.multi/multi-target-no-resumed.exp b/gdb/testsuite/gdb.multi/multi-target-no-resumed.exp
index 6e84d9a6949..0ce26f28199 100644
--- a/gdb/testsuite/gdb.multi/multi-target-no-resumed.exp
+++ b/gdb/testsuite/gdb.multi/multi-target-no-resumed.exp
@@ -59,7 +59,7 @@ proc test_no_resumed_infs {inf_A inf_B} {
# Now stop the program (all targets).
send_gdb "\003"
gdb_test_multiple "" "send_gdb control C" {
- -re "received signal SIGINT.*$gdb_prompt $" {
+ -re "(received signal SIGINT|stopped).*$gdb_prompt $" {
pass $gdb_test_name
}
}
diff --git a/gdb/testsuite/gdb.multi/multi-term-settings.exp b/gdb/testsuite/gdb.multi/multi-term-settings.exp
index 5275391a73c..7796d508083 100644
--- a/gdb/testsuite/gdb.multi/multi-term-settings.exp
+++ b/gdb/testsuite/gdb.multi/multi-term-settings.exp
@@ -278,7 +278,7 @@ proc coretest {inf1_how inf2_how} {
if {$expect_ttou} {
gdb_test "" "Quit" "stop with control-c (Quit)"
} else {
- gdb_test "" "received signal SIGINT.*" "stop with control-c (SIGINT)"
+ gdb_test "" "(received signal SIGINT|stopped).*" "stop with control-c (SIGINT)"
}
# Useful for debugging in case the Ctrl-C above fails.
diff --git a/gdb/testsuite/gdb.server/reconnect-ctrl-c.exp b/gdb/testsuite/gdb.server/reconnect-ctrl-c.exp
index 11aa5147c78..2121c47e873 100644
--- a/gdb/testsuite/gdb.server/reconnect-ctrl-c.exp
+++ b/gdb/testsuite/gdb.server/reconnect-ctrl-c.exp
@@ -49,7 +49,7 @@ with_test_prefix "preparation" {
gdb_test "disconnect" ".*"
}
-# Connect, continue, send Ctrl-C and expect a SIGINT stop.
+# Connect, continue, send Ctrl-C and expect a stop.
proc connect_continue_ctrl_c {} {
global gdbserver_protocol gdbserver_gdbport
@@ -67,7 +67,7 @@ proc connect_continue_ctrl_c {} {
}
after 1000 {send_gdb "\003"}
- gdb_test "" "Program received signal SIGINT.*" "stop with control-c"
+ gdb_test "" "Program (received signal SIGINT|stopped).*" "stop with control-c"
}
with_test_prefix "first" {
diff --git a/gdb/testsuite/gdb.threads/async.exp b/gdb/testsuite/gdb.threads/async.exp
index c49deb1f8b5..f7be1271b7b 100644
--- a/gdb/testsuite/gdb.threads/async.exp
+++ b/gdb/testsuite/gdb.threads/async.exp
@@ -80,7 +80,7 @@ proc test_current_thread {expected_thr} {
gdb_test_multiple $test $test {
-re "^interrupt\r\n$gdb_prompt " {
gdb_test_multiple "" $test {
- -re "Thread .* received signal SIGINT, Interrupt\\." {
+ -re "Thread .* (received signal SIGINT, Interrupt|stopped)\\." {
pass $test
}
}
diff --git a/gdb/testsuite/gdb.threads/continue-pending-status.exp b/gdb/testsuite/gdb.threads/continue-pending-status.exp
index c0321c39d11..ca82290e260 100644
--- a/gdb/testsuite/gdb.threads/continue-pending-status.exp
+++ b/gdb/testsuite/gdb.threads/continue-pending-status.exp
@@ -116,7 +116,7 @@ for {set i 0} {$i < $attempts} {incr i} {
set msg "caught interrupt"
gdb_test_multiple "" $msg {
- -re "Thread .* received signal SIGINT.*$gdb_prompt $" {
+ -re "Thread .* (received signal SIGINT|stopped).*$gdb_prompt $" {
pass $msg
}
}
diff --git a/gdb/testsuite/gdb.threads/leader-exit.exp b/gdb/testsuite/gdb.threads/leader-exit.exp
index fe06e6d4f29..fb76bba3e3b 100644
--- a/gdb/testsuite/gdb.threads/leader-exit.exp
+++ b/gdb/testsuite/gdb.threads/leader-exit.exp
@@ -55,7 +55,7 @@ send_gdb "\003"
set test "caught interrupt"
gdb_test_multiple "" $test {
- -re "Thread .* received signal SIGINT.*$gdb_prompt $" {
+ -re "Thread .* (received signal SIGINT|stopped).*$gdb_prompt $" {
pass $test
}
}
diff --git a/gdb/testsuite/gdb.threads/manythreads.exp b/gdb/testsuite/gdb.threads/manythreads.exp
index b0004b912b7..992c46a3874 100644
--- a/gdb/testsuite/gdb.threads/manythreads.exp
+++ b/gdb/testsuite/gdb.threads/manythreads.exp
@@ -56,7 +56,7 @@ gdb_test_multiple "continue" "first continue" {
# we don't lose GDB's output while we do it.
remote_expect host 1 { timeout { } }
-# Send a Ctrl-C and wait for the SIGINT.
+# Send a Ctrl-C and wait for the stop.
proc interrupt_and_wait { message } {
global gdb_prompt
@@ -70,7 +70,7 @@ proc interrupt_and_wait { message } {
-re "\\\[\[^\]\]* exited\\\]\r\n" {
exp_continue
}
- -re " received signal SIGINT.*$gdb_prompt $" {
+ -re " (received signal SIGINT|stopped).*$gdb_prompt $" {
pass "$message"
}
-re "$gdb_prompt $" {
diff --git a/gdb/testsuite/gdb.threads/pthreads.exp b/gdb/testsuite/gdb.threads/pthreads.exp
index 86258b1d874..4bf8544db52 100644
--- a/gdb/testsuite/gdb.threads/pthreads.exp
+++ b/gdb/testsuite/gdb.threads/pthreads.exp
@@ -204,7 +204,7 @@ proc check_control_c {} {
send_gdb "\003"
set description "Stopped with a ^C"
gdb_expect {
- -re "Thread .* received signal SIGINT.*$gdb_prompt $" {
+ -re "Thread .* (received signal SIGINT|stopped).*$gdb_prompt $" {
pass $description
}
-re "Quit.*$gdb_prompt $" {
diff --git a/gdb/testsuite/gdb.threads/schedlock.exp b/gdb/testsuite/gdb.threads/schedlock.exp
index 90c70587220..ab25c3d0388 100644
--- a/gdb/testsuite/gdb.threads/schedlock.exp
+++ b/gdb/testsuite/gdb.threads/schedlock.exp
@@ -68,14 +68,9 @@ proc stop_process { description } {
# For this to work we must be sure to consume the "Continuing."
# message first, or GDB's signal handler may not be in place.
after 1000 {send_gdb "\003"}
- gdb_expect {
- -re "Thread .* received signal SIGINT.*$gdb_prompt $"
- {
- pass $description
- }
- timeout
- {
- fail "$description (timeout)"
+ gdb_test_multiple "" $description {
+ -re "Thread .* (received signal SIGINT|stopped).*$gdb_prompt $" {
+ pass $description
}
}
}
diff --git a/gdb/testsuite/gdb.threads/sigthread.exp b/gdb/testsuite/gdb.threads/sigthread.exp
index 867aef9a710..43f39406380 100644
--- a/gdb/testsuite/gdb.threads/sigthread.exp
+++ b/gdb/testsuite/gdb.threads/sigthread.exp
@@ -49,4 +49,4 @@ after 500 {send_gdb "\003"}
# Make sure we do not get an internal error from hitting Control-C
# while many signals are flying back and forth.
-gdb_test "" "Thread .* received signal SIGINT.*" "stop with control-c"
+gdb_test "" "Thread .* (received signal SIGINT|stopped).*" "stop with control-c"
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index d8c684c7238..5aeebb3704b 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -2870,6 +2870,25 @@ gdb_caching_proc supports_memtag {
return 0
}
+# Return true if the target is able to interrupt a program that blocks
+# SIGINT.
+proc can_interrupt_blocked_sigint {} {
+ if {[istarget *-*-linux*]} {
+ gdb_test_multiple "maint show target-non-stop" "" {
+ -re "(is|currently) on.*$::gdb_prompt $" {
+ }
+ -re "(is|currently) off.*$::gdb_prompt $" {
+ # GDBserver still tries to interrupt programs with
+ # SIGINT.
+ return 0
+ }
+ }
+ }
+
+ # Assume possible.
+ return 1
+}
+
# Return 1 if the target supports hardware single stepping.
proc can_hardware_single_step {} {
--
2.26.2
next prev parent reply other threads:[~2021-06-14 21:28 UTC|newest]
Thread overview: 34+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-06-14 21:23 [PATCH v2 00/16] Interrupting programs that block/ignore SIGINT Pedro Alves
2021-06-14 21:23 ` [PATCH v2 01/16] Test interrupting programs that block SIGINT [gdb/9425, gdb/14559] Pedro Alves
2021-06-14 21:23 ` [PATCH v2 02/16] prefork_hook: Remove 'args' parameter Pedro Alves
2021-06-14 21:23 ` [PATCH v2 03/16] Make gdb.base/long-inferior-output.exp fail fast Pedro Alves
2021-06-14 21:23 ` [PATCH v2 04/16] Fix gdb.multi/multi-term-settings.exp race Pedro Alves
2021-06-14 21:23 ` [PATCH v2 05/16] Don't check parent pid in gdb.threads/{ia64-sigill, siginfo-threads, watchthreads-reorder}.c Pedro Alves
2021-06-14 21:24 ` [PATCH v2 06/16] Special-case "set inferior-tty /dev/tty" Pedro Alves
2021-06-14 21:24 ` [PATCH v2 07/16] Make inferior/GDB share terminal in tests expecting output after detach Pedro Alves
2021-06-14 21:24 ` [PATCH v2 08/16] Make inferior/GDB share terminal in tests that exercise GDB/inferior reading same input Pedro Alves
2021-06-14 21:24 ` [PATCH v2 09/16] gdb.mi/mi-logging.exp, don't send input to GDB while the inferior is running Pedro Alves
2021-06-14 21:24 ` [PATCH v2 10/16] target_terminal::ours_for_output before printing signal received Pedro Alves
2021-06-14 21:24 ` [PATCH v2 11/16] Move scoped_ignore_sigttou to gdbsupport/ Pedro Alves
2021-06-17 21:49 ` Pedro Alves
2021-06-14 21:24 ` [PATCH v2 12/16] Always put inferiors in their own terminal/session [gdb/9425, gdb/14559] Pedro Alves
2021-06-14 21:24 ` [PATCH v2 13/16] exists_non_stop_target: Avoid flushing frames Pedro Alves
2021-06-14 21:24 ` [PATCH v2 14/16] convert previous_inferior_ptid to strong reference to thread_info Pedro Alves
2021-06-14 21:24 ` Pedro Alves [this message]
2021-07-08 23:05 ` [PATCH v2 15/16] GNU/Linux: Interrupt/Ctrl-C with SIGSTOP instead of SIGINT [PR gdb/9425, PR gdb/14559] Maciej W. Rozycki
2021-07-13 15:26 ` Pedro Alves
2021-06-14 21:24 ` [PATCH v2 16/16] Document pseudo-terminal and interrupting changes Pedro Alves
2021-06-15 12:56 ` Eli Zaretskii via Gdb-patches
2021-06-16 9:31 ` Pedro Alves
2021-06-16 12:29 ` Eli Zaretskii via Gdb-patches
2021-06-16 10:15 ` Pedro Alves
2021-06-16 12:15 ` Eli Zaretskii via Gdb-patches
2021-06-16 12:26 ` Pedro Alves
2021-06-16 13:05 ` Eli Zaretskii via Gdb-patches
2021-06-15 12:34 ` [PATCH v2 00/16] Interrupting programs that block/ignore SIGINT Eli Zaretskii via Gdb-patches
2021-06-16 11:27 ` Pedro Alves
2021-06-16 12:45 ` Eli Zaretskii via Gdb-patches
2021-06-18 10:12 ` Andrew Burgess
2021-06-24 18:12 ` Konstantin Kharlamov via Gdb-patches
2021-06-24 18:55 ` Pedro Alves
2021-06-29 1:15 ` Eldar Abusalimov via Gdb-patches
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20210614212410.1612666-16-pedro@palves.net \
--to=pedro@palves.net \
--cc=gdb-patches@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox