}
}
+/* 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
break;
}
+ stop_all_threads_if_all_stop_mode ();
+
/* No error, don't finish the state yet. */
finish_state.release ();
}
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)
/* 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
--- /dev/null
+/* 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;
+}
--- /dev/null
+# 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}
+ }
+}