diff options
-rw-r--r-- | gdb/infrun.c | 19 | ||||
-rw-r--r-- | gdb/testsuite/gdb.threads/step-N-all-progress.c | 51 | ||||
-rw-r--r-- | gdb/testsuite/gdb.threads/step-N-all-progress.exp | 59 |
3 files changed, 124 insertions, 5 deletions
diff --git a/gdb/infrun.c b/gdb/infrun.c index a669423..a59cbe6 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -3971,6 +3971,16 @@ prepare_for_detach (void) } } +/* If all-stop, but there exists a non-stop target, stop all threads + now that we're presenting the stop to the user. */ + +static void +stop_all_threads_if_all_stop_mode () +{ + if (!non_stop && exists_non_stop_target ()) + stop_all_threads ("presenting stop to user in all-stop"); +} + /* Wait for control to return from inferior to debugger. If inferior gets a signal, we may decide to start it up again @@ -4017,6 +4027,8 @@ wait_for_inferior (inferior *inf) break; } + stop_all_threads_if_all_stop_mode (); + /* No error, don't finish the state yet. */ finish_state.release (); } @@ -4240,6 +4252,8 @@ fetch_inferior_event () bool should_notify_stop = true; int proceeded = 0; + stop_all_threads_if_all_stop_mode (); + clean_up_just_stopped_threads_fsms (ecs); if (thr != nullptr && thr->thread_fsm () != nullptr) @@ -8138,11 +8152,6 @@ stop_waiting (struct execution_control_state *ecs) /* Let callers know we don't want to wait for the inferior anymore. */ ecs->wait_some_more = 0; - - /* If all-stop, but there exists a non-stop target, stop all - threads now that we're presenting the stop to the user. */ - if (!non_stop && exists_non_stop_target ()) - stop_all_threads ("presenting stop to user in all-stop"); } /* Like keep_going, but passes the signal to the inferior, even if the diff --git a/gdb/testsuite/gdb.threads/step-N-all-progress.c b/gdb/testsuite/gdb.threads/step-N-all-progress.c new file mode 100644 index 0000000..8d3fbeb --- /dev/null +++ b/gdb/testsuite/gdb.threads/step-N-all-progress.c @@ -0,0 +1,51 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2022 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include <pthread.h> +#include <unistd.h> +#include <stddef.h> + +static pthread_barrier_t barrier; + +static void * +thread_func (void *arg) +{ + pthread_barrier_wait (&barrier); + return NULL; +} + +int +main () +{ + pthread_t thread; + int ret; + + alarm (30); + + pthread_barrier_init (&barrier, NULL, 2); + + /* We run to this line below, and then issue "next 3". That should + step over the 3 lines below and land on the return statement. If + GDB prematurely stops the thread_func thread after the first of + the 3 nexts (and never resumes it again), then the join won't + ever return. */ + pthread_create (&thread, NULL, thread_func, NULL); /* set break here */ + pthread_barrier_wait (&barrier); + pthread_join (thread, NULL); + + return 0; +} diff --git a/gdb/testsuite/gdb.threads/step-N-all-progress.exp b/gdb/testsuite/gdb.threads/step-N-all-progress.exp new file mode 100644 index 0000000..b1d1ba7 --- /dev/null +++ b/gdb/testsuite/gdb.threads/step-N-all-progress.exp @@ -0,0 +1,59 @@ +# Copyright 2022 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# Test that with "next N", all threads are resumed at each of the N +# steps. GDB used to have a bug where in target-non-stop targets, and +# in all-stop mode, after the first "next" (or "step/stepi/nexti"), +# GDB would prematurely stop all threads. For the subsequent N-1 +# steps, only the stepped thread would continue running, while all the +# other threads would remain stopped. + +standard_testfile + +if { [build_executable "failed to prepare" $testfile \ + $srcfile {debug pthreads}] == -1 } { + return +} + +proc test {non-stop target-non-stop} { + save_vars ::GDBFLAGS { + append ::GDBFLAGS " -ex \"maintenance set target-non-stop ${target-non-stop}\"" + append ::GDBFLAGS " -ex \"set non-stop ${non-stop}\"" + clean_restart $::binfile + } + + if { ![runto_main] } { + return + } + + set lineno [gdb_get_line_number "set break here"] + + gdb_breakpoint $lineno + + gdb_continue_to_breakpoint "break here" + + gdb_test "next 3" "return 0;" +} + +foreach_with_prefix non-stop {off on} { + foreach_with_prefix target-non-stop {off on} { + if {${non-stop} == "on" && ${target-non-stop} == "off"} { + # Invalid combination. + continue + } + + test ${non-stop} ${target-non-stop} + } +} |