static bool use_range_stepping = true;
+/* From the remote target's point of view, each thread is in one of these three
+ states. */
+enum class resume_state
+{
+ /* Not resumed - we haven't been asked to resume this thread. */
+ NOT_RESUMED,
+
+ /* We have been asked to resume this thread, but haven't sent a vCont action
+ for it yet. We'll need to consider it next time commit_resume is
+ called. */
+ RESUMED_PENDING_VCONT,
+
+ /* We have been asked to resume this thread, and we have sent a vCont action
+ for it. */
+ RESUMED,
+};
+
+/* Information about a thread's pending vCont-resume. Used when a thread is in
+ the remote_resume_state::RESUMED_PENDING_VCONT state. remote_target::resume
+ stores this information which is then picked up by
+ remote_target::commit_resume to know which is the proper action for this
+ thread to include in the vCont packet. */
+struct resumed_pending_vcont_info
+{
+ /* True if the last resume call for this thread was a step request, false
+ if a continue request. */
+ bool step;
+
+ /* The signal specified in the last resume call for this thread. */
+ gdb_signal sig;
+};
+
/* Private data that we'll store in (struct thread_info)->priv. */
struct remote_thread_info : public private_thread_info
{
to stop for a watchpoint. */
CORE_ADDR watch_data_address = 0;
- /* Fields used by the vCont action coalescing implemented in
- remote_resume / remote_commit_resume. remote_resume stores each
- thread's last resume request in these fields, so that a later
- remote_commit_resume knows which is the proper action for this
- thread to include in the vCont packet. */
+ /* Get the thread's resume state. */
+ enum resume_state resume_state () const
+ {
+ return m_resume_state;
+ }
- /* True if the last target_resume call for this thread was a step
- request, false if a continue request. */
- int last_resume_step = 0;
+ /* Put the thread in the NOT_RESUMED state. */
+ void set_not_resumed ()
+ {
+ m_resume_state = resume_state::NOT_RESUMED;
+ }
- /* The signal specified in the last target_resume call for this
- thread. */
- gdb_signal last_resume_sig = GDB_SIGNAL_0;
+ /* Put the thread in the RESUMED_PENDING_VCONT state. */
+ void set_resumed_pending_vcont (bool step, gdb_signal sig)
+ {
+ m_resume_state = resume_state::RESUMED_PENDING_VCONT;
+ m_resumed_pending_vcont_info.step = step;
+ m_resumed_pending_vcont_info.sig = sig;
+ }
+
+ /* Get the information this thread's pending vCont-resumption.
- /* Whether this thread was already vCont-resumed on the remote
- side. */
- int vcont_resumed = 0;
+ Must only be called if the thread is in the RESUMED_PENDING_VCONT resume
+ state. */
+ const struct resumed_pending_vcont_info &resumed_pending_vcont_info () const
+ {
+ gdb_assert (m_resume_state == resume_state::RESUMED_PENDING_VCONT);
+
+ return m_resumed_pending_vcont_info;
+ }
+
+ /* Put the thread in the VCONT_RESUMED state. */
+ void set_resumed ()
+ {
+ m_resume_state = resume_state::RESUMED;
+ }
+
+private:
+ /* Resume state for this thread. This is used to implement vCont action
+ coalescing (only when the target operates in non-stop mode).
+
+ remote_target::resume moves the thread to the RESUMED_PENDING_VCONT state,
+ which notes that this thread must be considered in the next commit_resume
+ call.
+
+ remote_target::commit_resume sends a vCont packet with actions for the
+ threads in the RESUMED_PENDING_VCONT state and moves them to the
+ VCONT_RESUMED state.
+
+ When reporting a stop to the core for a thread, that thread is moved back
+ to the NOT_RESUMED state. */
+ enum resume_state m_resume_state = resume_state::NOT_RESUMED;
+
+ /* Extra info used if the thread is in the RESUMED_PENDING_VCONT state. */
+ struct resumed_pending_vcont_info m_resumed_pending_vcont_info;
};
remote_state::remote_state ()
else
thread = add_thread (this, ptid);
- get_remote_thread_info (thread)->vcont_resumed = executing;
+ /* We start by assuming threads are resumed. That state then gets updated
+ when we process a matching stop reply. */
+ get_remote_thread_info (thread)->set_resumed ();
+
set_executing (this, ptid, executing);
set_running (this, ptid, running);
set_executing (this, event_ptid, false);
set_running (this, event_ptid, false);
- get_remote_thread_info (evthread)->vcont_resumed = 0;
+ get_remote_thread_info (evthread)->set_not_resumed ();
}
/* "Notice" the new inferiors before anything related to
individually. Resuming remote threads directly in target_resume
would thus result in sending one packet per thread. Instead, to
minimize roundtrip latency, here we just store the resume
- request; the actual remote resumption will be done in
- target_commit_resume / remote_commit_resume, where we'll be able
- to do vCont action coalescing. */
+ request (put the thread in RESUMED_PENDING_VCONT state); the actual remote
+ resumption will be done in remote_target::commit_resume, where we'll be
+ able to do vCont action coalescing. */
if (target_is_non_stop_p () && ::execution_direction != EXEC_REVERSE)
{
remote_thread_info *remote_thr;
else
remote_thr = get_remote_thread_info (this, ptid);
- remote_thr->last_resume_step = step;
- remote_thr->last_resume_sig = siggnal;
+ /* We don't expect the core to ask to resume an already resumed (from
+ its point of view) thread. */
+ gdb_assert (remote_thr->resume_state () == resume_state::NOT_RESUMED);
+
+ remote_thr->set_resumed_pending_vcont (step, siggnal);
return;
}
if (!remote_resume_with_vcont (ptid, step, siggnal))
remote_resume_with_hc (ptid, step, siggnal);
+ /* Update resumed state tracked by the remote target. */
+ for (thread_info *tp : all_non_exited_threads (this, ptid))
+ get_remote_thread_info (tp)->set_resumed ();
+
/* We are about to start executing the inferior, let's register it
with the event loop. NOTE: this is the one place where all the
execution commands end up. We could alternatively do this in each
for (thread_info *tp : all_non_exited_threads (this))
{
+ remote_thread_info *priv = get_remote_thread_info (tp);
+
/* If a thread of a process is not meant to be resumed, then we
can't wildcard that process. */
- if (!tp->executing)
+ if (priv->resume_state () == resume_state::NOT_RESUMED)
{
get_remote_inferior (tp->inf)->may_wildcard_vcont = false;
{
remote_thread_info *remote_thr = get_remote_thread_info (tp);
- if (!tp->executing || remote_thr->vcont_resumed)
+ /* If the thread was previously vCont-resumed, no need to send a specific
+ action for it. If we didn't receive a resume request for it, don't
+ send an action for it either. */
+ if (remote_thr->resume_state () != resume_state::RESUMED_PENDING_VCONT)
continue;
gdb_assert (!thread_is_in_step_over_chain (tp));
- if (!remote_thr->last_resume_step
- && remote_thr->last_resume_sig == GDB_SIGNAL_0
- && get_remote_inferior (tp->inf)->may_wildcard_vcont)
- {
- /* We'll send a wildcard resume instead. */
- remote_thr->vcont_resumed = 1;
- continue;
- }
+ const resumed_pending_vcont_info &info
+ = remote_thr->resumed_pending_vcont_info ();
- vcont_builder.push_action (tp->ptid,
- remote_thr->last_resume_step,
- remote_thr->last_resume_sig);
- remote_thr->vcont_resumed = 1;
+ /* Check if we need to send a specific action for this thread. If not,
+ it will be included in a wildcard resume instead. */
+ if (info.step || info.sig != GDB_SIGNAL_0
+ || !get_remote_inferior (tp->inf)->may_wildcard_vcont)
+ vcont_builder.push_action (tp->ptid, info.step, info.sig);
+
+ remote_thr->set_resumed ();
}
/* Now check whether we can send any process-wide wildcard. This is
remote_thr->core = stop_reply->core;
remote_thr->stop_reason = stop_reply->stop_reason;
remote_thr->watch_data_address = stop_reply->watch_data_address;
- remote_thr->vcont_resumed = 0;
+
+ if (target_is_non_stop_p ())
+ {
+ /* If the target works in non-stop mode, a stop-reply indicates that
+ only this thread stopped. */
+ remote_thr->set_not_resumed ();
+ }
+ else
+ {
+ /* If the target works in all-stop mode, a stop-reply indicates that
+ all the target's threads stopped. */
+ for (thread_info *tp : all_non_exited_threads (this))
+ get_remote_thread_info (tp)->set_not_resumed ();
+ }
}
delete stop_reply;