[v2,1/8] fbsd-nat: Add a list of pending events.

Message ID 20230717192039.13976-2-jhb@FreeBSD.org
State New
Headers
Series Fixes for multiprocess for FreeBSD's native target |

Commit Message

John Baldwin July 17, 2023, 7:20 p.m. UTC
  The m_pending_events list stores a queue of deferred events that might
be reported by the next call to the target's wait method.  The set of
events that are eligible is filtered by the ptid passed to resume.

For now this just replaces the list of vfork_done events.  A
subsequent commit will reuse this to store other events.
---
 gdb/fbsd-nat.c | 128 ++++++++++++++++++++++++++++---------------------
 gdb/fbsd-nat.h |  45 +++++++++++++++++
 2 files changed, 118 insertions(+), 55 deletions(-)
  

Patch

diff --git a/gdb/fbsd-nat.c b/gdb/fbsd-nat.c
index b0ca8b00699..f9d8632c0ef 100644
--- a/gdb/fbsd-nat.c
+++ b/gdb/fbsd-nat.c
@@ -47,13 +47,47 @@ 
 #include "fbsd-nat.h"
 #include "fbsd-tdep.h"
 
-#include <list>
-
 #ifndef PT_GETREGSET
 #define	PT_GETREGSET	42	/* Get a target register set */
 #define	PT_SETREGSET	43	/* Set a target register set */
 #endif
 
+/* See fbsd-nat.h.  */
+
+void
+fbsd_nat_target::add_pending_event (const ptid_t &ptid,
+				    const target_waitstatus &status)
+{
+  gdb_assert (find_inferior_ptid (this, ptid) != nullptr);
+  m_pending_events.emplace_back (ptid, status);
+}
+
+/* See fbsd-nat.h.  */
+
+bool
+fbsd_nat_target::have_pending_event (ptid_t filter)
+{
+  for (const pending_event &event : m_pending_events)
+    if (event.ptid.matches (filter))
+      return true;
+  return false;
+}
+
+/* See fbsd-nat.h.  */
+
+gdb::optional<fbsd_nat_target::pending_event>
+fbsd_nat_target::take_pending_event ()
+{
+  for (auto it = m_pending_events.begin (); it != m_pending_events.end (); it++)
+    if (it->ptid.matches (m_resume_ptid))
+      {
+	pending_event event = *it;
+	m_pending_events.erase (it);
+	return event;
+      }
+  return {};
+}
+
 /* Return the name of a file that can be opened to get the symbols for
    the child process identified by PID.  */
 
@@ -1061,47 +1095,18 @@  fbsd_is_child_pending (pid_t pid)
 }
 
 #ifndef PTRACE_VFORK
-static std::forward_list<ptid_t> fbsd_pending_vfork_done;
-
 /* Record a pending vfork done event.  */
 
 static void
 fbsd_add_vfork_done (ptid_t pid)
 {
-  fbsd_pending_vfork_done.push_front (pid);
+  add_pending_event (ptid, target_waitstatus ().set_vfork_done ());
 
   /* If we're in async mode, need to tell the event loop there's
      something here to process.  */
   if (target_is_async_p ())
     async_file_mark ();
 }
-
-/* Check for a pending vfork done event for a specific PID.  */
-
-static int
-fbsd_is_vfork_done_pending (pid_t pid)
-{
-  for (auto it = fbsd_pending_vfork_done.begin ();
-       it != fbsd_pending_vfork_done.end (); it++)
-    if (it->pid () == pid)
-      return 1;
-  return 0;
-}
-
-/* Check for a pending vfork done event.  If one is found, remove it
-   from the list and return the PTID.  */
-
-static ptid_t
-fbsd_next_vfork_done (void)
-{
-  if (!fbsd_pending_vfork_done.empty ())
-    {
-      ptid_t ptid = fbsd_pending_vfork_done.front ();
-      fbsd_pending_vfork_done.pop_front ();
-      return ptid;
-    }
-  return null_ptid;
-}
 #endif
 #endif
 
