Letting a "checkpoint" run to exit with "set non-stop on" behaves
differently compared to the default all-stop mode ("set non-stop
off").
Currently, in non-stop mode:
(gdb) start
Temporary breakpoint 1 at 0x40086b: file src/gdb/testsuite/gdb.base/checkpoint.c, line 28.
Starting program: build/gdb/testsuite/gdb.base/checkpoint
Temporary breakpoint 1, main () at src/gdb/testsuite/gdb.base/checkpoint.c:28
28 char *tmp = &linebuf[0];
(gdb) checkpoint
checkpoint 1: fork returned pid 24948.
(gdb) c
Continuing.
Copy complete.
Deleting copy.
[Inferior 1 (process 24944) exited normally]
[Switching to process 24948]
(gdb) info threads
Id Target Id Frame
1 process 24948 "checkpoint" (running)
No selected thread. See `help thread'.
(gdb) c
The program is not being run.
(gdb)
Two issues above:
1. Thread 1 got stuck in "(running)" state (it isn't really running)
2. While checkpoints try to preserve the illusion that the thread is
still the same when the process exits, GDB switched to "No thread
selected." instead of staying with thread 1 selected.
Problem #1 is caused by handle_inferior_event and normal_stop not
considering that when a
TARGET_WAITKIND_SIGNALLED/TARGET_WAITKIND_EXITED event is reported,
and the inferior is mourned, the target may still have execution.
Problem #2 is caused by the make_cleanup_restore_current_thread
cleanup installed by fetch_inferior_event not being able to find the
original thread 1's ptid in the thread list, thus not being able to
restore thread 1 as selected thread. The fix is to make the cleanup
installed by make_cleanup_restore_current_thread aware of thread ptid
changes, by installing a thread_ptid_changed observer that adjusts the
cleanup's data.
After the patch, we get the same in all-stop and non-stop modes:
(gdb) c
Continuing.
Copy complete.
Deleting copy.
[Inferior 1 (process 25109) exited normally]
[Switching to process 25113]
(gdb) info threads
Id Target Id Frame
* 1 process 25113 "checkpoint" main () at src/gdb/testsuite/gdb.base/checkpoint.c:28
(gdb)
Turns out the whole checkpoints.exp file can run in non-stop mode
unmodified. I thought of moving most of the test file's contents to a
procedure that can be called twice, once in non-stop mode and another
in all-stop mode. But then, the test already takes close to 30
seconds to run on my machine, so I thought it'd be nicer to run
all-stop and non-stop mode in parallel. Thus I added a new
checkpoint-ns.exp file that just appends "set non-stop on" to GDBFLAGS
and sources checkpoint.exp.
gdb/ChangeLog:
2015-08-07 Pedro Alves <palves@redhat.com>
* infrun.c (handle_inferior_event): If we get
TARGET_WAITKIND_SIGNALLED or TARGET_WAITKIND_EXITED in non-stop
mode, mark all threads of the exiting process as not-executing.
(normal_stop): If we get TARGET_WAITKIND_SIGNALLED or
TARGET_WAITKIND_EXITED in non-stop mode, finish all threads of the
exiting process, if inferior_ptid still points at a process.
* thread.c (struct current_thread_cleanup) <next>: New field.
(current_thread_cleanup_chain): New global.
(restore_current_thread_ptid_changed): New function.
(restore_current_thread_cleanup_dtor): Remove the cleanup from the
current_thread_cleanup_chain list.
(make_cleanup_restore_current_thread): Add the cleanup data to the
current_thread_cleanup_chain list.
(_initialize_thread): Install restore_current_thread_ptid_changed
as thread_ptid_changed observer.
gdb/testsuite/ChangeLog:
2015-08-07 Pedro Alves <palves@redhat.com>
* gdb.base/checkpoint-ns.exp: New file.
* gdb.base/checkpoint.exp: Pass explicit "checkpoint.c" to
standard_testfile.