gdb/remote.c: refactor pending fork status functions

In preparation for a following patch, refactor a few things that I did
find a bit awkward, and to make them a bit more reusable.

 - Pass an inferior to kill_new_fork_children instead of a pid.  That
   allows iterating on only this inferior's threads and avoid further
   filtering on the thread's pid.
 - Change thread_pending_fork_status to return a non-nullptr value only
   if the thread does have a pending fork status.
 - Remove is_pending_fork_parent_thread, as one can just use
   thread_pending_fork_status and check for nullptr.
 - Replace is_pending_fork_parent with is_fork_status, which just
   returns if the given target_waitkind if a fork or a vfork.  Push
   filtering on the pid to the callers, when it is necessary.

Change-Id: I0764ccc684d40f054e39df6fa5458cc4c5d1cd7b
This commit is contained in:
Simon Marchi 2021-12-01 09:40:02 -05:00
parent a4543480c5
commit 28561a6559

View file

@ -776,7 +776,7 @@ public: /* Remote specific methods. */
void remote_btrace_maybe_reopen (); void remote_btrace_maybe_reopen ();
void remove_new_fork_children (threads_listing_context *context); void remove_new_fork_children (threads_listing_context *context);
void kill_new_fork_children (int pid); void kill_new_fork_children (inferior *inf);
void discard_pending_stop_replies (struct inferior *inf); void discard_pending_stop_replies (struct inferior *inf);
int stop_reply_queue_length (); int stop_reply_queue_length ();
@ -5876,45 +5876,30 @@ remote_target::open_1 (const char *name, int from_tty, int extended_p)
rs->wait_forever_enabled_p = 1; rs->wait_forever_enabled_p = 1;
} }
/* Determine if THREAD_PTID is a pending fork parent thread. ARG contains /* Determine if WS represents a fork status. */
the pid of the process that owns the threads we want to check, or
-1 if we want to check all threads. */
static int static bool
is_pending_fork_parent (const target_waitstatus &ws, int event_pid, is_fork_status (target_waitkind kind)
ptid_t thread_ptid)
{ {
if (ws.kind () == TARGET_WAITKIND_FORKED return (kind == TARGET_WAITKIND_FORKED
|| ws.kind () == TARGET_WAITKIND_VFORKED) || kind == TARGET_WAITKIND_VFORKED);
{
if (event_pid == -1 || event_pid == thread_ptid.pid ())
return 1;
}
return 0;
} }
/* Return the thread's pending status used to determine whether the /* Return THREAD's pending status if it is a pending fork parent, else
thread is a fork parent stopped at a fork event. */ return nullptr. */
static const target_waitstatus & static const target_waitstatus *
thread_pending_fork_status (struct thread_info *thread) thread_pending_fork_status (struct thread_info *thread)
{ {
if (thread->has_pending_waitstatus ()) const target_waitstatus &ws
return thread->pending_waitstatus (); = (thread->has_pending_waitstatus ()
else ? thread->pending_waitstatus ()
return thread->pending_follow; : thread->pending_follow);
}
/* Determine if THREAD is a pending fork parent thread. */ if (!is_fork_status (ws.kind ()))
return nullptr;
static int return &ws;
is_pending_fork_parent_thread (struct thread_info *thread)
{
const target_waitstatus &ws = thread_pending_fork_status (thread);
int pid = -1;
return is_pending_fork_parent (ws, pid, thread->ptid);
} }
/* Detach the specified process. */ /* Detach the specified process. */
@ -6828,7 +6813,7 @@ remote_target::commit_resumed ()
/* If a thread is the parent of an unfollowed fork, then we /* If a thread is the parent of an unfollowed fork, then we
can't do a global wildcard, as that would resume the fork can't do a global wildcard, as that would resume the fork
child. */ child. */
if (is_pending_fork_parent_thread (tp)) if (thread_pending_fork_status (tp) != nullptr)
may_global_wildcard_vcont = false; may_global_wildcard_vcont = false;
} }
@ -7303,17 +7288,18 @@ struct notif_client notif_client_stop =
void void
remote_target::remove_new_fork_children (threads_listing_context *context) remote_target::remove_new_fork_children (threads_listing_context *context)
{ {
int pid = -1;
struct notif_client *notif = &notif_client_stop; struct notif_client *notif = &notif_client_stop;
/* For any threads stopped at a fork event, remove the corresponding /* For any threads stopped at a fork event, remove the corresponding
fork child threads from the CONTEXT list. */ fork child threads from the CONTEXT list. */
for (thread_info *thread : all_non_exited_threads (this)) for (thread_info *thread : all_non_exited_threads (this))
{ {
const target_waitstatus &ws = thread_pending_fork_status (thread); const target_waitstatus *ws = thread_pending_fork_status (thread);
if (is_pending_fork_parent (ws, pid, thread->ptid)) if (ws == nullptr)
context->remove_thread (ws.child_ptid ()); continue;
context->remove_thread (ws->child_ptid ());
} }
/* Check for any pending fork events (not reported or processed yet) /* Check for any pending fork events (not reported or processed yet)
@ -10066,45 +10052,48 @@ remote_target::getpkt_or_notif_sane (gdb::char_vector *buf, int forever,
return getpkt_or_notif_sane_1 (buf, forever, 1, is_notif); return getpkt_or_notif_sane_1 (buf, forever, 1, is_notif);
} }
/* Kill any new fork children of process PID that haven't been /* Kill any new fork children of inferior INF that haven't been
processed by follow_fork. */ processed by follow_fork. */
void void
remote_target::kill_new_fork_children (int pid) remote_target::kill_new_fork_children (inferior *inf)
{ {
remote_state *rs = get_remote_state (); remote_state *rs = get_remote_state ();
struct notif_client *notif = &notif_client_stop; struct notif_client *notif = &notif_client_stop;
/* Kill the fork child threads of any threads in process PID /* Kill the fork child threads of any threads in inferior INF that are stopped
that are stopped at a fork event. */ at a fork event. */
for (thread_info *thread : all_non_exited_threads (this)) for (thread_info *thread : inf->non_exited_threads ())
{ {
const target_waitstatus &ws = thread->pending_follow; const target_waitstatus *ws = thread_pending_fork_status (thread);
if (is_pending_fork_parent (ws, pid, thread->ptid)) if (ws == nullptr)
{ continue;
int child_pid = ws.child_ptid ().pid ();
int res;
res = remote_vkill (child_pid); int child_pid = ws->child_ptid ().pid ();
if (res != 0) int res = remote_vkill (child_pid);
error (_("Can't kill fork child process %d"), child_pid);
} if (res != 0)
error (_("Can't kill fork child process %d"), child_pid);
} }
/* Check for any pending fork events (not reported or processed yet) /* Check for any pending fork events (not reported or processed yet)
in process PID and kill those fork child threads as well. */ in inferior INF and kill those fork child threads as well. */
remote_notif_get_pending_events (notif); remote_notif_get_pending_events (notif);
for (auto &event : rs->stop_reply_queue) for (auto &event : rs->stop_reply_queue)
if (is_pending_fork_parent (event->ws, pid, event->ptid)) {
{ if (event->ptid.pid () != inf->pid)
int child_pid = event->ws.child_ptid ().pid (); continue;
int res;
res = remote_vkill (child_pid); if (!is_fork_status (event->ws.kind ()))
if (res != 0) continue;
error (_("Can't kill fork child process %d"), child_pid);
} int child_pid = event->ws.child_ptid ().pid ();
int res = remote_vkill (child_pid);
if (res != 0)
error (_("Can't kill fork child process %d"), child_pid);
}
} }
@ -10114,18 +10103,20 @@ void
remote_target::kill () remote_target::kill ()
{ {
int res = -1; int res = -1;
int pid = inferior_ptid.pid (); inferior *inf = find_inferior_pid (this, inferior_ptid.pid ());
struct remote_state *rs = get_remote_state (); struct remote_state *rs = get_remote_state ();
gdb_assert (inf != nullptr);
if (packet_support (PACKET_vKill) != PACKET_DISABLE) if (packet_support (PACKET_vKill) != PACKET_DISABLE)
{ {
/* If we're stopped while forking and we haven't followed yet, /* If we're stopped while forking and we haven't followed yet,
kill the child task. We need to do this before killing the kill the child task. We need to do this before killing the
parent task because if this is a vfork then the parent will parent task because if this is a vfork then the parent will
be sleeping. */ be sleeping. */
kill_new_fork_children (pid); kill_new_fork_children (inf);
res = remote_vkill (pid); res = remote_vkill (inf->pid);
if (res == 0) if (res == 0)
{ {
target_mourn_inferior (inferior_ptid); target_mourn_inferior (inferior_ptid);