@@ -1110,21 +1115,18 @@  fbsd_next_vfork_done (void)
 void
 fbsd_nat_target::resume (ptid_t ptid, int step, enum gdb_signal signo)
 {
-#if defined(TDP_RFPPWAIT) && !defined(PTRACE_VFORK)
-  pid_t pid;
-
-  /* Don't PT_CONTINUE a process which has a pending vfork done event.  */
-  if (minus_one_ptid == ptid)
-    pid = inferior_ptid.pid ();
-  else
-    pid = ptid.pid ();
-  if (fbsd_is_vfork_done_pending (pid))
-    return;
-#endif
-
   fbsd_nat_debug_printf ("[%s], step %d, signo %d (%s)",
 			 target_pid_to_str (ptid).c_str (), step, signo,
 			 gdb_signal_to_name (signo));
+
+  /* Don't PT_CONTINUE a thread or process which has a pending event.  */
+  m_resume_ptid = ptid;
+  if (have_pending_event (ptid))
+    {
+      fbsd_nat_debug_printf ("found pending event");
+      return;
+    }
+
   if (ptid.lwp_p ())
     {
       /* If ptid is a specific LWP, suspend all other LWPs in the process.  */
@@ -1257,14 +1259,6 @@  fbsd_nat_target::wait_1 (ptid_t ptid, struct target_waitstatus *ourstatus,
 
   while (1)
     {
-#ifndef PTRACE_VFORK
-      wptid = fbsd_next_vfork_done ();
-      if (wptid != null_ptid)
-	{
-	  ourstatus->set_vfork_done ();
-	  return wptid;
-	}
-#endif
       wptid = inf_ptrace_target::wait (ptid, ourstatus, target_options);
       if (ourstatus->kind () == TARGET_WAITKIND_STOPPED)
 	{
@@ -1473,16 +1467,26 @@  ptid_t
 fbsd_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
 		       target_wait_flags target_options)
 {
-  ptid_t wptid;
-
   fbsd_nat_debug_printf ("[%s], [%s]", target_pid_to_str (ptid).c_str (),
 			 target_options_to_string (target_options).c_str ());
 
+  /* If there is a valid pending event, return it.  */
+  gdb::optional<pending_event> event = take_pending_event ();
+  if (event.has_value ())
+    {
+      fbsd_nat_debug_printf ("returning pending event [%s], [%s]",
+			     target_pid_to_str (event->ptid).c_str (),
+			     event->status.to_string ().c_str ());
+      gdb_assert (event->ptid.matches (ptid));
+      *ourstatus = event->status;
+      return event->ptid;
+    }
+
   /* Ensure any subsequent events trigger a new event in the loop.  */
   if (is_async_p ())
     async_file_flush ();
 
-  wptid = wait_1 (ptid, ourstatus, target_options);
+  ptid_t wptid = wait_1 (ptid, ourstatus, target_options);
 
   /* If we are in async mode and found an event, there may still be
      another event pending.  Trigger the event pipe so that that the
@@ -1585,9 +1589,23 @@  fbsd_nat_target::create_inferior (const char *exec_file,
     (disable_randomization);
 #endif
 
+  /* Expect a wait for the new process.  */
+  m_resume_ptid = minus_one_ptid;
+  fbsd_nat_debug_printf ("setting resume_ptid to [%s]",
+			 target_pid_to_str (m_resume_ptid).c_str ());
   inf_ptrace_target::create_inferior (exec_file, allargs, env, from_tty);
 }
 
+void
+fbsd_nat_target::attach (const char *args, int from_tty)
+{
+  /* Expect a wait for the new process.  */
+  m_resume_ptid = minus_one_ptid;
+  fbsd_nat_debug_printf ("setting resume_ptid to [%s]",
+			 target_pid_to_str (m_resume_ptid).c_str ());
+  inf_ptrace_target::attach (args, from_tty);
+}
+
 #ifdef TDP_RFPPWAIT
 /* Target hook for follow_fork.  On entry and at return inferior_ptid is
    the ptid of the followed inferior.  */
diff --git a/gdb/fbsd-nat.h b/gdb/fbsd-nat.h
index a19bceaf5e4..e1d5b8efdf0 100644
--- a/gdb/fbsd-nat.h
+++ b/gdb/fbsd-nat.h
@@ -20,12 +20,15 @@ 
 #ifndef FBSD_NAT_H
 #define FBSD_NAT_H
 
+#include "gdbsupport/gdb_optional.h"
 #include "inf-ptrace.h"
 #include "regcache.h"
 #include "regset.h"
 #include <osreldate.h>
 #include <sys/proc.h>
 
+#include <list>
+
 /* FreeBSD kernels 11.3 and later report valid si_code values for
    SIGTRAP on all architectures.  Older FreeBSD kernels that supported
    TRAP_BRKPT did not report valid values for MIPS and sparc64.  Even
@@ -76,6 +79,8 @@  class fbsd_nat_target : public inf_ptrace_target
   void create_inferior (const char *, const std::string &,
 			char **, int) override;
 
+  void attach (const char *, int) override;
+
   void resume (ptid_t, int, enum gdb_signal) override;
 
   ptid_t wait (ptid_t, struct target_waitstatus *, target_wait_flags) override;
@@ -217,6 +222,46 @@  class fbsd_nat_target : public inf_ptrace_target
     return store_regset (regcache, regnum, note, regset, regbase, &regs,
 			 sizeof (regs));
   }
+
+private:
+  /* If an event is triggered asynchronously (fake vfork_done events)
+     or occurs when the core is not expecting it, a pending event is
+     created.  This event is then returned by a future call to the
+     target wait method.  */
+
+  struct pending_event
+  {
+    pending_event (const ptid_t &_ptid, const target_waitstatus &_status) :
+      ptid (_ptid), status (_status) {}
+
+    ptid_t ptid;
+    target_waitstatus status;
+  };
+
+  /* Add a new pending event to the list.  */
+
+  void add_pending_event (const ptid_t &ptid, const target_waitstatus &status);
+
+  /* Return true if there is a pending event matching FILTER.  */
+
+  bool have_pending_event (ptid_t filter);
+
+  /* Helper method called by the target wait method.  Check if there
+     is a pending event matching M_RESUME_PTID.  If there is a
+     matching event, the event is removed from the pending list and
+     returned.  */
+
+  gdb::optional<pending_event> take_pending_event ();
+
+  /* List of pending events.  */
+
+  std::list<pending_event> m_pending_events;
+
+  /* Filter for ptid's allowed to report events from wait.  Normally
+     set in resume, but also reset to minus_one_ptid in
+     create_inferior and attach.  */
+
+  ptid_t m_resume_ptid;
 };
 
 /* Fetch the signal information for PTID and store it in *SIGINFO.