all-stop "follow-fork parent" and selecting another thread
authorPedro Alves <pedro@palves.net>
Fri, 25 Nov 2022 16:20:22 +0000 (16:20 +0000)
committerPedro Alves <pedro@palves.net>
Mon, 27 Feb 2023 19:12:28 +0000 (19:12 +0000)
commitbd9482bca71e7bf4149a319a95d6fec4589c3758
treeab45f8aa5885c319be238dcafa292cf917d96b28
parent3505d4c4f7e2156837c7bfcbecf0a03b202e7ffb
all-stop "follow-fork parent" and selecting another thread

With:

 - catch a fork in thread 1
 - select thread 2
 - set follow-fork child
 - next

... follow_fork notices that thread 1 had last stopped for a fork
which hasn't been followed yet, and because thread 1 is not the
current thread, GDB aborts the execution command, presenting the stop
in thread 1.

That makes sense, as only the forking thread (thread 1) survives in
the child, so better stop and let the user decide how to proceed.

However, with:

 - catch a fork in thread 1
 - select thread 2
 - set follow-fork parent << note difference here
 - next

... GDB does the same: follow_fork notices that thread 1 had last
stopped for a fork which hasn't been followed yet, and because thread
1 is not the current thread, GDB aborts the execution command,
presenting the stop in thread 1.

Aborting/stopping in this case doesn't make sense to me.  As we're
following the parent, thread 2 will still continue to exist in the
parent.  What the child does after we've followed the parent shouldn't
matter -- it can go on running free, be detached, etc., depending on
"set schedule-multiple", "set detach-on-fork", etc.  That does not
influence the execution command that the user issued for the parent
thread.

So this patch changes GDB in that direction -- in follow_fork, if
following the parent, and we've switched threads meanwhile, switch
back to the unfollowed thread, follow it (stay with the parent), and
don't abort/stop.  If we're following a fork (as opposed to vfork),
then switch back again to the thread that the user was trying to
resume.  If following a vfork, however, stay with the vforking-thread
selected, as we will need to see a vfork_done event first, before we
can resume any other thread.

As I was working on this, I managed to end up calling target_resume
for a solo-thread resume (to collect the vfork_done event), with
scope_ptid pointing at the vfork parent thread, and inferior_ptid
pointing to the vfork child.  For a solo-thread resume, the scope_ptid
argument to target_resume must the same as inferior_ptid.  The mistake
was caught by the assertion in target_resume, like so:

...
  [infrun] resume_1: step=0, signal=GDB_SIGNAL_0, trap_expected=0, current thread [1722839.1722839.0] at 0x5555555553c3
  [infrun] do_target_resume: resume_ptid=1722839.1722939.0, step=0, sig=GDB_SIGNAL_0
../../src/gdb/target.c:2661: internal-error: target_resume: Assertion `inferior_ptid.matches (scope_ptid)' failed.
...

but I think it doesn't hurt to catch such a mistake earlier, hence the
change in internal_resume_ptid.

Change-Id: I896705506a16d2488b1bfb4736315dd966f4e412
gdb/infrun.c
gdb/testsuite/gdb.threads/foll-fork-other-thread.c [new file with mode: 0644]
gdb/testsuite/gdb.threads/foll-fork-other-thread.exp [new file with mode: 0644]