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
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;
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
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)
{
}
/* 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)
/* 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 ()
{
#include "target.h"
#include <set>
+#include "gdbsupport/intrusive_list.h"
+#include "gdbthread.h"
/* Abstract base class inherited by all process_stratum targets. */
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;
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. */
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. */
/* 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)
{
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. */
{
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;
}
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);
+}
*/
#include <functional>
+#include <string>
class ptid_t
{
|| *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 ()