aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/gdbthread.h16
-rw-r--r--gdb/inferior.c21
-rw-r--r--gdb/inferior.h3
-rw-r--r--gdb/process-stratum-target.c34
-rw-r--r--gdb/process-stratum-target.h21
-rw-r--r--gdb/thread.c40
-rw-r--r--gdbsupport/ptid.cc8
-rw-r--r--gdbsupport/ptid.h7
8 files changed, 146 insertions, 4 deletions
diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index e9d1bbe..9c178f5 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -296,8 +296,7 @@ public:
bool resumed () const
{ return m_resumed; }
- void set_resumed (bool resumed)
- { m_resumed = resumed; }
+ void set_resumed (bool resumed);
/* Frontend view of the thread state. Note that the THREAD_RUNNING/
THREAD_STOPPED states are different from EXECUTING. When the
@@ -470,6 +469,12 @@ public:
linked. */
intrusive_list_node<thread_info> step_over_list_node;
+ /* Node for list of threads that are resumed and have a pending wait status.
+
+ The list head for this is in process_stratum_target, hence all threads in
+ this list belong to that process target. */
+ intrusive_list_node<thread_info> resumed_with_pending_wait_status_node;
+
/* Displaced-step state for this thread. */
displaced_step_thread_state displaced_step_state;
@@ -488,6 +493,13 @@ private:
thread_suspend_state m_suspend;
};
+using thread_info_resumed_with_pending_wait_status_node
+ = intrusive_member_node<thread_info,
+ &thread_info::resumed_with_pending_wait_status_node>;
+using thread_info_resumed_with_pending_wait_status_list
+ = intrusive_list<thread_info,
+ thread_info_resumed_with_pending_wait_status_node>;
+
/* A gdb::ref_ptr pointer to a thread_info. */
using thread_info_ref
diff --git a/gdb/inferior.c b/gdb/inferior.c
index 9681aaf..3c569f4 100644
--- a/gdb/inferior.c
+++ b/gdb/inferior.c
@@ -89,6 +89,27 @@ inferior::inferior (int pid_)
m_target_stack.push (get_dummy_target ());
}
+/* See inferior.h. */
+
+int
+inferior::unpush_target (struct target_ops *t)
+{
+ /* If unpushing the process stratum target from the inferior while threads
+ exist in the inferior, ensure that we don't leave any threads of the
+ inferior in the target's "resumed with pending wait status" list.
+
+ See also the comment in set_thread_exited. */
+ if (t->stratum () == process_stratum)
+ {
+ process_stratum_target *proc_target = as_process_stratum_target (t);
+
+ for (thread_info *thread : this->non_exited_threads ())
+ proc_target->maybe_remove_resumed_with_pending_wait_status (thread);
+ }
+
+ return m_target_stack.unpush (t);
+}
+
void
inferior::set_tty (const char *terminal_name)
{
diff --git a/gdb/inferior.h b/gdb/inferior.h
index 830dec3..2bfe29a 100644
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
@@ -362,8 +362,7 @@ public:
}
/* Unpush T from this inferior's target stack. */
- int unpush_target (struct target_ops *t)
- { return m_target_stack.unpush (t); }
+ int unpush_target (struct target_ops *t);
/* Returns true if T is pushed in this inferior's target stack. */
bool target_is_pushed (target_ops *t)
diff --git a/gdb/process-stratum-target.c b/gdb/process-stratum-target.c
index c851090..2cb6dfc 100644
--- a/gdb/process-stratum-target.c
+++ b/gdb/process-stratum-target.c
@@ -106,6 +106,40 @@ process_stratum_target::follow_exec (inferior *follow_inf, ptid_t ptid,
/* See process-stratum-target.h. */
+void
+process_stratum_target::maybe_add_resumed_with_pending_wait_status
+ (thread_info *thread)
+{
+ gdb_assert (!thread->resumed_with_pending_wait_status_node.is_linked ());
+
+ if (thread->resumed () && thread->has_pending_waitstatus ())
+ {
+ infrun_debug_printf ("adding to resumed threads with event list: %s",
+ thread->ptid.to_string ().c_str ());
+ m_resumed_with_pending_wait_status.push_back (*thread);
+ }
+}
+
+/* See process-stratum-target.h. */
+
+void
+process_stratum_target::maybe_remove_resumed_with_pending_wait_status
+ (thread_info *thread)
+{
+ if (thread->resumed () && thread->has_pending_waitstatus ())
+ {
+ infrun_debug_printf ("removing from resumed threads with event list: %s",
+ thread->ptid.to_string ().c_str ());
+ gdb_assert (thread->resumed_with_pending_wait_status_node.is_linked ());
+ auto it = m_resumed_with_pending_wait_status.iterator_to (*thread);
+ m_resumed_with_pending_wait_status.erase (it);
+ }
+ else
+ gdb_assert (!thread->resumed_with_pending_wait_status_node.is_linked ());
+}
+
+/* See process-stratum-target.h. */
+
std::set<process_stratum_target *>
all_non_exited_process_targets ()
{
diff --git a/gdb/process-stratum-target.h b/gdb/process-stratum-target.h
index 31a9775..f037280 100644
--- a/gdb/process-stratum-target.h
+++ b/gdb/process-stratum-target.h
@@ -22,6 +22,8 @@
#include "target.h"
#include <set>
+#include "gdbsupport/intrusive_list.h"
+#include "gdbthread.h"
/* Abstract base class inherited by all process_stratum targets. */
@@ -78,6 +80,14 @@ public:
may have spawned new threads we haven't heard of yet. */
bool threads_executing = false;
+ /* If THREAD is resumed and has a pending wait status, add it to the
+ target's "resumed with pending wait status" list. */
+ void maybe_add_resumed_with_pending_wait_status (thread_info *thread);
+
+ /* If THREAD is resumed and has a pending wait status, remove it from the
+ target's "resumed with pending wait status" list. */
+ void maybe_remove_resumed_with_pending_wait_status (thread_info *thread);
+
/* The connection number. Visible in "info connections". */
int connection_number = 0;
@@ -112,6 +122,17 @@ public:
coalesce multiple resumption requests in a single vCont
packet. */
bool commit_resumed_state = false;
+
+private:
+ /* List of threads managed by this target which simultaneously are resumed
+ and have a pending wait status.
+
+ This is done for optimization reasons, it would be possible to walk the
+ inferior thread lists to find these threads. But since this is something
+ we need to do quite frequently in the hot path, maintaining this list
+ avoids walking the thread lists repeatedly. */
+ thread_info_resumed_with_pending_wait_status_list
+ m_resumed_with_pending_wait_status;
};
/* Downcast TARGET to process_stratum_target. */
diff --git a/gdb/thread.c b/gdb/thread.c
index 289d33c..74d6b90 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -188,6 +188,17 @@ set_thread_exited (thread_info *tp, bool silent)
if (tp->state != THREAD_EXITED)
{
+ process_stratum_target *proc_target = tp->inf->process_target ();
+
+ /* Some targets unpush themselves from the inferior's target stack before
+ clearing the inferior's thread list (which marks all threads as exited,
+ and therefore leads to this function). In this case, the inferior's
+ process target will be nullptr when we arrive here.
+
+ See also the comment in inferior::unpush_target. */
+ if (proc_target != nullptr)
+ proc_target->maybe_remove_resumed_with_pending_wait_status (tp);
+
gdb::observers::thread_exit.notify (tp, silent);
/* Tag it as exited. */
@@ -296,12 +307,38 @@ thread_info::deletable () const
/* See gdbthread.h. */
void
+thread_info::set_resumed (bool resumed)
+{
+ if (resumed == m_resumed)
+ return;
+
+ process_stratum_target *proc_target = this->inf->process_target ();
+
+ /* If we transition from resumed to not resumed, we might need to remove
+ the thread from the resumed threads with pending statuses list. */
+ if (!resumed)
+ proc_target->maybe_remove_resumed_with_pending_wait_status (this);
+
+ m_resumed = resumed;
+
+ /* If we transition from not resumed to resumed, we might need to add
+ the thread to the resumed threads with pending statuses list. */
+ if (resumed)
+ proc_target->maybe_add_resumed_with_pending_wait_status (this);
+}
+
+/* See gdbthread.h. */
+
+void
thread_info::set_pending_waitstatus (const target_waitstatus &ws)
{
gdb_assert (!this->has_pending_waitstatus ());
m_suspend.waitstatus = ws;
m_suspend.waitstatus_pending_p = 1;
+
+ process_stratum_target *proc_target = this->inf->process_target ();
+ proc_target->maybe_add_resumed_with_pending_wait_status (this);
}
/* See gdbthread.h. */
@@ -311,6 +348,9 @@ thread_info::clear_pending_waitstatus ()
{
gdb_assert (this->has_pending_waitstatus ());
+ process_stratum_target *proc_target = this->inf->process_target ();
+ proc_target->maybe_remove_resumed_with_pending_wait_status (this);
+
m_suspend.waitstatus_pending_p = 0;
}
diff --git a/gdbsupport/ptid.cc b/gdbsupport/ptid.cc
index 73e2918..2417120 100644
--- a/gdbsupport/ptid.cc
+++ b/gdbsupport/ptid.cc
@@ -24,3 +24,11 @@
ptid_t const null_ptid = ptid_t::make_null ();
ptid_t const minus_one_ptid = ptid_t::make_minus_one ();
+
+/* See ptid.h. */
+
+std::string
+ptid_t::to_string () const
+{
+ return string_printf ("%d.%ld.%ld", m_pid, m_lwp, m_tid);
+}
diff --git a/gdbsupport/ptid.h b/gdbsupport/ptid.h
index a0a9175..a2553b2 100644
--- a/gdbsupport/ptid.h
+++ b/gdbsupport/ptid.h
@@ -33,6 +33,7 @@
*/
#include <functional>
+#include <string>
class ptid_t
{
@@ -124,6 +125,12 @@ public:
|| *this == filter);
}
+ /* Return a string representation of the ptid.
+
+ This is only meant to be used in debug messages. */
+
+ std::string to_string () const;
+
/* Make a null ptid. */
static constexpr ptid_t make_null ()