forked from Imagelibrary/binutils-gdb
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
85 lines
1.7 KiB
C
85 lines
1.7 KiB
C
/* 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 <sys/types.h>
|
|
#include <sys/wait.h>
|
|
#include <errno.h>
|
|
#include <assert.h>
|
|
#include <limits.h>
|
|
|
|
/* Set by GDB. */
|
|
volatile int stop_looping = 0;
|
|
|
|
static void *
|
|
gdb_forker_thread (void *arg)
|
|
{
|
|
int ret;
|
|
int stat;
|
|
pid_t pid = FORK_FUNC ();
|
|
|
|
if (pid == 0)
|
|
_exit (0);
|
|
|
|
assert (pid > 0);
|
|
|
|
/* Wait for child to exit. */
|
|
do
|
|
{
|
|
ret = waitpid (pid, &stat, 0);
|
|
}
|
|
while (ret == -1 && errno == EINTR);
|
|
|
|
assert (ret == pid);
|
|
assert (WIFEXITED (stat));
|
|
assert (WEXITSTATUS (stat) == 0);
|
|
|
|
stop_looping = 1;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
sleep_a_bit (void)
|
|
{
|
|
usleep (1000 * 50);
|
|
}
|
|
|
|
int
|
|
main (void)
|
|
{
|
|
int i;
|
|
int ret;
|
|
pthread_t thread;
|
|
|
|
alarm (60);
|
|
|
|
ret = pthread_create (&thread, NULL, gdb_forker_thread, NULL);
|
|
assert (ret == 0);
|
|
|
|
while (!stop_looping) /* while loop */
|
|
{
|
|
sleep_a_bit (); /* break here */
|
|
sleep_a_bit (); /* other line */
|
|
}
|
|
|
|
pthread_join (thread, NULL);
|
|
|
|
return 0; /* exiting here */
|
|
}
|