C++ify fork_info, use std::list

- Convert new_fork and free_fork to fork_info ctor/dtor.
- Use std::list.

gdb/ChangeLog:
2019-03-06  Pedro Alves  <palves@redhat.com>

	* linux-fork.c: Include <list>.
	(fork_list): Now a std::list instance.
	(fork_info): Add ctor, dtor, and in-class initialize all fields.
	(forks_exist_p, find_last_fork): Adjust.
	(new_fork): Delete.
	(one_fork_p): New.
	(add_fork): Adjust.
	(free_fork): Delete, folded into fork_info::~fork_info().
	(delete_fork, find_fork_ptid, find_fork_id, find_fork_pid):
	Adjust.
	(init_fork_list): Delete.
	(linux_fork_killall, linux_fork_mourn_inferior)
	(linux_fork_detach, info_checkpoints_command): Adjust.
	(_initialize_linux_fork): No longer call init_fork_list.
This commit is contained in:
Pedro Alves 2019-03-06 18:29:18 +00:00
parent 72f31aea9e
commit 06974e6c05
2 changed files with 125 additions and 153 deletions

View File

@ -1,3 +1,20 @@
2019-03-06 Pedro Alves <palves@redhat.com>
* linux-fork.c: Include <list>.
(fork_list): Now a std::list instance.
(fork_info): Add ctor, dtor, and in-class initialize all fields.
(forks_exist_p, find_last_fork): Adjust.
(new_fork): Delete.
(one_fork_p): New.
(add_fork): Adjust.
(free_fork): Delete, folded into fork_info::~fork_info().
(delete_fork, find_fork_ptid, find_fork_id, find_fork_pid):
Adjust.
(init_fork_list): Delete.
(linux_fork_killall, linux_fork_mourn_inferior)
(linux_fork_detach, info_checkpoints_command): Adjust.
(_initialize_linux_fork): No longer call init_fork_list.
2019-03-06 Pedro Alves <palves@redhat.com>
* linux-fork.c (new_fork): New, split out of ...

View File

