From: John Baldwin Date: Mon, 14 Aug 2023 20:38:42 +0000 (-0700) Subject: fbsd-nat: Add a list of pending events. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=1b0fa45741276182cbb42d8a78b5eba0150d47a1;p=binutils-gdb.git fbsd-nat: Add a list of pending events. 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. --- 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 - #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::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 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 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 #include +#include + /* 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 @@ public: 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 @@ protected: return store_regset (regcache, regnum, note, regset, regbase, ®s, 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 take_pending_event (); + + /* List of pending events. */ + + std::list 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.