@@ -3796,8 +3796,18 @@ handle_inferior_event (struct execution_control_state *ecs)
any other process were left running. */
if (!non_stop)
set_executing (minus_one_ptid, 0);
- else if (ecs->ws.kind != TARGET_WAITKIND_SIGNALLED
- && ecs->ws.kind != TARGET_WAITKIND_EXITED)
+ else if (ecs->ws.kind == TARGET_WAITKIND_SIGNALLED
+ && ecs->ws.kind == TARGET_WAITKIND_EXITED)
+ {
+ ptid_t pid_ptid;
+
+ /* Some targets still have execution when a process exits.
+ E.g., for "checkpoint", when when a fork exits and is
+ mourned, linux-fork.c switches to another fork. */
+ pid_ptid = pid_to_ptid (ptid_get_pid (ecs->ptid));
+ set_executing (pid_ptid, 0);
+ }
+ else
set_executing (ecs->ptid, 0);
switch (ecs->ws.kind)
@@ -6536,6 +6546,7 @@ normal_stop (void)
struct target_waitstatus last;
ptid_t last_ptid;
struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
+ ptid_t pid_ptid;
get_last_target_status (&last_ptid, &last);
@@ -6545,9 +6556,19 @@ normal_stop (void)
here, so do this before any filtered output. */
if (!non_stop)
make_cleanup (finish_thread_state_cleanup, &minus_one_ptid);
- else if (last.kind != TARGET_WAITKIND_SIGNALLED
- && last.kind != TARGET_WAITKIND_EXITED
- && last.kind != TARGET_WAITKIND_NO_RESUMED)
+ else if (last.kind == TARGET_WAITKIND_SIGNALLED
+ || last.kind == TARGET_WAITKIND_EXITED)
+ {
+ /* Some targets still have execution when a process exits.
+ E.g., for "checkpoint", when when a fork exits and is
+ mourned, linux-fork.c switches to another fork. */
+ if (!ptid_equal (inferior_ptid, null_ptid))
+ {
+ pid_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
+ make_cleanup (finish_thread_state_cleanup, &pid_ptid);
+ }
+ }
+ else if (last.kind != TARGET_WAITKIND_NO_RESUMED)
make_cleanup (finish_thread_state_cleanup, &inferior_ptid);
/* As we're presenting a stop, and potentially removing breakpoints,
new file mode 100644
@@ -0,0 +1,27 @@
+# Copyright 2015 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 gdb checkpoint and restart in non-stop mode.
+
+# We drive non-stop mode from a separate file because the whole test
+# takes a while to run. This way, we can test both modes in parallel.
+
+# checkpoint.exp reads this variable.
+set checkpoint_non_stop 1
+
+source $srcdir/$subdir/checkpoint.exp
+
+# Unset to avoid problems with non-parallel mode.
+unset checkpoint_non_stop
@@ -13,6 +13,20 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. */
+#
+# This tests gdb checkpoint and restart.
+#
+
+# Note this file is also sourced by checkpoint-ns.exp to run all the
+# tests below in non-stop mode. That's driven by a separate file so
+# testing both all-stop and non-stop can be done in parallel.
+
+# This is the variable checkpoint-ns.exp sets to request non-stop
+# mode. When not set, default to all-stop mode.
+if {![info exists checkpoint_non_stop]} {
+ set checkpoint_non_stop 0
+}
+
if { [is_remote target] || ![isnative] } then {
continue
}
@@ -24,8 +38,10 @@ if {![istarget "*-*-linux*"]} then {
continue
}
-
-standard_testfile .c
+# Must name the source file explicitly, otherwise when driven by
+# checkpoints-ns.exp, we'd try compiling checkpoints-ns.c, which
+# doesn't exist.
+standard_testfile checkpoint.c
set pi_txt [gdb_remote_download host ${srcdir}/${subdir}/pi.txt]
if {[is_remote host]} {
@@ -42,9 +58,9 @@ if {[prepare_for_testing ${testfile}.exp $testfile $srcfile \
global gdb_prompt
-#
-# This tests gdb checkpoint and restart.
-#
+if {$checkpoint_non_stop} {
+ gdb_test_no_output "set non-stop on"
+}
runto_main
set break1_loc [gdb_get_line_number "breakpoint 1"]
@@ -327,6 +343,11 @@ gdb_start
gdb_reinitialize_dir $srcdir/$subdir
gdb_load ${binfile}
+if {$checkpoint_non_stop} {
+ gdb_test_no_output "set non-stop on" \
+ "set non-stop on, for many checkpoints"
+}
+
runto_main
gdb_breakpoint $break1_loc
@@ -1266,8 +1266,16 @@ restore_selected_frame (struct frame_id a_frame_id, int frame_level)
}
}
+/* Data used by the cleanup installed by
+ 'make_cleanup_restore_current_thread'. */
+
struct current_thread_cleanup
{
+ /* Next in list of currently installed 'struct
+ current_thread_cleanup' cleanups. See
+ 'current_thread_cleanup_chain' below. */
+ struct current_thread_cleanup *next;
+
ptid_t inferior_ptid;
struct frame_id selected_frame_id;
int selected_frame_level;
@@ -1276,6 +1284,29 @@ struct current_thread_cleanup
int was_removable;
};
+/* A chain of currently installed 'struct current_thread_cleanup'
+ cleanups. Restoring the previously selected thread looks up the
+ old thread in the thread list by ptid. If the thread changes ptid,
+ we need to update the cleanup's thread structure so the look up
+ succeeds. */
+static struct current_thread_cleanup *current_thread_cleanup_chain;
+
+/* A thread_ptid_changed observer. Update all currently installed
+ current_thread_cleanup cleanups that want to switch back to
+ OLD_PTID to switch back to NEW_PTID instead. */
+
+static void
+restore_current_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid)
+{
+ struct current_thread_cleanup *it;
+
+ for (it = current_thread_cleanup_chain; it != NULL; it = it->next)
+ {
+ if (ptid_equal (it->inferior_ptid, old_ptid))
+ it->inferior_ptid = new_ptid;
+ }
+}
+
static void
do_restore_current_thread_cleanup (void *arg)
{
@@ -1316,6 +1347,8 @@ restore_current_thread_cleanup_dtor (void *arg)
struct thread_info *tp;
struct inferior *inf;
+ current_thread_cleanup_chain = current_thread_cleanup_chain->next;
+
tp = find_thread_ptid (old->inferior_ptid);
if (tp)
tp->refcount--;
@@ -1349,6 +1382,9 @@ make_cleanup_restore_current_thread (void)
old->inf_id = current_inferior ()->num;
old->was_removable = current_inferior ()->removable;
+ old->next = current_thread_cleanup_chain;
+ current_thread_cleanup_chain = old;
+
if (!ptid_equal (inferior_ptid, null_ptid))
{
old->was_stopped = is_stopped (inferior_ptid);
@@ -1803,4 +1839,6 @@ Show printing of thread events (such as thread start and exit)."), NULL,
&setprintlist, &showprintlist);
create_internalvar_type_lazy ("_thread", &thread_funcs, NULL);
+
+ observer_attach_thread_ptid_changed (restore_current_thread_ptid_changed);
}