@ -35,30 +35,66 @@
#include <dirent.h>
#include <ctype.h>
struct fork_info *fork_list;
static int highest_fork_num;
#include <list>
/* Fork list data structure: */
struct fork_info
{
struct fork_info *next;
ptid_t ptid;
ptid_t parent_ptid;
int num; /* Convenient handle (GDB fork id). */
readonly_detached_regcache *savedregs; /* Convenient for info fork, saves
having to actually switch contexts. */
CORE_ADDR pc;
int clobber_regs; /* True if we should restore saved regs. */
off_t *filepos; /* Set of open file descriptors' offsets. */
int maxfd;
explicit fork_info (pid_t pid)
: ptid (pid, pid, 0)
{
}
~fork_info ()
{
/* Notes on step-resume breakpoints: since this is a concern for
threads, let's convince ourselves that it's not a concern for
forks. There are two ways for a fork_info to be created.
First, by the checkpoint command, in which case we're at a gdb
prompt and there can't be any step-resume breakpoint. Second,
by a fork in the user program, in which case we *may* have
stepped into the fork call, but regardless of whether we follow
the parent or the child, we will return to the same place and
the step-resume breakpoint, if any, will take care of itself as
usual. And unlike threads, we do not save a private copy of
the step-resume breakpoint -- so we're OK. */
if (savedregs)
delete savedregs;
if (filepos)
xfree (filepos);
}
ptid_t ptid = null_ptid;
ptid_t parent_ptid = null_ptid;
/* Convenient handle (GDB fork id). */
int num = 0;
/* Convenient for info fork, saves having to actually switch
contexts. */
readonly_detached_regcache *savedregs = nullptr;
CORE_ADDR pc = 0;
/* True if we should restore saved regs. */
int clobber_regs = 0;
/* Set of open file descriptors' offsets. */
off_t *filepos = nullptr;
int maxfd = 0;
};
static std::list<fork_info> fork_list;
static int highest_fork_num;
/* Fork list methods: */
int
forks_exist_p (void)
{
return (fork_list != NULL);
return !fork_list.empty ();
}
/* Return the last fork in the list. */
@ -66,26 +102,19 @@ forks_exist_p (void)
static struct fork_info *
find_last_fork (void)
{
struct fork_info *last;
if (fork_list == NULL)
if (fork_list.empty ())
return NULL;
for (last = fork_list; last->next != NULL; last = last->next)
;
return last;
return &fork_list.back ();
}
/* Allocate a new fork. */
/* Return true iff there's one fork in the list. */
static struct fork_info *
new_fork (pid_t pid)
static bool
one_fork_p ()
{
struct fork_info *fp;
fp = XCNEW (struct fork_info);
fp->ptid = ptid_t (pid, pid, 0);
return fp;
return (!fork_list.empty ()
&& &fork_list.front () == &fork_list.back ());
}
/* Add a new fork to the internal fork list. */
@ -93,93 +122,46 @@ new_fork (pid_t pid)
void
add_fork (pid_t pid)
{
struct fork_info *fp = new_fork (pid);
fork_list.emplace_back (pid);
if (fork_list == NULL)
{
fork_list = fp;
highest_fork_num = 0;
}
else
{
struct fork_info *last = find_last_fork ();
last->next = fp;
}
if (one_fork_p ())
highest_fork_num = 0;
fork_info *fp = &fork_list.back ();
fp->num = ++highest_fork_num;
}
static void
free_fork (struct fork_info *fp)
{
/* Notes on step-resume breakpoints: since this is a concern for
threads, let's convince ourselves that it's not a concern for
forks. There are two ways for a fork_info to be created. First,
by the checkpoint command, in which case we're at a gdb prompt
and there can't be any step-resume breakpoint. Second, by a fork
in the user program, in which case we *may* have stepped into the
fork call, but regardless of whether we follow the parent or the
child, we will return to the same place and the step-resume
breakpoint, if any, will take care of itself as usual. And
unlike threads, we do not save a private copy of the step-resume
breakpoint -- so we're OK. */
if (fp)
{
if (fp->savedregs)
delete fp->savedregs;
if (fp->filepos)
xfree (fp->filepos);
xfree (fp);
}
}
static void
delete_fork (ptid_t ptid)
{
struct fork_info *fp, *fpprev;
fpprev = NULL;
linux_target->low_forget_process (ptid.pid ());
for (fp = fork_list; fp; fpprev = fp, fp = fp->next)
if (fp->ptid == ptid)
break;
for (auto it = fork_list.begin (); it != fork_list.end (); ++it)
if (it->ptid == ptid)
{
fork_list.erase (it);
if (!fp)
return;
if (fpprev)
fpprev->next = fp->next;
else
fork_list = fp->next;
free_fork (fp);
/* Special case: if there is now only one process in the list,
and if it is (hopefully!) the current inferior_ptid, then
remove it, leaving the list empty -- we're now down to the
default case of debugging a single process. */
if (fork_list != NULL && fork_list->next == NULL &&
fork_list->ptid == inferior_ptid)
{
/* Last fork -- delete from list and handle as solo process
(should be a safe recursion). */
delete_fork (inferior_ptid);
}
/* Special case: if there is now only one process in the list,
and if it is (hopefully!) the current inferior_ptid, then
remove it, leaving the list empty -- we're now down to the
default case of debugging a single process. */
if (one_fork_p () && fork_list.front ().ptid == inferior_ptid)
{
/* Last fork -- delete from list and handle as solo
process (should be a safe recursion). */
delete_fork (inferior_ptid);
}
return;
}
}
/* Find a fork_info by matching PTID. */
static struct fork_info *
find_fork_ptid (ptid_t ptid)
{
struct fork_info *fp;
for (fp = fork_list; fp; fp = fp->next)
if (fp->ptid == ptid)
return fp;
for (fork_info &fi : fork_list)
if (fi.ptid == ptid)
return &fi;
return NULL;
}
@ -188,11 +170,9 @@ find_fork_ptid (ptid_t ptid)
static struct fork_info *
find_fork_id (int num)
{
struct fork_info *fp;
for (fp = fork_list; fp; fp = fp->next)
if (fp->num == num)
return fp;
for (fork_info &fi : fork_list)
if (fi.num == num)
return &fi;
return NULL;
}
@ -201,11 +181,9 @@ find_fork_id (int num)
extern struct fork_info *
find_fork_pid (pid_t pid)
{
struct fork_info *fp;
for (fp = fork_list; fp; fp = fp->next)
if (pid == fp->ptid.pid ())
return fp;
for (fork_info &fi : fork_list)
if (pid == fi.ptid.pid ())
return &fi;
return NULL;
}
@ -220,23 +198,6 @@ fork_id_to_ptid (int num)
return ptid_t (-1);
}
static void
init_fork_list (void)
{
struct fork_info *fp, *fpnext;
if (!fork_list)
return;
for (fp = fork_list; fp; fp = fpnext)
{
fpnext = fp->next;
free_fork (fp);
}
fork_list = NULL;
}
/* Fork list <-> gdb interface. */
/* Utility function for fork_load/fork_save.
@ -350,13 +311,12 @@ linux_fork_killall (void)
status for it) -- however any process may be a child
or a parent, so may get a SIGCHLD from a previously
killed child. Wait them all out. */
struct fork_info *fp;
pid_t pid, ret;
int status;
for (fp = fork_list; fp; fp = fp->next)
for (fork_info &fi : fork_list)
{
pid = fp->ptid.pid ();
pid_t pid = fi.ptid.pid ();
int status;
pid_t ret;
do {
/* Use SIGKILL instead of PTRACE_KILL because the former works even
if the thread is running, while the later doesn't. */
@ -367,7 +327,9 @@ linux_fork_killall (void)
died. MVS comment cut-and-pasted from linux-nat. */
} while (ret == pid && WIFSTOPPED (status));
}
init_fork_list (); /* Clear list, prepare to start fresh. */
/* Clear list, prepare to start fresh. */
fork_list.clear ();
}
/* The current inferior_ptid has exited, but there are other viable
@ -394,7 +356,7 @@ linux_fork_mourn_inferior (void)
/* There should still be a fork - if there's only one left,
delete_fork won't remove it, because we haven't updated
inferior_ptid yet. */
gdb_assert (fork_list);
gdb_assert (!fork_list.empty ());
last = find_last_fork ();
fork_load_infrun_state (last);
@ -402,7 +364,7 @@ linux_fork_mourn_inferior (void)
target_pid_to_str (inferior_ptid));
/* If there's only one fork, switch back to non-fork mode. */
if (fork_list->next == NULL)
if (one_fork_p ())
delete_fork (inferior_ptid);
}
@ -425,16 +387,16 @@ linux_fork_detach (int from_tty)
/* There should still be a fork - if there's only one left,
delete_fork won't remove it, because we haven't updated
inferior_ptid yet. */
gdb_assert (fork_list);
gdb_assert (!fork_list.empty ());
fork_load_infrun_state (fork_list);
fork_load_infrun_state (&fork_list.front ());
if (from_tty)
printf_filtered (_("[Switching to %s]\n"),
target_pid_to_str (inferior_ptid));
/* If there's only one fork, switch back to non-fork mode. */
if (fork_list->next == NULL)
if (one_fork_p ())
delete_fork (inferior_ptid);
}
@ -606,34 +568,31 @@ static void
info_checkpoints_command (const char *arg, int from_tty)
{
struct gdbarch *gdbarch = get_current_arch ();
struct symtab_and_line sal;
struct fork_info *fp;
ULONGEST pc;
int requested = -1;
struct fork_info *printed = NULL;
const fork_info *printed = NULL;
if (arg && *arg)
requested = (int) parse_and_eval_long (arg);
for (fp = fork_list; fp; fp = fp->next)
for (const fork_info &fi : fork_list)
{
if (requested > 0 && fp->num != requested)
if (requested > 0 && fi.num != requested)
continue;
printed = fp;
if (fp->ptid == inferior_ptid)
printed = &fi;
if (fi.ptid == inferior_ptid)
printf_filtered ("* ");
else
printf_filtered (" ");
pc = fp->pc;
printf_filtered ("%d %s", fp->num, target_pid_to_str (fp->ptid));
if (fp->num == 0)
ULONGEST pc = fi.pc;
printf_filtered ("%d %s", fi.num, target_pid_to_str (fi.ptid));
if (fi.num == 0)
printf_filtered (_(" (main process)"));
printf_filtered (_(" at "));
fputs_filtered (paddress (gdbarch, pc), gdb_stdout);
sal = find_pc_line (pc, 0);
symtab_and_line sal = find_pc_line (pc, 0);
if (sal.symtab)
printf_filtered (_(", file %s"),
symtab_to_filename_for_display (sal.symtab));
@ -762,14 +721,12 @@ checkpoint_command (const char *args, int from_tty)
if (!fp)
error (_("Failed to find new fork"));
if (fork_list->next == NULL)
if (one_fork_p ())
{
/* Special case -- if this is the first fork in the list (the
list was hitherto empty), then add inferior_ptid first, as a
special zeroeth fork id. */
fork_info *first = new_fork (inferior_ptid.pid ());
first->next = fork_list;
fork_list = first;
fork_list.emplace_front (inferior_ptid.pid ());
}
fork_save_infrun_state (fp, 1);
@ -816,8 +773,6 @@ restart_command (const char *args, int from_tty)
void
_initialize_linux_fork (void)
{
init_fork_list ();
/* Checkpoint command: create a fork of the inferior process
and set it aside for later debugging. */