Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [PATCH 0/3] Changes to thread state tracking
@ 2021-08-30 20:03 Andrew Burgess
  2021-08-30 20:03 ` [PATCH 1/3] gdb: make thread_info::executing private Andrew Burgess
                   ` (2 more replies)
  0 siblings, 3 replies; 30+ messages in thread
From: Andrew Burgess @ 2021-08-30 20:03 UTC (permalink / raw)
  To: gdb-patches

A set of patches all related to tweaking how we track various bits of
thread state.

All feedback welcome.

Thanks,
Andrew


---

Andrew Burgess (3):
  gdb: make thread_info::executing private
  gdb: make thread_suspend_state::stop_pc optional
  gdb: make thread_info executing and resumed state more consistent

 gdb/breakpoint.c      |  4 +-
 gdb/frame.c           |  2 +-
 gdb/gdbthread.h       | 43 +++++++++++++++----
 gdb/infcmd.c          |  7 ++--
 gdb/inflow.c          |  2 +-
 gdb/infrun.c          | 97 +++++++++++++++++++++++++++++++++----------
 gdb/linux-nat.c       |  2 +-
 gdb/linux-thread-db.c |  2 +-
 gdb/record-btrace.c   |  2 +-
 gdb/remote.c          |  4 +-
 gdb/target.c          |  2 +-
 gdb/thread.c          | 51 ++++++++++++++---------
 12 files changed, 155 insertions(+), 63 deletions(-)

-- 
2.25.4


^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH 1/3] gdb: make thread_info::executing private
  2021-08-30 20:03 [PATCH 0/3] Changes to thread state tracking Andrew Burgess
@ 2021-08-30 20:03 ` Andrew Burgess
  2021-09-01 13:53   ` Simon Marchi via Gdb-patches
  2021-08-30 20:03 ` [PATCH 2/3] gdb: make thread_suspend_state::stop_pc optional Andrew Burgess
  2021-08-30 20:03 ` [PATCH 3/3] gdb: make thread_info executing and resumed state more consistent Andrew Burgess
  2 siblings, 1 reply; 30+ messages in thread
From: Andrew Burgess @ 2021-08-30 20:03 UTC (permalink / raw)
  To: gdb-patches

Rename thread_info::executing to thread_info::m_executing, and make it
private.  Add a new get/set member functions, and convert GDB to make
use of these.

The only real change of interest in this patch is in thread.c where I
have deleted the helper function set_executing_thread, and now just
use the new set function thread_info::set_executing.  However, the old
helper function set_executing_thread included some code to reset the
thread's stop_pc, so I moved this code into the new function
thread_info::set_executing.  However, I don't believe there is
anywhere that this results in a change of behaviour, previously the
executing flag was always set true through a call to
set_executing_thread anyway.
---
 gdb/breakpoint.c      |  4 ++--
 gdb/frame.c           |  2 +-
 gdb/gdbthread.h       | 15 ++++++++++-----
 gdb/infcmd.c          |  4 ++--
 gdb/inflow.c          |  2 +-
 gdb/infrun.c          | 26 +++++++++++++-------------
 gdb/linux-nat.c       |  2 +-
 gdb/linux-thread-db.c |  2 +-
 gdb/record-btrace.c   |  2 +-
 gdb/target.c          |  2 +-
 gdb/thread.c          | 37 +++++++++++++++++--------------------
 11 files changed, 50 insertions(+), 48 deletions(-)

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index feca224ccf4..1628c172271 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -1674,7 +1674,7 @@ watchpoint_in_thread_scope (struct watchpoint *b)
   return (b->pspace == current_program_space
 	  && (b->watchpoint_thread == null_ptid
 	      || (inferior_ptid == b->watchpoint_thread
-		  && !inferior_thread ()->executing)));
+		  && !inferior_thread ()->executing ())));
 }
 
 /* Set watchpoint B to disp_del_at_next_stop, even including its possible
@@ -4525,7 +4525,7 @@ get_bpstat_thread ()
     return NULL;
 
   thread_info *tp = inferior_thread ();
-  if (tp->state == THREAD_EXITED || tp->executing)
+  if (tp->state == THREAD_EXITED || tp->executing ())
     return NULL;
   return tp;
 }
diff --git a/gdb/frame.c b/gdb/frame.c
index 4d7505f7ae3..d28944075ed 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -1789,7 +1789,7 @@ has_stack_frames ()
 	return false;
 
       /* ... or from a spinning thread.  */
-      if (tp->executing)
+      if (tp->executing ())
 	return false;
     }
 
diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index 9c178f531d9..734fe3bce64 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -287,11 +287,10 @@ class thread_info : public refcounted_object,
      if the thread does not have a user-given name.  */
   char *name = NULL;
 
-  /* True means the thread is executing.  Note: this is different
-     from saying that there is an active target and we are stopped at
-     a breakpoint, for instance.  This is a real indicator whether the
-     thread is off and running.  */
-  bool executing = false;
+  bool executing () const
+  { return m_executing; }
+
+  void set_executing (bool executing);
 
   bool resumed () const
   { return m_resumed; }
@@ -488,6 +487,12 @@ class thread_info : public refcounted_object,
      the thread run.  */
   bool m_resumed = false;
 
+  /* True means the thread is executing.  Note: this is different
+     from saying that there is an active target and we are stopped at
+     a breakpoint, for instance.  This is a real indicator whether the
+     thread is off and running.  */
+  bool m_executing = false;
+
   /* State of inferior thread to restore after GDB is done with an inferior
      call.  See `struct thread_suspend_state'.  */
   thread_suspend_state m_suspend;
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index c183b60e81a..e6ee49bc43d 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -2371,7 +2371,7 @@ proceed_after_attach (inferior *inf)
   scoped_restore_current_thread restore_thread;
 
   for (thread_info *thread : inf->non_exited_threads ())
-    if (!thread->executing
+    if (!thread->executing ()
 	&& !thread->stop_requested
 	&& thread->stop_signal () == GDB_SIGNAL_0)
       {
@@ -2644,7 +2644,7 @@ notice_new_inferior (thread_info *thr, bool leave_running, int from_tty)
   /* When we "notice" a new inferior we need to do all the things we
      would normally do if we had just attached to it.  */
 
-  if (thr->executing)
+  if (thr->executing ())
     {
       struct inferior *inferior = current_inferior ();
 
diff --git a/gdb/inflow.c b/gdb/inflow.c
index 74dda702a8a..bcab66487b0 100644
--- a/gdb/inflow.c
+++ b/gdb/inflow.c
@@ -525,7 +525,7 @@ child_interrupt (struct target_ops *self)
   thread_info *resumed = NULL;
   for (thread_info *thr : all_non_exited_threads ())
     {
-      if (thr->executing)
+      if (thr->executing ())
 	{
 	  resumed = thr;
 	  break;
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 5ee650fa464..11440894b15 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -862,7 +862,7 @@ static void
 proceed_after_vfork_done (thread_info *thread)
 {
   if (thread->state == THREAD_RUNNING
-      && !thread->executing
+      && !thread->executing ()
       && !thread->stop_requested
       && thread->stop_signal () == GDB_SIGNAL_0)
     {
@@ -1885,7 +1885,7 @@ start_step_over (void)
 
       if (tp->control.trap_expected
 	  || tp->resumed ()
-	  || tp->executing)
+	  || tp->executing ())
 	{
 	  internal_error (__FILE__, __LINE__,
 			  "[%s] has inconsistent state: "
@@ -1893,7 +1893,7 @@ start_step_over (void)
 			  target_pid_to_str (tp->ptid).c_str (),
 			  tp->control.trap_expected,
 			  tp->resumed (),
-			  tp->executing);
+			  tp->executing ());
 	}
 
       infrun_debug_printf ("resuming [%s] for step-over",
@@ -3197,7 +3197,7 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
 	      {
 		infrun_debug_printf ("[%s] resumed",
 				     target_pid_to_str (tp->ptid).c_str ());
-		gdb_assert (tp->executing || tp->has_pending_waitstatus ());
+		gdb_assert (tp->executing () || tp->has_pending_waitstatus ());
 		continue;
 	      }
 
@@ -3329,7 +3329,7 @@ infrun_thread_stop_requested (ptid_t ptid)
     {
       if (tp->state != THREAD_RUNNING)
 	continue;
-      if (tp->executing)
+      if (tp->executing ())
 	continue;
 
       /* Remove matching threads from the step-over queue, so
@@ -3778,7 +3778,7 @@ prepare_for_detach (void)
 	{
 	  if (thr->displaced_step_state.in_progress ())
 	    {
-	      if (thr->executing)
+	      if (thr->executing ())
 		{
 		  if (!thr->stop_requested)
 		    {
@@ -4806,7 +4806,7 @@ handle_one (const wait_one_event &event)
 	t = add_thread (event.target, event.ptid);
 
       t->stop_requested = 0;
-      t->executing = 0;
+      t->set_executing (false);
       t->set_resumed (false);
       t->control.may_range_step = 0;
 
@@ -4947,7 +4947,7 @@ stop_all_threads (void)
 	      if (!target_is_non_stop_p ())
 		continue;
 
-	      if (t->executing)
+	      if (t->executing ())
 		{
 		  /* If already stopping, don't request a stop again.
 		     We just haven't seen the notification yet.  */
@@ -5091,7 +5091,7 @@ handle_no_resumed (struct execution_control_state *ecs)
 
   for (thread_info *thread : all_non_exited_threads ())
     {
-      if (swap_terminal && thread->executing)
+      if (swap_terminal && thread->executing ())
 	{
 	  if (thread->inf != curr_inf)
 	    {
@@ -5104,7 +5104,7 @@ handle_no_resumed (struct execution_control_state *ecs)
 	}
 
       if (!ignore_event
-	  && (thread->executing || thread->has_pending_waitstatus ()))
+	  && (thread->executing () || thread->has_pending_waitstatus ()))
 	{
 	  /* Either there were no unwaited-for children left in the
 	     target at some point, but there are now, or some target
@@ -5722,7 +5722,7 @@ restart_threads (struct thread_info *event_thread)
 	{
 	  infrun_debug_printf ("restart threads: [%s] resumed",
 			      target_pid_to_str (tp->ptid).c_str ());
-	  gdb_assert (tp->executing || tp->has_pending_waitstatus ());
+	  gdb_assert (tp->executing () || tp->has_pending_waitstatus ());
 	  continue;
 	}
 
@@ -5869,7 +5869,7 @@ finish_step_over (struct execution_control_state *ecs)
 	     do_target_wait.  */
 	  tp->set_resumed (true);
 
-	  gdb_assert (!tp->executing);
+	  gdb_assert (!tp->executing ());
 
 	  regcache = get_thread_regcache (tp);
 	  tp->set_stop_pc (regcache_read_pc (regcache));
@@ -7419,7 +7419,7 @@ restart_after_all_stop_detach (process_stratum_target *proc_target)
       /* If we have any thread that is already executing, then we
 	 don't need to resume the target -- it is already been
 	 resumed.  */
-      if (thr->executing)
+      if (thr->executing ())
 	return;
 
       /* If we have a pending event to process, skip resuming the
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index e9433b2206b..29ca62d2bc1 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -1280,7 +1280,7 @@ get_detach_signal (struct lwp_info *lp)
     {
       struct thread_info *tp = find_thread_ptid (linux_target, lp->ptid);
 
-      if (target_is_non_stop_p () && !tp->executing)
+      if (target_is_non_stop_p () && !tp->executing ())
 	{
 	  if (tp->has_pending_waitstatus ())
 	    signo = tp->pending_waitstatus ().value.sig;
diff --git a/gdb/linux-thread-db.c b/gdb/linux-thread-db.c
index eb2aa5ac409..245939b6400 100644
--- a/gdb/linux-thread-db.c
+++ b/gdb/linux-thread-db.c
@@ -1641,7 +1641,7 @@ thread_db_target::update_thread_list ()
 	continue;
 
       thread_info *thread = any_live_thread_of_inferior (inf);
-      if (thread == NULL || thread->executing)
+      if (thread == NULL || thread->executing ())
 	continue;
 
       /* It's best to avoid td_ta_thr_iter if possible.  That walks
diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index 85e357e604a..e2b9866d68a 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -1998,7 +1998,7 @@ get_thread_current_frame_id (struct thread_info *tp)
      For the former, EXECUTING is true and we're in wait, about to
      move the thread.  Since we need to recompute the stack, we temporarily
      set EXECUTING to false.  */
-  executing = tp->executing;
+  executing = tp->executing ();
   set_executing (proc_target, inferior_ptid, false);
 
   id = null_frame_id;
diff --git a/gdb/target.c b/gdb/target.c
index ae2d659583e..d1c1bf523ed 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -3815,7 +3815,7 @@ target_pass_ctrlc (void)
 	{
 	  /* A thread can be THREAD_STOPPED and executing, while
 	     running an infcall.  */
-	  if (thr->state == THREAD_RUNNING || thr->executing)
+	  if (thr->state == THREAD_RUNNING || thr->executing ())
 	    {
 	      /* We can get here quite deep in target layers.  Avoid
 		 switching thread context or anything that would
diff --git a/gdb/thread.c b/gdb/thread.c
index a82fb49140a..c95a9186681 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -319,6 +319,16 @@ thread_info::deletable () const
 
 /* See gdbthread.h.  */
 
+void
+thread_info::set_executing (bool executing)
+{
+  m_executing = executing;
+  if (executing)
+    this->set_stop_pc (~(CORE_ADDR) 0);
+}
+
+/* See gdbthread.h.  */
+
 void
 thread_info::set_resumed (bool resumed)
 {
@@ -625,13 +635,13 @@ any_live_thread_of_inferior (inferior *inf)
       curr_tp = inferior_thread ();
       if (curr_tp->state == THREAD_EXITED)
 	curr_tp = NULL;
-      else if (!curr_tp->executing)
+      else if (!curr_tp->executing ())
 	return curr_tp;
     }
 
   for (thread_info *tp : inf->non_exited_threads ())
     {
-      if (!tp->executing)
+      if (!tp->executing ())
 	return tp;
 
       tp_executing = tp;
@@ -841,24 +851,11 @@ set_running (process_stratum_target *targ, ptid_t ptid, bool running)
     gdb::observers::target_resumed.notify (ptid);
 }
 
-
-/* Helper for set_executing.  Set's the thread's 'executing' field
-   from EXECUTING, and if EXECUTING is true also clears the thread's
-   stop_pc.  */
-
-static void
-set_executing_thread (thread_info *thr, bool executing)
-{
-  thr->executing = executing;
-  if (executing)
-    thr->set_stop_pc (~(CORE_ADDR) 0);
-}
-
 void
 set_executing (process_stratum_target *targ, ptid_t ptid, bool executing)
 {
   for (thread_info *tp : all_non_exited_threads (targ, ptid))
-    set_executing_thread (tp, executing);
+    tp->set_executing (executing);
 
   /* It only takes one running thread to spawn more threads.  */
   if (executing)
@@ -895,7 +892,7 @@ finish_thread_state (process_stratum_target *targ, ptid_t ptid)
   bool any_started = false;
 
   for (thread_info *tp : all_non_exited_threads (targ, ptid))
-    if (set_running_thread (tp, tp->executing))
+    if (set_running_thread (tp, tp->executing ()))
       any_started = true;
 
   if (any_started)
@@ -922,7 +919,7 @@ validate_registers_access (void)
      at the prompt) when a thread is not executing for some internal
      reason, but is marked running from the user's perspective.  E.g.,
      the thread is waiting for its turn in the step-over queue.  */
-  if (tp->executing)
+  if (tp->executing ())
     error (_("Selected thread is running."));
 }
 
@@ -940,7 +937,7 @@ can_access_registers_thread (thread_info *thread)
     return false;
 
   /* ... or from a spinning thread.  FIXME: see validate_registers_access.  */
-  if (thread->executing)
+  if (thread->executing ())
     return false;
 
   return true;
@@ -1997,7 +1994,7 @@ update_threads_executing (void)
 
       for (thread_info *tp : inf->non_exited_threads ())
 	{
-	  if (tp->executing)
+	  if (tp->executing ())
 	    {
 	      targ->threads_executing = true;
 	      return;
-- 
2.25.4


^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH 2/3] gdb: make thread_suspend_state::stop_pc optional
  2021-08-30 20:03 [PATCH 0/3] Changes to thread state tracking Andrew Burgess
  2021-08-30 20:03 ` [PATCH 1/3] gdb: make thread_info::executing private Andrew Burgess
@ 2021-08-30 20:03 ` Andrew Burgess
  2021-09-01 14:23   ` Simon Marchi via Gdb-patches
  2021-08-30 20:03 ` [PATCH 3/3] gdb: make thread_info executing and resumed state more consistent Andrew Burgess
  2 siblings, 1 reply; 30+ messages in thread
From: Andrew Burgess @ 2021-08-30 20:03 UTC (permalink / raw)
  To: gdb-patches

Currently the stop_pc field of thread_suspect_state is a CORE_ADDR and
when we want to indicate that there is no stop_pc available we set
this field back to a special value.

There are actually two special values used, in post_create_inferior
the stop_pc is set to 0.  This is a little unfortunate, there are
plenty of embedded targets where 0 is a valid pc address.  The more
common special value for stop_pc was set in
thread_info::set_executing, where the value (~(CORE_ADDR) 0) was used.

This commit changes things so that the stop_pc is instead a
gdb::optional.  We can now explicitly reset the field to an
uninitialised state, we also have (when compiling with _GLIBCXX_DEBUG
defined) asserts that we don't read the stop_pc when its in an
uninitialised state (see gdbsupport/gdb_optional.h).

One situation where a thread will not have a stop_pc value is when the
thread is stopped as a consequence of GDB being in all stop mode, and
some other thread stopped at an interesting event.  When GDB brings
all the other threads to a stop those other threads will not have a
stop_pc set (thus avoiding an unnecessary read of $pc).

Previously, when GDB passed through handle_one (in infrun.c) the
threads executing flag was set to false and the stop_pc field was left
unchanged, i.e. it would (previous) have been left as ~0.

Now, handle_one leaves the stop_pc with no value.

This caused a problem when we later try to set these threads running
again, in proceed() we compare the current pc with the cached
stop_pc.  If the thread was stopped in via handle_one then the stop_pc
would have been left as ~0, and the compare (in proceed)
would (likely) fail.  Now however, this compare tries to read the
stop_pc when it has no value, this would trigger an assert.

To resolve this I've added thread_info::stop_pc_p() which returns true
if the thread has a cached stop_pc.  We should only ever call
thread_info::stop_pc() if we know that there is a cached stop_pc.

After running the testsuite I've seen no other situations where
stop_pc is read uninitialised.
---
 gdb/gdbthread.h | 26 ++++++++++++++++++++++----
 gdb/infcmd.c    |  2 +-
 gdb/infrun.c    |  3 ++-
 gdb/thread.c    |  2 +-
 4 files changed, 26 insertions(+), 7 deletions(-)

diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index 734fe3bce64..245445a859b 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -197,9 +197,12 @@ struct thread_suspend_state
        stop_reason: if the thread's PC has changed since the thread
        last stopped, a pending breakpoint waitstatus is discarded.
 
-     - If the thread is running, this is set to -1, to avoid leaving
-       it with a stale value, to make it easier to catch bugs.  */
-  CORE_ADDR stop_pc = 0;
+     - If the thread is running, then this field has its value removed by
+       calling stop_pc.reset() (see thread_info::set_executing()).
+       Attempting to read a gdb::optional with no value is undefined
+       behaviour and will trigger an assertion error when _GLIBCXX_DEBUG is
+       defined, which should make error easier to track down.  */
+  gdb::optional<CORE_ADDR> stop_pc;
 };
 
 /* Base class for target-specific thread data.  */
@@ -326,7 +329,7 @@ class thread_info : public refcounted_object,
 
   CORE_ADDR stop_pc () const
   {
-    return m_suspend.stop_pc;
+    return *m_suspend.stop_pc;
   }
 
   /* Set this thread's stop PC.  */
@@ -336,6 +339,21 @@ class thread_info : public refcounted_object,
     m_suspend.stop_pc = stop_pc;
   }
 
+  /* Remove the stop_pc stored on this thread.  */
+
+  void clear_stop_pc ()
+  {
+    m_suspend.stop_pc.reset ();
+  }
+
+  /* Return true if this thread has a cached stop pc value, otherwise
+     return false.  */
+
+  bool stop_pc_p () const
+  {
+    return m_suspend.stop_pc.has_value ();
+  }
+
   /* Return true if this thread has a pending wait status.  */
 
   bool has_pending_waitstatus () const
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index e6ee49bc43d..d948f4bafc5 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -249,7 +249,7 @@ post_create_inferior (int from_tty)
      missing registers info), ignore it.  */
   thread_info *thr = inferior_thread ();
 
-  thr->set_stop_pc (0);
+  thr->clear_stop_pc ();
   try
     {
       regcache *rc = get_thread_regcache (thr);
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 11440894b15..5554523a049 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -3051,7 +3051,8 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
 
   if (addr == (CORE_ADDR) -1)
     {
-      if (pc == cur_thr->stop_pc ()
+      if (cur_thr->stop_pc_p ()
+	  && pc == cur_thr->stop_pc ()
 	  && breakpoint_here_p (aspace, pc) == ordinary_breakpoint_here
 	  && execution_direction != EXEC_REVERSE)
 	/* There is a breakpoint at the address we will resume at,
diff --git a/gdb/thread.c b/gdb/thread.c
index c95a9186681..10c3dcd6991 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -324,7 +324,7 @@ thread_info::set_executing (bool executing)
 {
   m_executing = executing;
   if (executing)
-    this->set_stop_pc (~(CORE_ADDR) 0);
+    this->clear_stop_pc ();
 }
 
 /* See gdbthread.h.  */
-- 
2.25.4


^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH 3/3] gdb: make thread_info executing and resumed state more consistent
  2021-08-30 20:03 [PATCH 0/3] Changes to thread state tracking Andrew Burgess
  2021-08-30 20:03 ` [PATCH 1/3] gdb: make thread_info::executing private Andrew Burgess
  2021-08-30 20:03 ` [PATCH 2/3] gdb: make thread_suspend_state::stop_pc optional Andrew Burgess
@ 2021-08-30 20:03 ` Andrew Burgess
  2021-09-01 15:09   ` Simon Marchi via Gdb-patches
  2022-01-13 18:34   ` [PATCHv3] " Andrew Burgess via Gdb-patches
  2 siblings, 2 replies; 30+ messages in thread
From: Andrew Burgess @ 2021-08-30 20:03 UTC (permalink / raw)
  To: gdb-patches

This commit was inspired by this comment from Simon:

  https://sourceware.org/pipermail/gdb-patches/2021-July/180694.html

The comment is about two thread_info flags m_executing and m_resumed.
The m_resumed flag indicates that at the infrun level GDB has set the
thread running, while the m_executing flag indicates that the thread
is actually running at the target level.

It is very common that a thread can be m_resumed, but not m_executing,
that is, core GDB thinks the thread is, or should be, running, but at
the target level the thread isn't currently running.

The comment Simon made was in reply to a patch I posted where I found
a case where a thread was marked m_executing, but not m_resumed, that
is, at the infrun level GDB thought the thread was stopped, but at the
target level the thread was actually running.  Simon suggests that
this feels like an invalid state, and after thinking about it, I
agree.

So, this commit adds some new asserts to GDB.  The core idea here is
that the resumed and executing flags should only change in the
following pattern, to begin with everything is set false:

  Resumed: false
  Executing: false

Then infrun marks the thread resumed:

  Resumed: true
  Executing: false

Then a target starts the thread executing:

  Resumed: true
  Executing: true

The thread stops, the target spots this and marks the thread no longer
executing:

  Resumed: true
  Executing: false

And finally, infrun acknowledges that the thread is now no longer
resumed:

  Resumed: false
  Executing: false

Notice that at no point is resumed false, while executing is true.

And so we can add some asserts:

 1. The resumed flag should only change state when the executing flag
 is false, and

 2. The executing flag should only change state when the resumed flag
 is true.

I added these asserts and ....

.... it turns out these rules are broken all over the place in GDB, we
have problems like:

 (a) When new threads appear they are marked executing, but not
 resumed, and

 (b) In some places we mark a single thread as resumed, but then
 actually set multiple threads executing.

For (a) it could be argued that this is a legitimate state - this is
actually the problem I addressed in the original patch that Simon was
replying too, however, we don't need to support this as a separate
state, so if we can make this case follow the expected set of state
transitions then it allows us to reduce the number of states that GDB
can be in, which I think is a good thing.

Case (b) seems to just be a bug to me.

The interesting changes in this commit then are:

  * gdbthread.h (set_stop_pc): Add assert that the stop_pc can only be
  set when a thread is neither resumed, or executing.

  * infcmd.c (post_create_inferior): Ensure thread is non-resumed
  before clearing the stop_pc.

  * infrun.c (struct scoped_mark_thread_resumed): This new class is
  used to ensure that all the required threads are marked resumed when
  required, this addresses issue (b) above.  I make use of this new
  class in...

  (do_target_resume):  Use scoped_mark_thread_resumed to mark all
  threads resumed prior to actually calling into the target to resume
  the threads.  Placing this call here allows me to remove some calls
  to thread_info::set_resumed() in other places...

  (resume_1): Remove a call to thread_info::set_resumed() from here.

  (handle_inferior_event): Mark the thread as non-resumed prior to
  setting the stop_pc, this thread is stopping.  Additionally, when we
  need to place a thread back into the resumed state so that we can
  later find its pending event, we must mark the thread resumed after
  setting the stop_pc, see the asserts added to set_stop_pc for why.

  (keep_going_stepped_thread): Remove a call to set_resumed thanks to
  our changes in do_target_resume.

  * remote.c (remote_target::remote_add_thread): Mark the new thread
  as resumed.

  (remote_target::process_initial_stop_replies): Mark the thread as
  non-resumed.

  * thread.c (add_thread_silent): New threads are now created in the
  resumed state.  This reflects the reality of how GDB thinks about
  new threads, they appear in a running state, and we then process a
  stop event from (or about) the thread, and bring the thread to a
  stop.  As we most often first see the thread while processing the
  stop event then it makes sense (I think) that the thread starts as
  resumed, but not executing, as core GDB should consider the thread
  resumed at a high level, but in reality the thread is most likely
  stopped due to the event we are currently processing.

  (thread_info::set_executing): Add an early exit patch like we
  already have in thread_info::set_executing().  Also add the
  assertion that is one of the two core asserts for this patch.

  (thread_info::set_resumed): Add the other core assert for this
  patch.

This series has been tested on X86-64 GNU/Linux with the unix,
native-gdbserver, and native-extended-gdbserver boards.
---
 gdb/gdbthread.h |  2 ++
 gdb/infcmd.c    |  1 +
 gdb/infrun.c    | 70 ++++++++++++++++++++++++++++++++++++++++++-------
 gdb/remote.c    |  4 ++-
 gdb/thread.c    | 14 ++++++++++
 5 files changed, 81 insertions(+), 10 deletions(-)

diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index 245445a859b..120315ca25f 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -336,6 +336,8 @@ class thread_info : public refcounted_object,
 
   void set_stop_pc (CORE_ADDR stop_pc)
   {
+    gdb_assert (!m_resumed);
+    gdb_assert (!m_executing);
     m_suspend.stop_pc = stop_pc;
   }
 
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index d948f4bafc5..34924e17abe 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -249,6 +249,7 @@ post_create_inferior (int from_tty)
      missing registers info), ignore it.  */
   thread_info *thr = inferior_thread ();
 
+  thr->set_resumed (false);
   thr->clear_stop_pc ();
   try
     {
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 5554523a049..07847ade325 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -2100,6 +2100,52 @@ internal_resume_ptid (int user_step)
     return user_visible_resume_ptid (user_step);
 }
 
+/* Before calling into target code to set inferior threads executing we
+   must mark all threads as resumed.  If an exception is thrown while
+   trying to set the threads executing then we should mark the threads as
+   non-resumed.
+
+   Create an instance of this struct before */
+struct scoped_mark_thread_resumed
+{
+  /* Constructor.  All threads matching PTID will be marked as resumed.  */
+  scoped_mark_thread_resumed (process_stratum_target *targ, ptid_t ptid)
+    : m_target (targ), m_ptid (ptid)
+  {
+    gdb_assert (m_target != nullptr);
+    set_resumed (m_target, m_ptid, true);
+  }
+
+  /* Destructor.  If M_TARGET is not nullptr then mark all threads matching
+     M_PTID as no longer being resumed.  The expectation is that on the
+     exception path this will be called with M_TARGET still set to a valid
+     target.  If however, the threads were successfully set executing then
+     this->commit() will have been called, and M_TARGET will now be
+     nullptr.  */
+  ~scoped_mark_thread_resumed ()
+  {
+    if (m_target != nullptr)
+      set_resumed (m_target, m_ptid, false);
+  }
+
+  /* Called once all of the threads have successfully be set executing (by
+     calling into the target code).  Clears M_TARGET as an indication that,
+     when this object is destructed, we should leave all matching threads
+     as being marked resumed.  */
+  void commit ()
+  {
+    m_target = nullptr;
+  }
+
+private:
+
+  /* The target used for marking threads as resumed or non-resumed.  */
+  process_stratum_target *m_target;
+
+  /* The thread (or threads) to mark as resumed.  */
+  ptid_t m_ptid;
+};
+
 /* Wrapper for target_resume, that handles infrun-specific
    bookkeeping.  */
 
@@ -2108,6 +2154,11 @@ do_target_resume (ptid_t resume_ptid, bool step, enum gdb_signal sig)
 {
   struct thread_info *tp = inferior_thread ();
 
+  /* Create a scoped_mark_thread_resumed to mark all threads matching
+     RESUME_PTID as resumed.  */
+  process_stratum_target *curr_target = current_inferior ()->process_target ();
+  scoped_mark_thread_resumed scoped_resume (curr_target, resume_ptid);
+
   gdb_assert (!tp->stop_requested);
 
   /* Install inferior's terminal modes.  */
@@ -2146,6 +2197,9 @@ do_target_resume (ptid_t resume_ptid, bool step, enum gdb_signal sig)
 
   if (target_can_async_p ())
     target_async (1);
+
+  /* Call commit so SCOPED_RESUME leaves threads marked as resumed.  */
+  scoped_resume.commit ();
 }
 
 /* Resume the inferior.  SIG is the signal to give the inferior
@@ -2305,7 +2359,6 @@ resume_1 (enum gdb_signal sig)
 
 	      resume_ptid = internal_resume_ptid (user_step);
 	      do_target_resume (resume_ptid, false, GDB_SIGNAL_0);
-	      tp->set_resumed (true);
 	      return;
 	    }
 	}
@@ -2514,7 +2567,6 @@ resume_1 (enum gdb_signal sig)
     }
 
   do_target_resume (resume_ptid, step, sig);
-  tp->set_resumed (true);
 }
 
 /* Resume the inferior.  SIG is the signal to give the inferior
@@ -5616,6 +5668,9 @@ handle_inferior_event (struct execution_control_state *ecs)
 	 execd thread for that case (this is a nop otherwise).  */
       ecs->event_thread = inferior_thread ();
 
+      /* If we did select a new thread, make sure its non-resumed.  */
+      ecs->event_thread->set_resumed (false);
+
       ecs->event_thread->set_stop_pc
 	(regcache_read_pc (get_thread_regcache (ecs->event_thread)));
 
@@ -5865,12 +5920,6 @@ finish_step_over (struct execution_control_state *ecs)
 
 	  /* Record the event thread's event for later.  */
 	  save_waitstatus (tp, &ecs->ws);
-	  /* This was cleared early, by handle_inferior_event.  Set it
-	     so this pending event is considered by
-	     do_target_wait.  */
-	  tp->set_resumed (true);
-
-	  gdb_assert (!tp->executing ());
 
 	  regcache = get_thread_regcache (tp);
 	  tp->set_stop_pc (regcache_read_pc (regcache));
@@ -5881,6 +5930,10 @@ finish_step_over (struct execution_control_state *ecs)
 			       target_pid_to_str (tp->ptid).c_str (),
 			       currently_stepping (tp));
 
+	  /* This was cleared early, by handle_inferior_event.  Set it so
+	     this pending event is considered by do_target_wait.  */
+	  tp->set_resumed (true);
+
 	  /* This in-line step-over finished; clear this so we won't
 	     start a new one.  This is what handle_signal_stop would
 	     do, if we returned false.  */
@@ -7530,7 +7583,6 @@ keep_going_stepped_thread (struct thread_info *tp)
 				     get_frame_address_space (frame),
 				     tp->stop_pc ());
 
-      tp->set_resumed (true);
       resume_ptid = internal_resume_ptid (tp->control.stepping_command);
       do_target_resume (resume_ptid, false, GDB_SIGNAL_0);
     }
diff --git a/gdb/remote.c b/gdb/remote.c
index b6da6b086a2..0cfed0bdf65 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -2546,8 +2546,9 @@ remote_target::remote_add_thread (ptid_t ptid, bool running, bool executing)
      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_resumed (this, ptid, running);
+  set_executing (this, ptid, executing);
 
   return thread;
 }
@@ -4586,6 +4587,7 @@ remote_target::process_initial_stop_replies (int from_tty)
 	evthread->set_pending_waitstatus (ws);
 
       set_executing (this, event_ptid, false);
+      set_resumed (this, event_ptid, false);
       set_running (this, event_ptid, false);
       get_remote_thread_info (evthread)->set_not_resumed ();
     }
diff --git a/gdb/thread.c b/gdb/thread.c
index 10c3dcd6991..aceb233be80 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -262,6 +262,13 @@ add_thread_silent (process_stratum_target *targ, ptid_t ptid)
   tp = new_thread (inf, ptid);
   gdb::observers::new_thread.notify (tp);
 
+  /* All threads are created in a resumed state, that is as soon as GDB
+     sees a new thread it is expected to be running as far as the core of
+     GDB is concerned.  At a target level the thread is probably stopped
+     right now, hence the executing flag is left initialized to false.  */
+  tp->set_resumed (true);
+  gdb_assert (!tp->executing ());
+
   return tp;
 }
 
@@ -322,6 +329,11 @@ thread_info::deletable () const
 void
 thread_info::set_executing (bool executing)
 {
+  if (executing == m_executing)
+    return;
+
+  gdb_assert (m_resumed);
+
   m_executing = executing;
   if (executing)
     this->clear_stop_pc ();
@@ -335,6 +347,8 @@ thread_info::set_resumed (bool resumed)
   if (resumed == m_resumed)
     return;
 
+  gdb_assert (!m_executing);
+
   process_stratum_target *proc_target = this->inf->process_target ();
 
   /* If we transition from resumed to not resumed, we might need to remove
-- 
2.25.4


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 1/3] gdb: make thread_info::executing private
  2021-08-30 20:03 ` [PATCH 1/3] gdb: make thread_info::executing private Andrew Burgess
@ 2021-09-01 13:53   ` Simon Marchi via Gdb-patches
  2021-09-07 11:46     ` Andrew Burgess
  0 siblings, 1 reply; 30+ messages in thread
From: Simon Marchi via Gdb-patches @ 2021-09-01 13:53 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches

> @@ -841,24 +851,11 @@ set_running (process_stratum_target *targ, ptid_t ptid, bool running)
>      gdb::observers::target_resumed.notify (ptid);
>  }
>  
> -
> -/* Helper for set_executing.  Set's the thread's 'executing' field
> -   from EXECUTING, and if EXECUTING is true also clears the thread's
> -   stop_pc.  */

That comment should probably be moved to the set_executing
declaration, in the thread_info class.  The part about clearing stop_pc
is relevant to have there, I think.

Otherwise, LGTM.

Simon

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 2/3] gdb: make thread_suspend_state::stop_pc optional
  2021-08-30 20:03 ` [PATCH 2/3] gdb: make thread_suspend_state::stop_pc optional Andrew Burgess
@ 2021-09-01 14:23   ` Simon Marchi via Gdb-patches
  2021-09-07 13:21     ` Andrew Burgess
  0 siblings, 1 reply; 30+ messages in thread
From: Simon Marchi via Gdb-patches @ 2021-09-01 14:23 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches



On 2021-08-30 4:03 p.m., Andrew Burgess wrote:
> Currently the stop_pc field of thread_suspect_state is a CORE_ADDR and
> when we want to indicate that there is no stop_pc available we set
> this field back to a special value.
> 
> There are actually two special values used, in post_create_inferior
> the stop_pc is set to 0.  This is a little unfortunate, there are
> plenty of embedded targets where 0 is a valid pc address.  The more
> common special value for stop_pc was set in
> thread_info::set_executing, where the value (~(CORE_ADDR) 0) was used.
> 
> This commit changes things so that the stop_pc is instead a
> gdb::optional.  We can now explicitly reset the field to an
> uninitialised state, we also have (when compiling with _GLIBCXX_DEBUG
> defined) asserts that we don't read the stop_pc when its in an
> uninitialised state (see gdbsupport/gdb_optional.h).

Thanks, I think it's a good idea.

> One situation where a thread will not have a stop_pc value is when the
> thread is stopped as a consequence of GDB being in all stop mode, and
> some other thread stopped at an interesting event.  When GDB brings
> all the other threads to a stop those other threads will not have a
> stop_pc set (thus avoiding an unnecessary read of $pc).
> 
> Previously, when GDB passed through handle_one (in infrun.c) the
> threads executing flag was set to false and the stop_pc field was left
> unchanged, i.e. it would (previous) have been left as ~0.
> 
> Now, handle_one leaves the stop_pc with no value.
> 
> This caused a problem when we later try to set these threads running
> again, in proceed() we compare the current pc with the cached
> stop_pc.  If the thread was stopped in via handle_one then the stop_pc
> would have been left as ~0, and the compare (in proceed)
> would (likely) fail.  Now however, this compare tries to read the
> stop_pc when it has no value, this would trigger an assert.
> 
> To resolve this I've added thread_info::stop_pc_p() which returns true
> if the thread has a cached stop_pc.  We should only ever call
> thread_info::stop_pc() if we know that there is a cached stop_pc.

We could also make stop_pc return gdb::optional<CORE_ADDR>.  I think it
would be slightly better, since anybody calling stop_pc would see that
it returns an optional and be forced to consider that.  Otherwise, one
could call stop_pc and not know that stop_pc_p exists.  But otherwise
it's the same.

LGTM in any case.

Simon

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 3/3] gdb: make thread_info executing and resumed state more consistent
  2021-08-30 20:03 ` [PATCH 3/3] gdb: make thread_info executing and resumed state more consistent Andrew Burgess
@ 2021-09-01 15:09   ` Simon Marchi via Gdb-patches
  2021-09-22 11:21     ` Andrew Burgess
  2022-01-13 18:34   ` [PATCHv3] " Andrew Burgess via Gdb-patches
  1 sibling, 1 reply; 30+ messages in thread
From: Simon Marchi via Gdb-patches @ 2021-09-01 15:09 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches



On 2021-08-30 4:03 p.m., Andrew Burgess wrote:
> This commit was inspired by this comment from Simon:
> 
>   https://sourceware.org/pipermail/gdb-patches/2021-July/180694.html
> 
> The comment is about two thread_info flags m_executing and m_resumed.
> The m_resumed flag indicates that at the infrun level GDB has set the
> thread running, while the m_executing flag indicates that the thread
> is actually running at the target level.
> 
> It is very common that a thread can be m_resumed, but not m_executing,
> that is, core GDB thinks the thread is, or should be, running, but at
> the target level the thread isn't currently running.
> 
> The comment Simon made was in reply to a patch I posted where I found
> a case where a thread was marked m_executing, but not m_resumed, that
> is, at the infrun level GDB thought the thread was stopped, but at the
> target level the thread was actually running.  Simon suggests that
> this feels like an invalid state, and after thinking about it, I
> agree.
> 
> So, this commit adds some new asserts to GDB.  The core idea here is
> that the resumed and executing flags should only change in the
> following pattern, to begin with everything is set false:
> 
>   Resumed: false
>   Executing: false
> 
> Then infrun marks the thread resumed:
> 
>   Resumed: true
>   Executing: false
> 
> Then a target starts the thread executing:
> 
>   Resumed: true
>   Executing: true
> 
> The thread stops, the target spots this and marks the thread no longer
> executing:
> 
>   Resumed: true
>   Executing: false
> 
> And finally, infrun acknowledges that the thread is now no longer
> resumed:
> 
>   Resumed: false
>   Executing: false
> 
> Notice that at no point is resumed false, while executing is true.
> 
> And so we can add some asserts:
> 
>  1. The resumed flag should only change state when the executing flag
>  is false, and
> 
>  2. The executing flag should only change state when the resumed flag
>  is true.
> 
> I added these asserts and ....
> 
> .... it turns out these rules are broken all over the place in GDB, we
> have problems like:
> 
>  (a) When new threads appear they are marked executing, but not
>  resumed, and
> 
>  (b) In some places we mark a single thread as resumed, but then
>  actually set multiple threads executing.
> 
> For (a) it could be argued that this is a legitimate state - this is
> actually the problem I addressed in the original patch that Simon was
> replying too, however, we don't need to support this as a separate
> state, so if we can make this case follow the expected set of state
> transitions then it allows us to reduce the number of states that GDB
> can be in, which I think is a good thing.
> 
> Case (b) seems to just be a bug to me.

Did you consider collapsing the two fields (resumed and executing) into
a single one, with three states?  The names are silly, but as an
example:

enum class thread_resumption_state
{
  NOT_RESUMED,
  RESUMED_BUT_NOT_TARGET_RESUMED,
  RESUMED_AND_TARGET_RESUMED,
};

I think that would end up simpler than two booleans with rules.  But
since it would probably be a pretty big change, I will accept "nope" as
an answer.

> 
> The interesting changes in this commit then are:
> 
>   * gdbthread.h (set_stop_pc): Add assert that the stop_pc can only be
>   set when a thread is neither resumed, or executing.
> 
>   * infcmd.c (post_create_inferior): Ensure thread is non-resumed
>   before clearing the stop_pc.

Should clear_stop_pc have the same assertions as set_stop_pc?  I
guess you tried that and it didn't work?

> @@ -5616,6 +5668,9 @@ handle_inferior_event (struct execution_control_state *ecs)
>  	 execd thread for that case (this is a nop otherwise).  */
>        ecs->event_thread = inferior_thread ();
>  
> +      /* If we did select a new thread, make sure its non-resumed.  */
> +      ecs->event_thread->set_resumed (false);
> +

This one is in the TARGET_WAITKIND_EXECD handling... I'm wondering if it
should be target_ops::follow_exec's contract that any new thread of the
new inferior should be not resumed.  Because follow_exec is always
called in a context where the event thread on entry is not resumed.  So
it's not like new threads that are added in target_ops::wait, for
example.  For those, it makes sense to be added as resumed.

I think it would just mean adding a set_resumed (false) call in
process_stratum_target::follow_exec.  And possibly some assertions in
the follow_exec free function.  For example, I would add to the existing
assertions:

  /* If a new inferior was created, the target must have added at least
     one thread.  If the same inferior was used, we have left one
     thread.  */
  gdb_assert (!inf->thread_list.empty ());

  /* Any added thread must have been added in the not resumed state.  */
  for (thread_info *thread : inf->threads ())
    gdb_assert (!thread->resumed ());

PS: if taking into consideration my comment about the observer seeing
the correct resumed state, in add_thread_silent (below), then perhaps we
would need add_thread_silent to take a "resumed" parameter, so it can
set the right resumed state before calling the observer.

> diff --git a/gdb/thread.c b/gdb/thread.c
> index 10c3dcd6991..aceb233be80 100644
> --- a/gdb/thread.c
> +++ b/gdb/thread.c
> @@ -262,6 +262,13 @@ add_thread_silent (process_stratum_target *targ, ptid_t ptid)
>    tp = new_thread (inf, ptid);
>    gdb::observers::new_thread.notify (tp);
>  
> +  /* All threads are created in a resumed state, that is as soon as GDB
> +     sees a new thread it is expected to be running as far as the core of
> +     GDB is concerned.  At a target level the thread is probably stopped
> +     right now, hence the executing flag is left initialized to false.  */
> +  tp->set_resumed (true);
> +  gdb_assert (!tp->executing ());

I don't know if it matters, but should resumed be set before calling the
new_thread observer?  So that observers see the thread in the state we
intend it to be in?

Simon

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 1/3] gdb: make thread_info::executing private
  2021-09-01 13:53   ` Simon Marchi via Gdb-patches
@ 2021-09-07 11:46     ` Andrew Burgess
  0 siblings, 0 replies; 30+ messages in thread
From: Andrew Burgess @ 2021-09-07 11:46 UTC (permalink / raw)
  To: gdb-patches

* Simon Marchi <simon.marchi@polymtl.ca> [2021-09-01 09:53:31 -0400]:

> > @@ -841,24 +851,11 @@ set_running (process_stratum_target *targ, ptid_t ptid, bool running)
> >      gdb::observers::target_resumed.notify (ptid);
> >  }
> >  
> > -
> > -/* Helper for set_executing.  Set's the thread's 'executing' field
> > -   from EXECUTING, and if EXECUTING is true also clears the thread's
> > -   stop_pc.  */
> 
> That comment should probably be moved to the set_executing
> declaration, in the thread_info class.  The part about clearing stop_pc
> is relevant to have there, I think.

Thanks.  I made that change, and also added a comment onto the
declaration of set_resumed.

I pushed just this patch from this series, as this seems like a
reasonable cleanup on its own.

Below is what I pushed.

Thanks,
Andrew

---

commit 611841bb1afc689becfab6dd490e1799aabf547d
Author: Andrew Burgess <andrew.burgess@embecosm.com>
Date:   Tue Aug 10 11:20:44 2021 +0100

    gdb: make thread_info::executing private
    
    Rename thread_info::executing to thread_info::m_executing, and make it
    private.  Add a new get/set member functions, and convert GDB to make
    use of these.
    
    The only real change of interest in this patch is in thread.c where I
    have deleted the helper function set_executing_thread, and now just
    use the new set function thread_info::set_executing.  However, the old
    helper function set_executing_thread included some code to reset the
    thread's stop_pc, so I moved this code into the new function
    thread_info::set_executing.  However, I don't believe there is
    anywhere that this results in a change of behaviour, previously the
    executing flag was always set true through a call to
    set_executing_thread anyway.

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index f6c9683aecf..10b28c97be7 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -1661,7 +1661,7 @@ watchpoint_in_thread_scope (struct watchpoint *b)
   return (b->pspace == current_program_space
 	  && (b->watchpoint_thread == null_ptid
 	      || (inferior_ptid == b->watchpoint_thread
-		  && !inferior_thread ()->executing)));
+		  && !inferior_thread ()->executing ())));
 }
 
 /* Set watchpoint B to disp_del_at_next_stop, even including its possible
@@ -4512,7 +4512,7 @@ get_bpstat_thread ()
     return NULL;
 
   thread_info *tp = inferior_thread ();
-  if (tp->state == THREAD_EXITED || tp->executing)
+  if (tp->state == THREAD_EXITED || tp->executing ())
     return NULL;
   return tp;
 }
diff --git a/gdb/frame.c b/gdb/frame.c
index 4d7505f7ae3..d28944075ed 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -1789,7 +1789,7 @@ has_stack_frames ()
 	return false;
 
       /* ... or from a spinning thread.  */
-      if (tp->executing)
+      if (tp->executing ())
 	return false;
     }
 
diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index 9c178f531d9..e6f383cca61 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -287,15 +287,19 @@ class thread_info : public refcounted_object,
      if the thread does not have a user-given name.  */
   char *name = NULL;
 
-  /* True means the thread is executing.  Note: this is different
-     from saying that there is an active target and we are stopped at
-     a breakpoint, for instance.  This is a real indicator whether the
-     thread is off and running.  */
-  bool executing = false;
+  bool executing () const
+  { return m_executing; }
+
+  /* Set the thread's 'm_executing' field from EXECUTING, and if EXECUTING
+     is true also clears the thread's stop_pc.  */
+  void set_executing (bool executing);
 
   bool resumed () const
   { return m_resumed; }
 
+  /* Set the thread's 'm_resumed' field from RESUMED.  The thread may also
+     be added to (when RESUMED is true), or removed from (when RESUMED is
+     false), the list of threads with a pending wait status.  */
   void set_resumed (bool resumed);
 
   /* Frontend view of the thread state.  Note that the THREAD_RUNNING/
@@ -488,6 +492,12 @@ class thread_info : public refcounted_object,
      the thread run.  */
   bool m_resumed = false;
 
+  /* True means the thread is executing.  Note: this is different
+     from saying that there is an active target and we are stopped at
+     a breakpoint, for instance.  This is a real indicator whether the
+     thread is off and running.  */
+  bool m_executing = false;
+
   /* State of inferior thread to restore after GDB is done with an inferior
      call.  See `struct thread_suspend_state'.  */
   thread_suspend_state m_suspend;
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index c183b60e81a..e6ee49bc43d 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -2371,7 +2371,7 @@ proceed_after_attach (inferior *inf)
   scoped_restore_current_thread restore_thread;
 
   for (thread_info *thread : inf->non_exited_threads ())
-    if (!thread->executing
+    if (!thread->executing ()
 	&& !thread->stop_requested
 	&& thread->stop_signal () == GDB_SIGNAL_0)
       {
@@ -2644,7 +2644,7 @@ notice_new_inferior (thread_info *thr, bool leave_running, int from_tty)
   /* When we "notice" a new inferior we need to do all the things we
      would normally do if we had just attached to it.  */
 
-  if (thr->executing)
+  if (thr->executing ())
     {
       struct inferior *inferior = current_inferior ();
 
diff --git a/gdb/inflow.c b/gdb/inflow.c
index 74dda702a8a..bcab66487b0 100644
--- a/gdb/inflow.c
+++ b/gdb/inflow.c
@@ -525,7 +525,7 @@ child_interrupt (struct target_ops *self)
   thread_info *resumed = NULL;
   for (thread_info *thr : all_non_exited_threads ())
     {
-      if (thr->executing)
+      if (thr->executing ())
 	{
 	  resumed = thr;
 	  break;
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 694bbe665f4..8e778576eab 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -862,7 +862,7 @@ static void
 proceed_after_vfork_done (thread_info *thread)
 {
   if (thread->state == THREAD_RUNNING
-      && !thread->executing
+      && !thread->executing ()
       && !thread->stop_requested
       && thread->stop_signal () == GDB_SIGNAL_0)
     {
@@ -1885,7 +1885,7 @@ start_step_over (void)
 
       if (tp->control.trap_expected
 	  || tp->resumed ()
-	  || tp->executing)
+	  || tp->executing ())
 	{
 	  internal_error (__FILE__, __LINE__,
 			  "[%s] has inconsistent state: "
@@ -1893,7 +1893,7 @@ start_step_over (void)
 			  target_pid_to_str (tp->ptid).c_str (),
 			  tp->control.trap_expected,
 			  tp->resumed (),
-			  tp->executing);
+			  tp->executing ());
 	}
 
       infrun_debug_printf ("resuming [%s] for step-over",
@@ -3197,7 +3197,7 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
 	      {
 		infrun_debug_printf ("[%s] resumed",
 				     target_pid_to_str (tp->ptid).c_str ());
-		gdb_assert (tp->executing || tp->has_pending_waitstatus ());
+		gdb_assert (tp->executing () || tp->has_pending_waitstatus ());
 		continue;
 	      }
 
@@ -3329,7 +3329,7 @@ infrun_thread_stop_requested (ptid_t ptid)
     {
       if (tp->state != THREAD_RUNNING)
 	continue;
-      if (tp->executing)
+      if (tp->executing ())
 	continue;
 
       /* Remove matching threads from the step-over queue, so
@@ -3778,7 +3778,7 @@ prepare_for_detach (void)
 	{
 	  if (thr->displaced_step_state.in_progress ())
 	    {
-	      if (thr->executing)
+	      if (thr->executing ())
 		{
 		  if (!thr->stop_requested)
 		    {
@@ -4806,7 +4806,7 @@ handle_one (const wait_one_event &event)
 	t = add_thread (event.target, event.ptid);
 
       t->stop_requested = 0;
-      t->executing = 0;
+      t->set_executing (false);
       t->set_resumed (false);
       t->control.may_range_step = 0;
 
@@ -4947,7 +4947,7 @@ stop_all_threads (void)
 	      if (!target_is_non_stop_p ())
 		continue;
 
-	      if (t->executing)
+	      if (t->executing ())
 		{
 		  /* If already stopping, don't request a stop again.
 		     We just haven't seen the notification yet.  */
@@ -5091,7 +5091,7 @@ handle_no_resumed (struct execution_control_state *ecs)
 
   for (thread_info *thread : all_non_exited_threads ())
     {
-      if (swap_terminal && thread->executing)
+      if (swap_terminal && thread->executing ())
 	{
 	  if (thread->inf != curr_inf)
 	    {
@@ -5104,7 +5104,7 @@ handle_no_resumed (struct execution_control_state *ecs)
 	}
 
       if (!ignore_event
-	  && (thread->executing || thread->has_pending_waitstatus ()))
+	  && (thread->executing () || thread->has_pending_waitstatus ()))
 	{
 	  /* Either there were no unwaited-for children left in the
 	     target at some point, but there are now, or some target
@@ -5722,7 +5722,7 @@ restart_threads (struct thread_info *event_thread)
 	{
 	  infrun_debug_printf ("restart threads: [%s] resumed",
 			      target_pid_to_str (tp->ptid).c_str ());
-	  gdb_assert (tp->executing || tp->has_pending_waitstatus ());
+	  gdb_assert (tp->executing () || tp->has_pending_waitstatus ());
 	  continue;
 	}
 
@@ -5869,7 +5869,7 @@ finish_step_over (struct execution_control_state *ecs)
 	     do_target_wait.  */
 	  tp->set_resumed (true);
 
-	  gdb_assert (!tp->executing);
+	  gdb_assert (!tp->executing ());
 
 	  regcache = get_thread_regcache (tp);
 	  tp->set_stop_pc (regcache_read_pc (regcache));
@@ -7419,7 +7419,7 @@ restart_after_all_stop_detach (process_stratum_target *proc_target)
       /* If we have any thread that is already executing, then we
 	 don't need to resume the target -- it is already been
 	 resumed.  */
-      if (thr->executing)
+      if (thr->executing ())
 	return;
 
       /* If we have a pending event to process, skip resuming the
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index e9433b2206b..29ca62d2bc1 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -1280,7 +1280,7 @@ get_detach_signal (struct lwp_info *lp)
     {
       struct thread_info *tp = find_thread_ptid (linux_target, lp->ptid);
 
-      if (target_is_non_stop_p () && !tp->executing)
+      if (target_is_non_stop_p () && !tp->executing ())
 	{
 	  if (tp->has_pending_waitstatus ())
 	    signo = tp->pending_waitstatus ().value.sig;
diff --git a/gdb/linux-thread-db.c b/gdb/linux-thread-db.c
index eb2aa5ac409..245939b6400 100644
--- a/gdb/linux-thread-db.c
+++ b/gdb/linux-thread-db.c
@@ -1641,7 +1641,7 @@ thread_db_target::update_thread_list ()
 	continue;
 
       thread_info *thread = any_live_thread_of_inferior (inf);
-      if (thread == NULL || thread->executing)
+      if (thread == NULL || thread->executing ())
 	continue;
 
       /* It's best to avoid td_ta_thr_iter if possible.  That walks
diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index 85e357e604a..e2b9866d68a 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -1998,7 +1998,7 @@ get_thread_current_frame_id (struct thread_info *tp)
      For the former, EXECUTING is true and we're in wait, about to
      move the thread.  Since we need to recompute the stack, we temporarily
      set EXECUTING to false.  */
-  executing = tp->executing;
+  executing = tp->executing ();
   set_executing (proc_target, inferior_ptid, false);
 
   id = null_frame_id;
diff --git a/gdb/target.c b/gdb/target.c
index ae2d659583e..d1c1bf523ed 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -3815,7 +3815,7 @@ target_pass_ctrlc (void)
 	{
 	  /* A thread can be THREAD_STOPPED and executing, while
 	     running an infcall.  */
-	  if (thr->state == THREAD_RUNNING || thr->executing)
+	  if (thr->state == THREAD_RUNNING || thr->executing ())
 	    {
 	      /* We can get here quite deep in target layers.  Avoid
 		 switching thread context or anything that would
diff --git a/gdb/thread.c b/gdb/thread.c
index a82fb49140a..c95a9186681 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -319,6 +319,16 @@ thread_info::deletable () const
 
 /* See gdbthread.h.  */
 
+void
+thread_info::set_executing (bool executing)
+{
+  m_executing = executing;
+  if (executing)
+    this->set_stop_pc (~(CORE_ADDR) 0);
+}
+
+/* See gdbthread.h.  */
+
 void
 thread_info::set_resumed (bool resumed)
 {
@@ -625,13 +635,13 @@ any_live_thread_of_inferior (inferior *inf)
       curr_tp = inferior_thread ();
       if (curr_tp->state == THREAD_EXITED)
 	curr_tp = NULL;
-      else if (!curr_tp->executing)
+      else if (!curr_tp->executing ())
 	return curr_tp;
     }
 
   for (thread_info *tp : inf->non_exited_threads ())
     {
-      if (!tp->executing)
+      if (!tp->executing ())
 	return tp;
 
       tp_executing = tp;
@@ -841,24 +851,11 @@ set_running (process_stratum_target *targ, ptid_t ptid, bool running)
     gdb::observers::target_resumed.notify (ptid);
 }
 
-
-/* Helper for set_executing.  Set's the thread's 'executing' field
-   from EXECUTING, and if EXECUTING is true also clears the thread's
-   stop_pc.  */
-
-static void
-set_executing_thread (thread_info *thr, bool executing)
-{
-  thr->executing = executing;
-  if (executing)
-    thr->set_stop_pc (~(CORE_ADDR) 0);
-}
-
 void
 set_executing (process_stratum_target *targ, ptid_t ptid, bool executing)
 {
   for (thread_info *tp : all_non_exited_threads (targ, ptid))
-    set_executing_thread (tp, executing);
+    tp->set_executing (executing);
 
   /* It only takes one running thread to spawn more threads.  */
   if (executing)
@@ -895,7 +892,7 @@ finish_thread_state (process_stratum_target *targ, ptid_t ptid)
   bool any_started = false;
 
   for (thread_info *tp : all_non_exited_threads (targ, ptid))
-    if (set_running_thread (tp, tp->executing))
+    if (set_running_thread (tp, tp->executing ()))
       any_started = true;
 
   if (any_started)
@@ -922,7 +919,7 @@ validate_registers_access (void)
      at the prompt) when a thread is not executing for some internal
      reason, but is marked running from the user's perspective.  E.g.,
      the thread is waiting for its turn in the step-over queue.  */
-  if (tp->executing)
+  if (tp->executing ())
     error (_("Selected thread is running."));
 }
 
@@ -940,7 +937,7 @@ can_access_registers_thread (thread_info *thread)
     return false;
 
   /* ... or from a spinning thread.  FIXME: see validate_registers_access.  */
-  if (thread->executing)
+  if (thread->executing ())
     return false;
 
   return true;
@@ -1997,7 +1994,7 @@ update_threads_executing (void)
 
       for (thread_info *tp : inf->non_exited_threads ())
 	{
-	  if (tp->executing)
+	  if (tp->executing ())
 	    {
 	      targ->threads_executing = true;
 	      return;

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 2/3] gdb: make thread_suspend_state::stop_pc optional
  2021-09-01 14:23   ` Simon Marchi via Gdb-patches
@ 2021-09-07 13:21     ` Andrew Burgess
  2021-09-07 14:10       ` Simon Marchi via Gdb-patches
  0 siblings, 1 reply; 30+ messages in thread
From: Andrew Burgess @ 2021-09-07 13:21 UTC (permalink / raw)
  To: Simon Marchi; +Cc: gdb-patches

* Simon Marchi <simon.marchi@polymtl.ca> [2021-09-01 10:23:32 -0400]:

> 
> 
> On 2021-08-30 4:03 p.m., Andrew Burgess wrote:
> > Currently the stop_pc field of thread_suspect_state is a CORE_ADDR and
> > when we want to indicate that there is no stop_pc available we set
> > this field back to a special value.
> > 
> > There are actually two special values used, in post_create_inferior
> > the stop_pc is set to 0.  This is a little unfortunate, there are
> > plenty of embedded targets where 0 is a valid pc address.  The more
> > common special value for stop_pc was set in
> > thread_info::set_executing, where the value (~(CORE_ADDR) 0) was used.
> > 
> > This commit changes things so that the stop_pc is instead a
> > gdb::optional.  We can now explicitly reset the field to an
> > uninitialised state, we also have (when compiling with _GLIBCXX_DEBUG
> > defined) asserts that we don't read the stop_pc when its in an
> > uninitialised state (see gdbsupport/gdb_optional.h).
> 
> Thanks, I think it's a good idea.
> 
> > One situation where a thread will not have a stop_pc value is when the
> > thread is stopped as a consequence of GDB being in all stop mode, and
> > some other thread stopped at an interesting event.  When GDB brings
> > all the other threads to a stop those other threads will not have a
> > stop_pc set (thus avoiding an unnecessary read of $pc).
> > 
> > Previously, when GDB passed through handle_one (in infrun.c) the
> > threads executing flag was set to false and the stop_pc field was left
> > unchanged, i.e. it would (previous) have been left as ~0.
> > 
> > Now, handle_one leaves the stop_pc with no value.
> > 
> > This caused a problem when we later try to set these threads running
> > again, in proceed() we compare the current pc with the cached
> > stop_pc.  If the thread was stopped in via handle_one then the stop_pc
> > would have been left as ~0, and the compare (in proceed)
> > would (likely) fail.  Now however, this compare tries to read the
> > stop_pc when it has no value, this would trigger an assert.
> > 
> > To resolve this I've added thread_info::stop_pc_p() which returns true
> > if the thread has a cached stop_pc.  We should only ever call
> > thread_info::stop_pc() if we know that there is a cached stop_pc.
> 
> We could also make stop_pc return gdb::optional<CORE_ADDR>.  I think it
> would be slightly better, since anybody calling stop_pc would see that
> it returns an optional and be forced to consider that.  Otherwise, one
> could call stop_pc and not know that stop_pc_p exists.  But otherwise
> it's the same.

I did consider that initially, but most of the places where
thread_info::stop_pc is called the value is being immediately passed
through to some other function, here's an example pulled randomly from
infrun.c:

      ecs->event_thread->control.stop_bpstat
	= bpstat_stop_status (get_current_regcache ()->aspace (),
			      ecs->event_thread->stop_pc (),
			      ecs->event_thread, &ecs->ws);

if we are returned a gdb::optional<> then we might change the code to
do this:

      ecs->event_thread->control.stop_bpstat
	= bpstat_stop_status (get_current_regcache ()->aspace (),
			      *ecs->event_thread->stop_pc (),
			      ecs->event_thread, &ecs->ws);

Or maybe, like this:

      auto stop_pc = ecs->event_thread->stop_pc ();
      gdb_assert (stop_pc.has_value ());
      ecs->event_thread->control.stop_bpstat
	= bpstat_stop_status (get_current_regcache ()->aspace (),
			      *stop_pc,
			      ecs->event_thread, &ecs->ws);

In the first case, it doesn't feel like we've gained much over my
patch, where thead_info::stop_pc() accesses the value for us.
Further, once we've normalised the pattern of accessing the stop_pc as
`*ecs->event_thread->stop_pc ()`, I worry people still wouldn't
actually consider whether the stop_pc value was valid or not, they'd
just duplicate the existing code.

The second case seems excessively verbose, so much so, that you might
even be tempted to write a wrapper, say thread_info::stop_pc_value(),
which kind lands us back on my original patch...

Initially, I'd relied on the asserts within gdb::optional to ensure
that we didn't access the stop_pc when it had no value, but these
asserts are only present when compiling with _GLIBCXX_DEBUG defined -
I do this, but it's certainly not going to be standard in a release
build of GDB.  So, I wonder if this would be a good change:

  /* Return this thread's stop PC.  This should only be called when it is
     known that stop_pc has a value.  If this function is being used in a
     situation where a thread may not have had a stop_pc assigned, then
     stop_pc_p() can be used to check if the stop_pc is defined.  */

  CORE_ADDR stop_pc () const
  {
    gdb_assert (m_suspend.stop_pc.has_value ());
    return *m_suspend.stop_pc;
  }

I've (a) extended the comment to mention stop_pc_p(), and added an
assert that the stop_pc has a value.  Given that (currently) all
builds of GDB do check assertions, this should hopefully make it much
more likely that if someone does access stop_pc when they shouldn't
then GDB will rapidly point this out to them.

What are your thoughts?

Thanks,
Andrew

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 2/3] gdb: make thread_suspend_state::stop_pc optional
  2021-09-07 13:21     ` Andrew Burgess
@ 2021-09-07 14:10       ` Simon Marchi via Gdb-patches
  2021-09-08  9:50         ` Andrew Burgess
  0 siblings, 1 reply; 30+ messages in thread
From: Simon Marchi via Gdb-patches @ 2021-09-07 14:10 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches

On 2021-09-07 9:21 a.m., Andrew Burgess wrote:
> * Simon Marchi <simon.marchi@polymtl.ca> [2021-09-01 10:23:32 -0400]:
> 
>>
>>
>> On 2021-08-30 4:03 p.m., Andrew Burgess wrote:
>>> Currently the stop_pc field of thread_suspect_state is a CORE_ADDR and
>>> when we want to indicate that there is no stop_pc available we set
>>> this field back to a special value.
>>>
>>> There are actually two special values used, in post_create_inferior
>>> the stop_pc is set to 0.  This is a little unfortunate, there are
>>> plenty of embedded targets where 0 is a valid pc address.  The more
>>> common special value for stop_pc was set in
>>> thread_info::set_executing, where the value (~(CORE_ADDR) 0) was used.
>>>
>>> This commit changes things so that the stop_pc is instead a
>>> gdb::optional.  We can now explicitly reset the field to an
>>> uninitialised state, we also have (when compiling with _GLIBCXX_DEBUG
>>> defined) asserts that we don't read the stop_pc when its in an
>>> uninitialised state (see gdbsupport/gdb_optional.h).
>>
>> Thanks, I think it's a good idea.
>>
>>> One situation where a thread will not have a stop_pc value is when the
>>> thread is stopped as a consequence of GDB being in all stop mode, and
>>> some other thread stopped at an interesting event.  When GDB brings
>>> all the other threads to a stop those other threads will not have a
>>> stop_pc set (thus avoiding an unnecessary read of $pc).
>>>
>>> Previously, when GDB passed through handle_one (in infrun.c) the
>>> threads executing flag was set to false and the stop_pc field was left
>>> unchanged, i.e. it would (previous) have been left as ~0.
>>>
>>> Now, handle_one leaves the stop_pc with no value.
>>>
>>> This caused a problem when we later try to set these threads running
>>> again, in proceed() we compare the current pc with the cached
>>> stop_pc.  If the thread was stopped in via handle_one then the stop_pc
>>> would have been left as ~0, and the compare (in proceed)
>>> would (likely) fail.  Now however, this compare tries to read the
>>> stop_pc when it has no value, this would trigger an assert.
>>>
>>> To resolve this I've added thread_info::stop_pc_p() which returns true
>>> if the thread has a cached stop_pc.  We should only ever call
>>> thread_info::stop_pc() if we know that there is a cached stop_pc.
>>
>> We could also make stop_pc return gdb::optional<CORE_ADDR>.  I think it
>> would be slightly better, since anybody calling stop_pc would see that
>> it returns an optional and be forced to consider that.  Otherwise, one
>> could call stop_pc and not know that stop_pc_p exists.  But otherwise
>> it's the same.
> 
> I did consider that initially, but most of the places where
> thread_info::stop_pc is called the value is being immediately passed
> through to some other function, here's an example pulled randomly from
> infrun.c:
> 
>       ecs->event_thread->control.stop_bpstat
> 	= bpstat_stop_status (get_current_regcache ()->aspace (),
> 			      ecs->event_thread->stop_pc (),
> 			      ecs->event_thread, &ecs->ws);
> 
> if we are returned a gdb::optional<> then we might change the code to
> do this:
> 
>       ecs->event_thread->control.stop_bpstat
> 	= bpstat_stop_status (get_current_regcache ()->aspace (),
> 			      *ecs->event_thread->stop_pc (),
> 			      ecs->event_thread, &ecs->ws);
> 
> Or maybe, like this:
> 
>       auto stop_pc = ecs->event_thread->stop_pc ();
>       gdb_assert (stop_pc.has_value ());
>       ecs->event_thread->control.stop_bpstat
> 	= bpstat_stop_status (get_current_regcache ()->aspace (),
> 			      *stop_pc,
> 			      ecs->event_thread, &ecs->ws);
> 
> In the first case, it doesn't feel like we've gained much over my
> patch, where thead_info::stop_pc() accesses the value for us.
> Further, once we've normalised the pattern of accessing the stop_pc as
> `*ecs->event_thread->stop_pc ()`, I worry people still wouldn't
> actually consider whether the stop_pc value was valid or not, they'd
> just duplicate the existing code.
> 
> The second case seems excessively verbose, so much so, that you might
> even be tempted to write a wrapper, say thread_info::stop_pc_value(),
> which kind lands us back on my original patch...
> 
> Initially, I'd relied on the asserts within gdb::optional to ensure
> that we didn't access the stop_pc when it had no value, but these
> asserts are only present when compiling with _GLIBCXX_DEBUG defined -
> I do this, but it's certainly not going to be standard in a release
> build of GDB.  So, I wonder if this would be a good change:
> 
>   /* Return this thread's stop PC.  This should only be called when it is
>      known that stop_pc has a value.  If this function is being used in a
>      situation where a thread may not have had a stop_pc assigned, then
>      stop_pc_p() can be used to check if the stop_pc is defined.  */
> 
>   CORE_ADDR stop_pc () const
>   {
>     gdb_assert (m_suspend.stop_pc.has_value ());
>     return *m_suspend.stop_pc;
>   }

That one looks good to me, stating preconditions in the documentation
and enforcing them using assertions.  That's similar to how I designed
other things, like dynamic_prop.

Simon

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 2/3] gdb: make thread_suspend_state::stop_pc optional
  2021-09-07 14:10       ` Simon Marchi via Gdb-patches
@ 2021-09-08  9:50         ` Andrew Burgess
  0 siblings, 0 replies; 30+ messages in thread
From: Andrew Burgess @ 2021-09-08  9:50 UTC (permalink / raw)
  To: Simon Marchi; +Cc: gdb-patches

* Simon Marchi <simon.marchi@polymtl.ca> [2021-09-07 10:10:07 -0400]:

> On 2021-09-07 9:21 a.m., Andrew Burgess wrote:
> > * Simon Marchi <simon.marchi@polymtl.ca> [2021-09-01 10:23:32 -0400]:
> > 
> >>
> >>
> >> On 2021-08-30 4:03 p.m., Andrew Burgess wrote:
> >>> Currently the stop_pc field of thread_suspect_state is a CORE_ADDR and
> >>> when we want to indicate that there is no stop_pc available we set
> >>> this field back to a special value.
> >>>
> >>> There are actually two special values used, in post_create_inferior
> >>> the stop_pc is set to 0.  This is a little unfortunate, there are
> >>> plenty of embedded targets where 0 is a valid pc address.  The more
> >>> common special value for stop_pc was set in
> >>> thread_info::set_executing, where the value (~(CORE_ADDR) 0) was used.
> >>>
> >>> This commit changes things so that the stop_pc is instead a
> >>> gdb::optional.  We can now explicitly reset the field to an
> >>> uninitialised state, we also have (when compiling with _GLIBCXX_DEBUG
> >>> defined) asserts that we don't read the stop_pc when its in an
> >>> uninitialised state (see gdbsupport/gdb_optional.h).
> >>
> >> Thanks, I think it's a good idea.
> >>
> >>> One situation where a thread will not have a stop_pc value is when the
> >>> thread is stopped as a consequence of GDB being in all stop mode, and
> >>> some other thread stopped at an interesting event.  When GDB brings
> >>> all the other threads to a stop those other threads will not have a
> >>> stop_pc set (thus avoiding an unnecessary read of $pc).
> >>>
> >>> Previously, when GDB passed through handle_one (in infrun.c) the
> >>> threads executing flag was set to false and the stop_pc field was left
> >>> unchanged, i.e. it would (previous) have been left as ~0.
> >>>
> >>> Now, handle_one leaves the stop_pc with no value.
> >>>
> >>> This caused a problem when we later try to set these threads running
> >>> again, in proceed() we compare the current pc with the cached
> >>> stop_pc.  If the thread was stopped in via handle_one then the stop_pc
> >>> would have been left as ~0, and the compare (in proceed)
> >>> would (likely) fail.  Now however, this compare tries to read the
> >>> stop_pc when it has no value, this would trigger an assert.
> >>>
> >>> To resolve this I've added thread_info::stop_pc_p() which returns true
> >>> if the thread has a cached stop_pc.  We should only ever call
> >>> thread_info::stop_pc() if we know that there is a cached stop_pc.
> >>
> >> We could also make stop_pc return gdb::optional<CORE_ADDR>.  I think it
> >> would be slightly better, since anybody calling stop_pc would see that
> >> it returns an optional and be forced to consider that.  Otherwise, one
> >> could call stop_pc and not know that stop_pc_p exists.  But otherwise
> >> it's the same.
> > 
> > I did consider that initially, but most of the places where
> > thread_info::stop_pc is called the value is being immediately passed
> > through to some other function, here's an example pulled randomly from
> > infrun.c:
> > 
> >       ecs->event_thread->control.stop_bpstat
> > 	= bpstat_stop_status (get_current_regcache ()->aspace (),
> > 			      ecs->event_thread->stop_pc (),
> > 			      ecs->event_thread, &ecs->ws);
> > 
> > if we are returned a gdb::optional<> then we might change the code to
> > do this:
> > 
> >       ecs->event_thread->control.stop_bpstat
> > 	= bpstat_stop_status (get_current_regcache ()->aspace (),
> > 			      *ecs->event_thread->stop_pc (),
> > 			      ecs->event_thread, &ecs->ws);
> > 
> > Or maybe, like this:
> > 
> >       auto stop_pc = ecs->event_thread->stop_pc ();
> >       gdb_assert (stop_pc.has_value ());
> >       ecs->event_thread->control.stop_bpstat
> > 	= bpstat_stop_status (get_current_regcache ()->aspace (),
> > 			      *stop_pc,
> > 			      ecs->event_thread, &ecs->ws);
> > 
> > In the first case, it doesn't feel like we've gained much over my
> > patch, where thead_info::stop_pc() accesses the value for us.
> > Further, once we've normalised the pattern of accessing the stop_pc as
> > `*ecs->event_thread->stop_pc ()`, I worry people still wouldn't
> > actually consider whether the stop_pc value was valid or not, they'd
> > just duplicate the existing code.
> > 
> > The second case seems excessively verbose, so much so, that you might
> > even be tempted to write a wrapper, say thread_info::stop_pc_value(),
> > which kind lands us back on my original patch...
> > 
> > Initially, I'd relied on the asserts within gdb::optional to ensure
> > that we didn't access the stop_pc when it had no value, but these
> > asserts are only present when compiling with _GLIBCXX_DEBUG defined -
> > I do this, but it's certainly not going to be standard in a release
> > build of GDB.  So, I wonder if this would be a good change:
> > 
> >   /* Return this thread's stop PC.  This should only be called when it is
> >      known that stop_pc has a value.  If this function is being used in a
> >      situation where a thread may not have had a stop_pc assigned, then
> >      stop_pc_p() can be used to check if the stop_pc is defined.  */
> > 
> >   CORE_ADDR stop_pc () const
> >   {
> >     gdb_assert (m_suspend.stop_pc.has_value ());
> >     return *m_suspend.stop_pc;
> >   }
> 
> That one looks good to me, stating preconditions in the documentation
> and enforcing them using assertions.  That's similar to how I designed
> other things, like dynamic_prop.
> 
> Simon

Thanks, I pushed this patch with that change in place.

Andrew

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 3/3] gdb: make thread_info executing and resumed state more consistent
  2021-09-01 15:09   ` Simon Marchi via Gdb-patches
@ 2021-09-22 11:21     ` Andrew Burgess
  2021-09-23 17:14       ` Simon Marchi via Gdb-patches
  0 siblings, 1 reply; 30+ messages in thread
From: Andrew Burgess @ 2021-09-22 11:21 UTC (permalink / raw)
  To: gdb-patches

* Simon Marchi <simon.marchi@polymtl.ca> [2021-09-01 11:09:31 -0400]:

> 
> 
> On 2021-08-30 4:03 p.m., Andrew Burgess wrote:
> > This commit was inspired by this comment from Simon:
> > 
> >   https://sourceware.org/pipermail/gdb-patches/2021-July/180694.html
> > 
> > The comment is about two thread_info flags m_executing and m_resumed.
> > The m_resumed flag indicates that at the infrun level GDB has set the
> > thread running, while the m_executing flag indicates that the thread
> > is actually running at the target level.
> > 
> > It is very common that a thread can be m_resumed, but not m_executing,
> > that is, core GDB thinks the thread is, or should be, running, but at
> > the target level the thread isn't currently running.
> > 
> > The comment Simon made was in reply to a patch I posted where I found
> > a case where a thread was marked m_executing, but not m_resumed, that
> > is, at the infrun level GDB thought the thread was stopped, but at the
> > target level the thread was actually running.  Simon suggests that
> > this feels like an invalid state, and after thinking about it, I
> > agree.
> > 
> > So, this commit adds some new asserts to GDB.  The core idea here is
> > that the resumed and executing flags should only change in the
> > following pattern, to begin with everything is set false:
> > 
> >   Resumed: false
> >   Executing: false
> > 
> > Then infrun marks the thread resumed:
> > 
> >   Resumed: true
> >   Executing: false
> > 
> > Then a target starts the thread executing:
> > 
> >   Resumed: true
> >   Executing: true
> > 
> > The thread stops, the target spots this and marks the thread no longer
> > executing:
> > 
> >   Resumed: true
> >   Executing: false
> > 
> > And finally, infrun acknowledges that the thread is now no longer
> > resumed:
> > 
> >   Resumed: false
> >   Executing: false
> > 
> > Notice that at no point is resumed false, while executing is true.
> > 
> > And so we can add some asserts:
> > 
> >  1. The resumed flag should only change state when the executing flag
> >  is false, and
> > 
> >  2. The executing flag should only change state when the resumed flag
> >  is true.
> > 
> > I added these asserts and ....
> > 
> > .... it turns out these rules are broken all over the place in GDB, we
> > have problems like:
> > 
> >  (a) When new threads appear they are marked executing, but not
> >  resumed, and
> > 
> >  (b) In some places we mark a single thread as resumed, but then
> >  actually set multiple threads executing.
> > 
> > For (a) it could be argued that this is a legitimate state - this is
> > actually the problem I addressed in the original patch that Simon was
> > replying too, however, we don't need to support this as a separate
> > state, so if we can make this case follow the expected set of state
> > transitions then it allows us to reduce the number of states that GDB
> > can be in, which I think is a good thing.
> > 
> > Case (b) seems to just be a bug to me.
> 
> Did you consider collapsing the two fields (resumed and executing) into
> a single one, with three states?  The names are silly, but as an
> example:
> 
> enum class thread_resumption_state
> {
>   NOT_RESUMED,
>   RESUMED_BUT_NOT_TARGET_RESUMED,
>   RESUMED_AND_TARGET_RESUMED,
> };
> 
> I think that would end up simpler than two booleans with rules.  But
> since it would probably be a pretty big change, I will accept "nope" as
> an answer.

I did think about this, but I guess I'm not quite sure how this ends
up being any simpler than the two booleans with rules.

My assumption is that we'd want to keep the API as
executing/set_executing and resumed/set_resumed as this represents the
questions we want to ask.

As such something like set_executing would become:

  void
  thread_info::set_executing (bool e)
  {
    if (m_state == RESUMED_AND_TARGET_RESUMED)
      return;

    gdb_assert (m_state == RESUMED_BUT_NOT_TARGET_RESUMED);

    m_state = RESUMED_AND_TARGET_RESUMED;
  }

Which doesn't feel any less complex to me.

Of course, we could change the API so the user sets the state
directly, like:

  void
  thread_info_::set_executing_resumed_state (enum state_type s)
  {
    /* ... */
  }

But then we'd _still_ end up having to assert the correct state
transitions.

Maybe I'm just not understanding what you're suggesting though...

> 
> > 
> > The interesting changes in this commit then are:
> > 
> >   * gdbthread.h (set_stop_pc): Add assert that the stop_pc can only be
> >   set when a thread is neither resumed, or executing.
> > 
> >   * infcmd.c (post_create_inferior): Ensure thread is non-resumed
> >   before clearing the stop_pc.
> 
> Should clear_stop_pc have the same assertions as set_stop_pc?  I
> guess you tried that and it didn't work?

I've added these in the new patch.

> 
> > @@ -5616,6 +5668,9 @@ handle_inferior_event (struct execution_control_state *ecs)
> >  	 execd thread for that case (this is a nop otherwise).  */
> >        ecs->event_thread = inferior_thread ();
> >  
> > +      /* If we did select a new thread, make sure its non-resumed.  */
> > +      ecs->event_thread->set_resumed (false);
> > +
> 
> This one is in the TARGET_WAITKIND_EXECD handling... I'm wondering if it
> should be target_ops::follow_exec's contract that any new thread of the
> new inferior should be not resumed.  Because follow_exec is always
> called in a context where the event thread on entry is not resumed.  So
> it's not like new threads that are added in target_ops::wait, for
> example.  For those, it makes sense to be added as resumed.
> 
> I think it would just mean adding a set_resumed (false) call in
> process_stratum_target::follow_exec.  And possibly some assertions in
> the follow_exec free function.  For example, I would add to the existing
> assertions:
> 
>   /* If a new inferior was created, the target must have added at least
>      one thread.  If the same inferior was used, we have left one
>      thread.  */
>   gdb_assert (!inf->thread_list.empty ());
> 
>   /* Any added thread must have been added in the not resumed state.  */
>   for (thread_info *thread : inf->threads ())
>     gdb_assert (!thread->resumed ());
> 
> PS: if taking into consideration my comment about the observer seeing
> the correct resumed state, in add_thread_silent (below), then perhaps we
> would need add_thread_silent to take a "resumed" parameter, so it can
> set the right resumed state before calling the observer.

I think I've addressed all of this in the new patch below.  The thread
coming out of ::follow_exec should now be non-resumed.

> 
> > diff --git a/gdb/thread.c b/gdb/thread.c
> > index 10c3dcd6991..aceb233be80 100644
> > --- a/gdb/thread.c
> > +++ b/gdb/thread.c
> > @@ -262,6 +262,13 @@ add_thread_silent (process_stratum_target *targ, ptid_t ptid)
> >    tp = new_thread (inf, ptid);
> >    gdb::observers::new_thread.notify (tp);
> >  
> > +  /* All threads are created in a resumed state, that is as soon as GDB
> > +     sees a new thread it is expected to be running as far as the core of
> > +     GDB is concerned.  At a target level the thread is probably stopped
> > +     right now, hence the executing flag is left initialized to false.  */
> > +  tp->set_resumed (true);
> > +  gdb_assert (!tp->executing ());
> 
> I don't know if it matters, but should resumed be set before calling the
> new_thread observer?  So that observers see the thread in the state we
> intend it to be in?

I checked, and as far as I can tell it doesn't currently matter, but I
agree we should try to do the right thing here, so I've changed this
in the new patch version.

Below is V2 of this patch.  There's a lot of change since V1.

 - The add_thread* calls now take a flag, and threads can be started
   as resumed or non-resumed.

 - Some of the state changes, like in ::follow_exec, are now pushed
   back to where the thread is created, as a result, some places where
   in V1 I was changing the state, I'm now asserting the state.

 - Added some asserts to clear_stop_pc

One big consequence of this patch is that we now expect that threads
are created in the "correct" resumed/non-resumed state.  A place where
this is definitely now wrong is during the initial creation of a
process to debug - threads are created in the default resumed state,
which is not correct.

I've fixed this for the native Linux and remote targets, but for all
other targets this will likely be incorrect.

As I'm not able to test these targets I made the choice to, instead of
asserting that GDB has the correct state, fix the state.  This can be
seen in gdb_startup_inferior (fork-child.c) and one in run_command_1
(infcmd.c), where I've added comments about this.

I don't really see a way around this.  If I make the default thread
state be non-resumed then the inferior creation code would work, but
any target specific code to handle creating new threads would
potentially be wrong (as threads would be created non-resumed when
they should be resumed).

I could potentially just add the asserts and let all the other targets
break; then offer help as/when these issues are reported.

Thoughts on this welcome.

Thanks,
Andrew

----

commit 32b05d0b4f46070df5583bc8e411034da8dc4d5a
Author: Andrew Burgess <andrew.burgess@embecosm.com>
Date:   Mon Aug 16 12:09:45 2021 +0100

    gdb: make thread_info executing and resumed state more consistent
    
    This commit was inspired by this comment from Simon:
    
      https://sourceware.org/pipermail/gdb-patches/2021-July/180694.html
    
    The comment is about two thread_info flags m_executing and m_resumed.
    The m_resumed flag indicates that at the infrun level GDB has set the
    thread running, while the m_executing flag indicates that the thread
    is actually running at the target level.
    
    It is very common that a thread can be m_resumed, but not m_executing,
    that is, core GDB thinks the thread is, or should be, running, but at
    the target level the thread isn't currently running.
    
    The comment Simon made was in reply to a patch I posted where I found
    a case where a thread was marked m_executing, but not m_resumed, that
    is, at the infrun level GDB thought the thread was stopped, but at the
    target level the thread was actually running.  Simon suggests that
    this feels like an invalid state, and after thinking about it, I
    agree.
    
    So, the goal of this commit is to add some asserts to GDB.  The core
    idea here is that the resumed and executing flags should only change
    in the following pattern, to begin with everything is set false:
    
      Resumed: false
      Executing: false
    
    Then infrun marks the thread resumed:
    
      Resumed: true
      Executing: false
    
    Then a target starts the thread executing:
    
      Resumed: true
      Executing: true
    
    The thread stops, the target spots this and marks the thread no longer
    executing:
    
      Resumed: true
      Executing: false
    
    And finally, infrun acknowledges that the thread is now no longer
    resumed:
    
      Resumed: false
      Executing: false
    
    Notice that at no point is resumed false, while executing is true.
    
    And so we can add these asserts:
    
     1. The resumed flag should only change state when the executing flag
     is false, and
    
     2. The executing flag should only change state when the resumed flag
     is true.
    
    I added these asserts and ....
    
    .... it turns out these rules are broken all over the place in GDB, we
    have problems like:
    
     (a) When new threads appear they are marked executing, but not
     resumed, and
    
     (b) In some places we mark a single thread as resumed, but then
     actually set multiple threads executing.
    
    For (a) it could be argued that this is a legitimate state - this is
    actually the problem I addressed in the original patch that Simon was
    replying too, however, we don't need to support this as a separate
    state, so if we can make this case follow the expected set of state
    transitions then it allows us to reduce the number of states that GDB
    can be in, which I think is a good thing.
    
    Case (b) seems to just be a bug to me.
    
    My initial approach was to retain the idea that threads are always
    created in the non-executing, non-resumed state, and then find all the
    places where new threads are created (which should be in the resumed
    state), and mark the thread resumed in that case.
    
    However, after looking at the changes for a while, it felt like it
    would be simpler to create threads as resumed by default and instead
    force the threads back to non-resumed in the few cases where this was
    appropriate.  The appropriate case being (as far as I can tell), just
    the initial threads created as part of starting up a new inferior.
    
    So, that's what this patch does.  The thread creation routines now
    take a flag to indicate if the new thread should be created resumed or
    not.  Threads created as part of the ::create_inferior process should
    be created non-resumed, while all other threads are created resumed.
    
    The only problem is that this change requires updates to all targets
    that supply ::create_inferior, and I'm mostly only able to test
    GNU/Linux targets.
    
    And so, I have two changes, one in gdb_startup_inferior (fork-child.c)
    and one in run_command_1 (infcmd.c) where, instead of asserting that
    a thread is in a particular resumed/non-resumed state, I am setting
    the thread back to non-resumed.  I believe that this should fix up
    GDB's state for any target that is not (yet) doing the correct thing
    when creating its initial threads.
    
    Here is a description of all the individual changes:
    
      * corelow.c (add_to_thread_list): When adding threads as part of
      setting up a core target, the threads should not be resumed.
    
      (core_target_open): When adding threads as part of setting up a core
      target, the threads should not be resumed.  For sanity, assert that
      the threads of a core target are not resumed once the initial target
      has been setup.
    
      * fork-child.c (gdb_startup_inferior): Upon entry to this function
      no threads in the inferior should be resumed, however, I suspect not
      all targets comply with this assertion, so for now I don't actually
      assert anything.  As we're about to resume the inferior though, mark
      all threads as resumed.
    
      * gdbthread.h (set_stop_pc): Add assert that the stop_pc can only be
      set when a thread is neither resumed, or executing.
    
      (clear_stop_pc): The stop_pc is cleared as part of setting the
      thread executing.  And, as a thread is only set executing after it
      is marked resumed, we can add some asserts to this function to
      validate GDB's state.
    
      (add_thread): Update header comment, add extra 'resumed_p' parameter.
    
      (add_thread_silent): Add extra 'resumed_p' parameter.
    
      (add_thread_with_info): Add extra 'resumed_p' parameter.
    
      * inf-ptrace.c (inf_ptrace_target::create_inferior): The initial
      thread is created non-resumed.
    
      * infcmd.c (post_create_inferior): Only attempt to set the stop_pc
      once per-stop.  I've updated the comment, and re-indented the code
      under the new if condition.
    
      (run_command_1): After creating the inferior all threads should be
      non-resumed, however, I suspect that not all targets comply with
      this assertion, so, instead of asserting this, I set all threads
      back to non-resumed to save any badly behaved targets.
    
      * infrun.c (follow_fork_inferior): After a fork all threads in the
      child should already have been marked as non-resumed.
    
      (follow_exec): Upon entry the thread performing the exec should
      already be marked as non-resumed.  After the exec the selected
      thread should also be non-resumed.
    
      (struct scoped_mark_thread_resumed): This new class is used to
      ensure that all the required threads are marked resumed when
      required, this addresses issue (b) above.  I make use of this new
      class in...
    
      (do_target_resume):  Use scoped_mark_thread_resumed to mark all
      threads resumed prior to actually calling into the target to resume
      the threads.  Placing this call here allows me to remove some calls
      to thread_info::set_resumed() in other places...
    
      (resume_1): Remove a call to thread_info::set_resumed() from here.
    
      (handle_inferior_event): Assert that the thread is not resumed when
      handling an exec event.
    
      (finish_step_over): When we need to place a thread back into the
      resumed state so that we can later find its pending event, we must
      mark the thread resumed after setting the stop_pc, see the asserts
      added to set_stop_pc for why.
    
      (keep_going_stepped_thread): Remove a call to set_resumed thanks to
      our changes in do_target_resume.
    
      * process-stratum-target.c (process_stratum_target::follow_exec):
      If creating a new thread to handle the exec in, then it should be
      created non-resumed.
    
      (process_stratum_target::follow_fork): If creating a new thread to
      follow the child of a fork, the new thread should be non-resumed.
    
      * remote.c (remote_target::add_current_inferior_and_thread): Add
      resumed_p parameter.  Use this parameter to decide if the new thread
      should be started resumed or not.
    
      (remote_target::remote_add_thread): Mark the thread resumed before
      marking it executed.
    
      (remote_target::process_initial_stop_replies): Mark the thread as
      non-resumed.
    
      (remote_target::start_remote): Create the initial thread in a
      resumed state.
    
      (extended_remote_target::create_inferior): Create the initial thread
      in a non-resumed state.
    
      * thread.c (add_thread_silent): Take a new resumed_p parameter, use
      this to set if the new thread is resumed or not.  All new threads
      are created non-executing, so assert this.
    
      (add_thread_with_info): Pass through the new resumed_p parameter.
    
      (add_thread): Pass through the new resumed_p parameter.
    
      (thread_info::set_executing): Add an early exit patch like we
      already have in thread_info::set_executing().  Also add the
      assertion that is one of the two core asserts for this patch.  Mark
      the thread executing after clearing the stop_pc, this allows the
      assertion we added to thread_info::clear_stop_pc above to work.
    
      (thread_info::set_resumed): Add the other core assert for this
      patch.
    
    This series has been tested on X86-64 GNU/Linux with the unix,
    native-gdbserver, and native-extended-gdbserver boards.

diff --git a/gdb/corelow.c b/gdb/corelow.c
index 711e86c4cd4..d6846b8f609 100644
--- a/gdb/corelow.c
+++ b/gdb/corelow.c
@@ -347,7 +347,8 @@ add_to_thread_list (asection *asect, asection *reg_sect)
 
   ptid_t ptid (pid, lwpid);
 
-  thread_info *thr = add_thread (inf->process_target (), ptid);
+  /* Pass false to indicate the thread should be added non-resumed.  */
+  thread_info *thr = add_thread (inf->process_target (), ptid, false);
 
 /* Warning, Will Robinson, looking at BFD private data! */
 
@@ -505,7 +506,7 @@ core_target_open (const char *arg, int from_tty)
       if (thread == NULL)
 	{
 	  inferior_appeared (current_inferior (), CORELOW_PID);
-	  thread = add_thread_silent (target, ptid_t (CORELOW_PID));
+	  thread = add_thread_silent (target, ptid_t (CORELOW_PID), false);
 	}
 
       switch_to_thread (thread);
@@ -514,6 +515,10 @@ core_target_open (const char *arg, int from_tty)
   if (current_program_space->exec_bfd () == nullptr)
     locate_exec_from_corefile_build_id (core_bfd, from_tty);
 
+  /* Threads in a core file are not resumed.  */
+  for (thread_info *thread : current_inferior ()->threads ())
+    gdb_assert (!thread->resumed ());
+
   post_create_inferior (from_tty);
 
   /* Now go through the target stack looking for threads since there
diff --git a/gdb/fork-child.c b/gdb/fork-child.c
index 3ce7d64b855..8890ea41e05 100644
--- a/gdb/fork-child.c
+++ b/gdb/fork-child.c
@@ -126,10 +126,24 @@ gdb_startup_inferior (pid_t pid, int num_traps)
   inferior *inf = current_inferior ();
   process_stratum_target *proc_target = inf->process_target ();
 
+  for (thread_info *thread : inf->threads ())
+    {
+      /* Ideally, all targets would created their initial threads in the
+	 non-resumed state, and only when we get here would we mark the
+	 threads as resumed.  However, this is not currently the case, some
+	 targets create their initial threads in the resumed state (for no
+	 particular reason other than historical), and so we can't assert
+	 anything about the state of the inferior threads at this point.
+
+	 What we'd like to say is:  gdb_assert (!thread->resumed ());   */
+      thread->set_resumed (true);
+    }
+
   ptid_t ptid = startup_inferior (proc_target, pid, num_traps, NULL, NULL);
 
   /* Mark all threads non-executing.  */
   set_executing (proc_target, ptid, false);
+  set_resumed (proc_target, ptid, false);
 
   return ptid;
 }
diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index 4b271943d50..9ffe9233c77 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -345,6 +345,8 @@ class thread_info : public refcounted_object,
 
   void set_stop_pc (CORE_ADDR stop_pc)
   {
+    gdb_assert (!m_resumed);
+    gdb_assert (!m_executing);
     m_suspend.stop_pc = stop_pc;
   }
 
@@ -352,6 +354,8 @@ class thread_info : public refcounted_object,
 
   void clear_stop_pc ()
   {
+    gdb_assert (m_resumed);
+    gdb_assert (!m_executing);
     m_suspend.stop_pc.reset ();
   }
 
@@ -547,22 +551,25 @@ using inferior_ref
 /* Create an empty thread list, or empty the existing one.  */
 extern void init_thread_list (void);
 
-/* Add a thread to the thread list, print a message
-   that a new thread is found, and return the pointer to
-   the new thread.  Caller my use this pointer to 
-   initialize the private thread data.  */
+/* Add a thread to the thread list, print a message that a new thread is
+   found, and return the pointer to the new thread.  Caller my use this
+   pointer to initialize the private thread data.  When RESUMED_P is true
+   the thread is created in a resumed state, otherwise, the thread is
+   created in a non-resumed state.  */
 extern struct thread_info *add_thread (process_stratum_target *targ,
-				       ptid_t ptid);
+				       ptid_t ptid, bool resumed_p = true);
 
 /* Same as add_thread, but does not print a message about new
    thread.  */
 extern struct thread_info *add_thread_silent (process_stratum_target *targ,
-					      ptid_t ptid);
+					      ptid_t ptid,
+					      bool resumed_p = true);
 
 /* Same as add_thread, and sets the private info.  */
 extern struct thread_info *add_thread_with_info (process_stratum_target *targ,
 						 ptid_t ptid,
-						 private_thread_info *);
+						 private_thread_info *,
+						 bool resumed_p = true);
 
 /* Delete thread THREAD and notify of thread exit.  If the thread is
    currently not deletable, don't actually delete it but still tag it
diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c
index afa38de6ef7..0366bb940e0 100644
--- a/gdb/inf-ptrace.c
+++ b/gdb/inf-ptrace.c
@@ -94,7 +94,7 @@ inf_ptrace_target::create_inferior (const char *exec_file,
   /* We have something that executes now.  We'll be running through
      the shell at this point (if startup-with-shell is true), but the
      pid shouldn't change.  */
-  thread_info *thr = add_thread_silent (this, ptid);
+  thread_info *thr = add_thread_silent (this, ptid, false);
   switch_to_thread (thr);
 
   unpusher.release ();
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index d948f4bafc5..d31ba5af144 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -244,22 +244,29 @@ post_create_inferior (int from_tty)
      don't need to.  */
   target_find_description ();
 
-  /* Now that we know the register layout, retrieve current PC.  But
-     if the PC is unavailable (e.g., we're opening a core file with
-     missing registers info), ignore it.  */
+  /* Now that we know the register layout, update the stop_pc if it is not
+     already set.  If GDB attached to a running process then the stop_pc
+     will have been set while processing the stop events triggered during
+     the attach.  If this is a core file, or we're just starting a new
+     process, then the stop_pc will not currently be set.
+
+     But, if the PC is unavailable (e.g., we're opening a core file with
+     missing registers info), ignore it.  Obviously, if we're trying to
+     debug a running process and we can't read the PC then this is bad and
+     shouldn't be ignored, but we'll soon hit errors trying to read the PC
+     elsewhere in GDB, so ignoring this here is fine.  */
   thread_info *thr = inferior_thread ();
-
-  thr->clear_stop_pc ();
-  try
-    {
-      regcache *rc = get_thread_regcache (thr);
-      thr->set_stop_pc (regcache_read_pc (rc));
-    }
-  catch (const gdb_exception_error &ex)
-    {
-      if (ex.error != NOT_AVAILABLE_ERROR)
-	throw;
-    }
+  if (!thr->stop_pc_p ())
+    try
+      {
+	regcache *rc = get_thread_regcache (thr);
+	thr->set_stop_pc (regcache_read_pc (rc));
+      }
+    catch (const gdb_exception_error &ex)
+      {
+	if (ex.error != NOT_AVAILABLE_ERROR)
+	  throw;
+      }
 
   if (current_program_space->exec_bfd ())
     {
@@ -453,6 +460,19 @@ run_command_1 (const char *args, int from_tty, enum run_how run_how)
      shouldn't refer to run_target again.  */
   run_target = NULL;
 
+  /* After creating the inferior its threads are not resumed.  */
+  for (thread_info *thread : current_inferior ()->threads ())
+    {
+      /* Ideally, all targets would leave their threads non-resumed after
+	 the create_inferior call above.  Unfortunately, this is probably
+	 not the case.  The 'probably' here is simply due to an inability
+	 to test all targets.  So, rather than asserting that all threads
+	 are non-resumed here, set the threads to be non-resumed.
+
+	 We'd like to say: gdb_assert (!thread->resumed ());  */
+      thread->set_resumed (false);
+    }
+
   /* We're starting off a new process.  When we get out of here, in
      non-stop mode, finish the state of all threads of that process,
      but leave other threads alone, as they may be stopped in internal
diff --git a/gdb/infrun.c b/gdb/infrun.c
index d1ac9b4cbbb..ca4568ba272 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -580,7 +580,13 @@ holding the child stopped.  Try \"set detach-on-fork\" or \
   /* If there is a child inferior, target_follow_fork must have created a thread
      for it.  */
   if (child_inf != nullptr)
-    gdb_assert (!child_inf->thread_list.empty ());
+    {
+      gdb_assert (!child_inf->thread_list.empty ());
+
+      /* Any added thread should have been marked non-resumed already.  */
+      for (thread_info *thread : child_inf->threads ())
+	gdb_assert (!thread->resumed ());
+    }
 
   /* Detach the parent if needed.  */
   if (follow_child)
@@ -1091,6 +1097,7 @@ follow_exec (ptid_t ptid, const char *exec_file_target)
      breakpoint or similar, it's gone now.  We cannot truly
      step-to-next statement through an exec().  */
   thread_info *th = inferior_thread ();
+  gdb_assert (!th->resumed ());
   th->control.step_resume_breakpoint = NULL;
   th->control.exception_resume_breakpoint = NULL;
   th->control.single_step_breakpoints = NULL;
@@ -1172,6 +1179,11 @@ follow_exec (ptid_t ptid, const char *exec_file_target)
   gdb_assert (current_inferior () == inf);
   gdb_assert (current_program_space == inf->pspace);
 
+  /* The inferior (and so thread) might have changed depending on which
+     path we took through the above code.  However, the currently selected
+     thread should not be in a resumed state.  */
+  gdb_assert (!inferior_thread ()->resumed ());
+
   /* Attempt to open the exec file.  SYMFILE_DEFER_BP_RESET is used
      because the proper displacement for a PIE (Position Independent
      Executable) main symbol file will only be computed by
@@ -2100,6 +2112,52 @@ internal_resume_ptid (int user_step)
     return user_visible_resume_ptid (user_step);
 }
 
+/* Before calling into target code to set inferior threads executing we
+   must mark all threads as resumed.  If an exception is thrown while
+   trying to set the threads executing then we should mark the threads as
+   non-resumed.
+
+   Create an instance of this struct before */
+struct scoped_mark_thread_resumed
+{
+  /* Constructor.  All threads matching PTID will be marked as resumed.  */
+  scoped_mark_thread_resumed (process_stratum_target *targ, ptid_t ptid)
+    : m_target (targ), m_ptid (ptid)
+  {
+    gdb_assert (m_target != nullptr);
+    set_resumed (m_target, m_ptid, true);
+  }
+
+  /* Destructor.  If M_TARGET is not nullptr then mark all threads matching
+     M_PTID as no longer being resumed.  The expectation is that on the
+     exception path this will be called with M_TARGET still set to a valid
+     target.  If however, the threads were successfully set executing then
+     this->commit() will have been called, and M_TARGET will now be
+     nullptr.  */
+  ~scoped_mark_thread_resumed ()
+  {
+    if (m_target != nullptr)
+      set_resumed (m_target, m_ptid, false);
+  }
+
+  /* Called once all of the threads have successfully be set executing (by
+     calling into the target code).  Clears M_TARGET as an indication that,
+     when this object is destructed, we should leave all matching threads
+     as being marked resumed.  */
+  void commit ()
+  {
+    m_target = nullptr;
+  }
+
+private:
+
+  /* The target used for marking threads as resumed or non-resumed.  */
+  process_stratum_target *m_target;
+
+  /* The thread (or threads) to mark as resumed.  */
+  ptid_t m_ptid;
+};
+
 /* Wrapper for target_resume, that handles infrun-specific
    bookkeeping.  */
 
@@ -2108,6 +2166,11 @@ do_target_resume (ptid_t resume_ptid, bool step, enum gdb_signal sig)
 {
   struct thread_info *tp = inferior_thread ();
 
+  /* Create a scoped_mark_thread_resumed to mark all threads matching
+     RESUME_PTID as resumed.  */
+  process_stratum_target *curr_target = current_inferior ()->process_target ();
+  scoped_mark_thread_resumed scoped_resume (curr_target, resume_ptid);
+
   gdb_assert (!tp->stop_requested);
 
   /* Install inferior's terminal modes.  */
@@ -2146,6 +2209,9 @@ do_target_resume (ptid_t resume_ptid, bool step, enum gdb_signal sig)
 
   if (target_can_async_p ())
     target_async (1);
+
+  /* Call commit so SCOPED_RESUME leaves threads marked as resumed.  */
+  scoped_resume.commit ();
 }
 
 /* Resume the inferior.  SIG is the signal to give the inferior
@@ -2305,7 +2371,6 @@ resume_1 (enum gdb_signal sig)
 
 	      resume_ptid = internal_resume_ptid (user_step);
 	      do_target_resume (resume_ptid, false, GDB_SIGNAL_0);
-	      tp->set_resumed (true);
 	      return;
 	    }
 	}
@@ -2514,7 +2579,6 @@ resume_1 (enum gdb_signal sig)
     }
 
   do_target_resume (resume_ptid, step, sig);
-  tp->set_resumed (true);
 }
 
 /* Resume the inferior.  SIG is the signal to give the inferior
@@ -5616,6 +5680,10 @@ handle_inferior_event (struct execution_control_state *ecs)
 	 execd thread for that case (this is a nop otherwise).  */
       ecs->event_thread = inferior_thread ();
 
+      /* If we did switch threads above, then the new thread should still
+	 be in the non-resumed state.  */
+      gdb_assert (!ecs->event_thread->resumed ());
+
       ecs->event_thread->set_stop_pc
 	(regcache_read_pc (get_thread_regcache (ecs->event_thread)));
 
@@ -5865,12 +5933,6 @@ finish_step_over (struct execution_control_state *ecs)
 
 	  /* Record the event thread's event for later.  */
 	  save_waitstatus (tp, &ecs->ws);
-	  /* This was cleared early, by handle_inferior_event.  Set it
-	     so this pending event is considered by
-	     do_target_wait.  */
-	  tp->set_resumed (true);
-
-	  gdb_assert (!tp->executing ());
 
 	  regcache = get_thread_regcache (tp);
 	  tp->set_stop_pc (regcache_read_pc (regcache));
@@ -5881,6 +5943,10 @@ finish_step_over (struct execution_control_state *ecs)
 			       target_pid_to_str (tp->ptid).c_str (),
 			       currently_stepping (tp));
 
+	  /* This was cleared early, by handle_inferior_event.  Set it so
+	     this pending event is considered by do_target_wait.  */
+	  tp->set_resumed (true);
+
 	  /* This in-line step-over finished; clear this so we won't
 	     start a new one.  This is what handle_signal_stop would
 	     do, if we returned false.  */
@@ -7530,7 +7596,6 @@ keep_going_stepped_thread (struct thread_info *tp)
 				     get_frame_address_space (frame),
 				     tp->stop_pc ());
 
-      tp->set_resumed (true);
       resume_ptid = internal_resume_ptid (tp->control.stepping_command);
       do_target_resume (resume_ptid, false, GDB_SIGNAL_0);
     }
diff --git a/gdb/process-stratum-target.c b/gdb/process-stratum-target.c
index 4c726419b99..b6871403317 100644
--- a/gdb/process-stratum-target.c
+++ b/gdb/process-stratum-target.c
@@ -100,7 +100,7 @@ process_stratum_target::follow_exec (inferior *follow_inf, ptid_t ptid,
 	 may decide to unpush itself from the original inferior's target stack
 	 after that, at its discretion.  */
       follow_inf->push_target (orig_inf->process_target ());
-      thread_info *t = add_thread (follow_inf->process_target (), ptid);
+      thread_info *t = add_thread (follow_inf->process_target (), ptid, false);
 
       /* Leave the new inferior / thread as the current inferior / thread.  */
       switch_to_thread (t);
@@ -118,7 +118,7 @@ process_stratum_target::follow_fork (inferior *child_inf, ptid_t child_ptid,
   if (child_inf != nullptr)
     {
       child_inf->push_target (this);
-      add_thread_silent (this, child_ptid);
+      add_thread_silent (this, child_ptid, false);
     }
 }
 
diff --git a/gdb/remote.c b/gdb/remote.c
index b6da6b086a2..bb96149f70f 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -751,7 +751,8 @@ class remote_target : public process_stratum_target
   int remote_resume_with_vcont (ptid_t ptid, int step,
 				gdb_signal siggnal);
 
-  thread_info *add_current_inferior_and_thread (const char *wait_status);
+  thread_info *add_current_inferior_and_thread (const char *wait_status,
+						bool resumed_p);
 
   ptid_t wait_ns (ptid_t ptid, struct target_waitstatus *status,
 		  target_wait_flags options);
@@ -2546,8 +2547,9 @@ remote_target::remote_add_thread (ptid_t ptid, bool running, bool executing)
      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_resumed (this, ptid, running);
+  set_executing (this, ptid, executing);
 
   return thread;
 }
@@ -4440,7 +4442,8 @@ remote_target::get_current_thread (const char *wait_status)
    The function returns pointer to the main thread of the inferior. */
 
 thread_info *
-remote_target::add_current_inferior_and_thread (const char *wait_status)
+remote_target::add_current_inferior_and_thread (const char *wait_status,
+						bool resumed_p)
 {
   struct remote_state *rs = get_remote_state ();
   bool fake_pid_p = false;
@@ -4471,7 +4474,7 @@ remote_target::add_current_inferior_and_thread (const char *wait_status)
   /* Add the main thread and switch to it.  Don't try reading
      registers yet, since we haven't fetched the target description
      yet.  */
-  thread_info *tp = add_thread_silent (this, curr_ptid);
+  thread_info *tp = add_thread_silent (this, curr_ptid, resumed_p);
   switch_to_thread_no_regs (tp);
 
   return tp;
@@ -4586,6 +4589,7 @@ remote_target::process_initial_stop_replies (int from_tty)
 	evthread->set_pending_waitstatus (ws);
 
       set_executing (this, event_ptid, false);
+      set_resumed (this, event_ptid, false);
       set_running (this, event_ptid, false);
       get_remote_thread_info (evthread)->set_not_resumed ();
     }
@@ -4841,7 +4845,8 @@ remote_target::start_remote (int from_tty, int extended_p)
 	  /* Target has no concept of threads at all.  GDB treats
 	     non-threaded target as single-threaded; add a main
 	     thread.  */
-	  thread_info *tp = add_current_inferior_and_thread (wait_status);
+	  thread_info *tp
+	    = add_current_inferior_and_thread (wait_status, true);
 	  get_remote_thread_info (tp)->set_resumed ();
 	}
       else
@@ -10488,7 +10493,7 @@ Remote replied unexpectedly while setting startup-with-shell: %s"),
 
   /* vRun's success return is a stop reply.  */
   stop_reply = run_worked ? rs->buf.data () : NULL;
-  add_current_inferior_and_thread (stop_reply);
+  add_current_inferior_and_thread (stop_reply, false);
 
   /* Get updated offsets, if the stub uses qOffsets.  */
   get_offsets ();
diff --git a/gdb/thread.c b/gdb/thread.c
index 10c3dcd6991..a74ba94bbe8 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -245,7 +245,7 @@ new_thread (struct inferior *inf, ptid_t ptid)
 }
 
 struct thread_info *
-add_thread_silent (process_stratum_target *targ, ptid_t ptid)
+add_thread_silent (process_stratum_target *targ, ptid_t ptid, bool resumed_p)
 {
   gdb_assert (targ != nullptr);
 
@@ -260,6 +260,14 @@ add_thread_silent (process_stratum_target *targ, ptid_t ptid)
     delete_thread (tp);
 
   tp = new_thread (inf, ptid);
+
+  /* Upon creation, all threads are non-executing, and non-resumed.  Before
+     notifying observers of the new thread, we set the resumed flag to the
+     desired value.  */
+  gdb_assert (!tp->executing ());
+  tp->set_resumed (resumed_p);
+
+  /* Announce the new thread to all observers.  */
   gdb::observers::new_thread.notify (tp);
 
   return tp;
@@ -267,9 +275,9 @@ add_thread_silent (process_stratum_target *targ, ptid_t ptid)
 
 struct thread_info *
 add_thread_with_info (process_stratum_target *targ, ptid_t ptid,
-		      private_thread_info *priv)
+		      private_thread_info *priv, bool resumed_p)
 {
-  thread_info *result = add_thread_silent (targ, ptid);
+  thread_info *result = add_thread_silent (targ, ptid, resumed_p);
 
   result->priv.reset (priv);
 
@@ -281,9 +289,9 @@ add_thread_with_info (process_stratum_target *targ, ptid_t ptid,
 }
 
 struct thread_info *
-add_thread (process_stratum_target *targ, ptid_t ptid)
+add_thread (process_stratum_target *targ, ptid_t ptid, bool resumed_p)
 {
-  return add_thread_with_info (targ, ptid, NULL);
+  return add_thread_with_info (targ, ptid, NULL, resumed_p);
 }
 
 private_thread_info::~private_thread_info () = default;
@@ -322,9 +330,15 @@ thread_info::deletable () const
 void
 thread_info::set_executing (bool executing)
 {
-  m_executing = executing;
+  if (executing == m_executing)
+    return;
+
+  gdb_assert (m_resumed);
+
   if (executing)
     this->clear_stop_pc ();
+
+  m_executing = executing;
 }
 
 /* See gdbthread.h.  */
@@ -335,6 +349,8 @@ thread_info::set_resumed (bool resumed)
   if (resumed == m_resumed)
     return;
 
+  gdb_assert (!m_executing);
+
   process_stratum_target *proc_target = this->inf->process_target ();
 
   /* If we transition from resumed to not resumed, we might need to remove

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 3/3] gdb: make thread_info executing and resumed state more consistent
  2021-09-22 11:21     ` Andrew Burgess
@ 2021-09-23 17:14       ` Simon Marchi via Gdb-patches
  2021-09-29  8:09         ` Andrew Burgess
  0 siblings, 1 reply; 30+ messages in thread
From: Simon Marchi via Gdb-patches @ 2021-09-23 17:14 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches

> I did think about this, but I guess I'm not quite sure how this ends
> up being any simpler than the two booleans with rules.
> 
> My assumption is that we'd want to keep the API as
> executing/set_executing and resumed/set_resumed as this represents the
> questions we want to ask.
> 
> As such something like set_executing would become:
> 
>   void
>   thread_info::set_executing (bool e)
>   {
>     if (m_state == RESUMED_AND_TARGET_RESUMED)
>       return;
> 
>     gdb_assert (m_state == RESUMED_BUT_NOT_TARGET_RESUMED);
> 
>     m_state = RESUMED_AND_TARGET_RESUMED;
>   }
> 
> Which doesn't feel any less complex to me.
> 
> Of course, we could change the API so the user sets the state
> directly, like:
> 
>   void
>   thread_info_::set_executing_resumed_state (enum state_type s)
>   {
>     /* ... */
>   }
> 
> But then we'd _still_ end up having to assert the correct state
> transitions.

The later is what I was thinking.

What do you mean "assert the correct state transitions"?  With the enum
all possible transitions are valid.  I'm not sure if
RESUMED_AND_TARGET_RESUMED -> RESUMED_BUT_NOT_TARGET_RESUMED is actually
used, but it's not something prevented by your patch either.

Note that I'm still ok with how you are doing things, I'm just
discussing this to know whether we would want this as follow-up work or
not (if somebody is interested in implementing it).

>  - The add_thread* calls now take a flag, and threads can be started
>    as resumed or non-resumed.
> 
>  - Some of the state changes, like in ::follow_exec, are now pushed
>    back to where the thread is created, as a result, some places where
>    in V1 I was changing the state, I'm now asserting the state.
> 
>  - Added some asserts to clear_stop_pc
> 
> One big consequence of this patch is that we now expect that threads
> are created in the "correct" resumed/non-resumed state.  A place where
> this is definitely now wrong is during the initial creation of a
> process to debug - threads are created in the default resumed state,
> which is not correct.
> 
> I've fixed this for the native Linux and remote targets, but for all
> other targets this will likely be incorrect.
> 
> As I'm not able to test these targets I made the choice to, instead of
> asserting that GDB has the correct state, fix the state.  This can be
> seen in gdb_startup_inferior (fork-child.c) and one in run_command_1
> (infcmd.c), where I've added comments about this.
> 
> I don't really see a way around this.  If I make the default thread
> state be non-resumed then the inferior creation code would work, but
> any target specific code to handle creating new threads would
> potentially be wrong (as threads would be created non-resumed when
> they should be resumed).

I'm not a fan of the default parameter values in add_thread and friends.
I'd prefer having to pass an explicit value at each call site (there
aren't that many), that would force thinking about what to pass at each
call site.

For targets you can't build and test... I'd say do a best effort to
update them (update calls to add_thread* functions) and then use
assertions.  I much prefer a clear and consistent set of
preconditions/postconditions to the target interface than a state where
some targets do one thing and other targets do something else.  That's
easier to work with in the long run.  And ideally, these would be
documented in the target interface.  For example, the documentation for
target_ops::attach should say "threads created by the target during
attach should be marked as (resumed|non-resumed)".  If somebody hits one
of your assertions, because a target is not respecting this
postcondition, it will be quite obvious.


> @@ -1172,6 +1179,11 @@ follow_exec (ptid_t ptid, const char *exec_file_target)
>    gdb_assert (current_inferior () == inf);
>    gdb_assert (current_program_space == inf->pspace);
>  
> +  /* The inferior (and so thread) might have changed depending on which
> +     path we took through the above code.  However, the currently selected
> +     thread should not be in a resumed state.  */
> +  gdb_assert (!inferior_thread ()->resumed ());

Here, I suggested using a loop over all of current inferior's threads.
It sounds a bit silly, but I'm thinking that some weird platform some
day might have processes with two threads when coming out of an exec.
Alternatively, we could assert that the current inferior contains
exactly one thread.

> +
>    /* Attempt to open the exec file.  SYMFILE_DEFER_BP_RESET is used
>       because the proper displacement for a PIE (Position Independent
>       Executable) main symbol file will only be computed by
> @@ -2100,6 +2112,52 @@ internal_resume_ptid (int user_step)
>      return user_visible_resume_ptid (user_step);
>  }
>  
> +/* Before calling into target code to set inferior threads executing we
> +   must mark all threads as resumed.  If an exception is thrown while
> +   trying to set the threads executing then we should mark the threads as
> +   non-resumed.
> +
> +   Create an instance of this struct before */

Seems like this comment was not finished.

> +struct scoped_mark_thread_resumed
> +{
> +  /* Constructor.  All threads matching PTID will be marked as resumed.  */
> +  scoped_mark_thread_resumed (process_stratum_target *targ, ptid_t ptid)
> +    : m_target (targ), m_ptid (ptid)
> +  {
> +    gdb_assert (m_target != nullptr);
> +    set_resumed (m_target, m_ptid, true);
> +  }
> +
> +  /* Destructor.  If M_TARGET is not nullptr then mark all threads matching
> +     M_PTID as no longer being resumed.  The expectation is that on the
> +     exception path this will be called with M_TARGET still set to a valid
> +     target.  If however, the threads were successfully set executing then
> +     this->commit() will have been called, and M_TARGET will now be
> +     nullptr.  */

I'd say "If the object was not committed" instead of "If M_TARGET is not
nullptr".  M_TARGET being nullptr to represent the commit is an internal
detail, and this comment is supposed to describe the interface.

> +  ~scoped_mark_thread_resumed ()
> +  {
> +    if (m_target != nullptr)
> +      set_resumed (m_target, m_ptid, false);
> +  }
> +
> +  /* Called once all of the threads have successfully be set executing (by
> +     calling into the target code).  Clears M_TARGET as an indication that,
> +     when this object is destructed, we should leave all matching threads
> +     as being marked resumed.  */

Same idea here.  You could put the "Clear M_TARGET..." part inside the
method body (to describe the implementation), while the comment above
the method can describe the interface (e.g. "Calling commit makes it so
threads are left as resumed on destruction.").

Simon

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 3/3] gdb: make thread_info executing and resumed state more consistent
  2021-09-23 17:14       ` Simon Marchi via Gdb-patches
@ 2021-09-29  8:09         ` Andrew Burgess
  2021-10-08 19:33           ` Simon Marchi via Gdb-patches
  0 siblings, 1 reply; 30+ messages in thread
From: Andrew Burgess @ 2021-09-29  8:09 UTC (permalink / raw)
  To: Simon Marchi; +Cc: gdb-patches

* Simon Marchi <simon.marchi@polymtl.ca> [2021-09-23 13:14:33 -0400]:

> > I did think about this, but I guess I'm not quite sure how this ends
> > up being any simpler than the two booleans with rules.
> > 
> > My assumption is that we'd want to keep the API as
> > executing/set_executing and resumed/set_resumed as this represents the
> > questions we want to ask.
> > 
> > As such something like set_executing would become:
> > 
> >   void
> >   thread_info::set_executing (bool e)
> >   {
> >     if (m_state == RESUMED_AND_TARGET_RESUMED)
> >       return;
> > 
> >     gdb_assert (m_state == RESUMED_BUT_NOT_TARGET_RESUMED);
> > 
> >     m_state = RESUMED_AND_TARGET_RESUMED;
> >   }
> > 
> > Which doesn't feel any less complex to me.
> > 
> > Of course, we could change the API so the user sets the state
> > directly, like:
> > 
> >   void
> >   thread_info_::set_executing_resumed_state (enum state_type s)
> >   {
> >     /* ... */
> >   }
> > 
> > But then we'd _still_ end up having to assert the correct state
> > transitions.
> 
> The later is what I was thinking.
> 
> What do you mean "assert the correct state transitions"?  With the enum
> all possible transitions are valid.  I'm not sure if
> RESUMED_AND_TARGET_RESUMED -> RESUMED_BUT_NOT_TARGET_RESUMED is actually
> used, but it's not something prevented by your patch either.

The RESUMED_AND_TARGET_RESUMED -> RESUMED_BUT_NOT_TARGET_RESUMED
transition is definitely used, and is, I believe required with my
patch.

I don't know if there are many places in GDB that we actually sit in
the RESUMED_BUT_NOT_TARGET_RESUMED state for long (that would
currently be resumed=true,executing=false, right?) but my intention is
that we have to go back through that state, i.e. we can't set resumed
to false while executing is true.

From you original proposed states:

  enum class thread_resumption_state
  {
    NOT_RESUMED,			/* 1 */
    RESUMED_BUT_NOT_TARGET_RESUMED,	/* 2 */
    RESUMED_AND_TARGET_RESUMED,		/* 3 */
  };

Under the current scheme the transition order should always be:

  1 -> 2 -> 3 -> 2 -> 1

Anything else should trigger an assertion.

Ideally, if I transitioned to the new scheme I'd (at least initially)
want to keep assertions that force that transition scheme, so no
transitions 1->3 or 3->1.

However, there are places where set_resumed and set_executing are
right next to each other.

So maybe they would be merged into a single set_state call, which
means the 1->3 or 3->1 transitions would be legal.  So, then we remove
the asserts and allow any state transitions.

But then, if we have a bug which GDB skips the logic that used to be
responsible for "set_resumed" we'd never know, right?  When we hit the
old set_executing call, this will now just set the state as if the
resumed had happened...

...this seems less good to me.

I guess given you've said you're not against what I have then for now
I'd prefer to stick with the separate resumed/executing.  We can
always change later - I think it would be best done in a separate
patch anyway - I just want to try and explain my thinking.

Thanks for all your other feedback.   I'll go through and try and
address all your points and post a new version of the patch.

Thanks,
Andrew


> 
> Note that I'm still ok with how you are doing things, I'm just
> discussing this to know whether we would want this as follow-up work or
> not (if somebody is interested in implementing it).
> 
> >  - The add_thread* calls now take a flag, and threads can be started
> >    as resumed or non-resumed.
> > 
> >  - Some of the state changes, like in ::follow_exec, are now pushed
> >    back to where the thread is created, as a result, some places where
> >    in V1 I was changing the state, I'm now asserting the state.
> > 
> >  - Added some asserts to clear_stop_pc
> > 
> > One big consequence of this patch is that we now expect that threads
> > are created in the "correct" resumed/non-resumed state.  A place where
> > this is definitely now wrong is during the initial creation of a
> > process to debug - threads are created in the default resumed state,
> > which is not correct.
> > 
> > I've fixed this for the native Linux and remote targets, but for all
> > other targets this will likely be incorrect.
> > 
> > As I'm not able to test these targets I made the choice to, instead of
> > asserting that GDB has the correct state, fix the state.  This can be
> > seen in gdb_startup_inferior (fork-child.c) and one in run_command_1
> > (infcmd.c), where I've added comments about this.
> > 
> > I don't really see a way around this.  If I make the default thread
> > state be non-resumed then the inferior creation code would work, but
> > any target specific code to handle creating new threads would
> > potentially be wrong (as threads would be created non-resumed when
> > they should be resumed).
> 
> I'm not a fan of the default parameter values in add_thread and friends.
> I'd prefer having to pass an explicit value at each call site (there
> aren't that many), that would force thinking about what to pass at each
> call site.
> 
> For targets you can't build and test... I'd say do a best effort to
> update them (update calls to add_thread* functions) and then use
> assertions.  I much prefer a clear and consistent set of
> preconditions/postconditions to the target interface than a state where
> some targets do one thing and other targets do something else.  That's
> easier to work with in the long run.  And ideally, these would be
> documented in the target interface.  For example, the documentation for
> target_ops::attach should say "threads created by the target during
> attach should be marked as (resumed|non-resumed)".  If somebody hits one
> of your assertions, because a target is not respecting this
> postcondition, it will be quite obvious.
> 
> 
> > @@ -1172,6 +1179,11 @@ follow_exec (ptid_t ptid, const char *exec_file_target)
> >    gdb_assert (current_inferior () == inf);
> >    gdb_assert (current_program_space == inf->pspace);
> >  
> > +  /* The inferior (and so thread) might have changed depending on which
> > +     path we took through the above code.  However, the currently selected
> > +     thread should not be in a resumed state.  */
> > +  gdb_assert (!inferior_thread ()->resumed ());
> 
> Here, I suggested using a loop over all of current inferior's threads.
> It sounds a bit silly, but I'm thinking that some weird platform some
> day might have processes with two threads when coming out of an exec.
> Alternatively, we could assert that the current inferior contains
> exactly one thread.
> 
> > +
> >    /* Attempt to open the exec file.  SYMFILE_DEFER_BP_RESET is used
> >       because the proper displacement for a PIE (Position Independent
> >       Executable) main symbol file will only be computed by
> > @@ -2100,6 +2112,52 @@ internal_resume_ptid (int user_step)
> >      return user_visible_resume_ptid (user_step);
> >  }
> >  
> > +/* Before calling into target code to set inferior threads executing we
> > +   must mark all threads as resumed.  If an exception is thrown while
> > +   trying to set the threads executing then we should mark the threads as
> > +   non-resumed.
> > +
> > +   Create an instance of this struct before */
> 
> Seems like this comment was not finished.
> 
> > +struct scoped_mark_thread_resumed
> > +{
> > +  /* Constructor.  All threads matching PTID will be marked as resumed.  */
> > +  scoped_mark_thread_resumed (process_stratum_target *targ, ptid_t ptid)
> > +    : m_target (targ), m_ptid (ptid)
> > +  {
> > +    gdb_assert (m_target != nullptr);
> > +    set_resumed (m_target, m_ptid, true);
> > +  }
> > +
> > +  /* Destructor.  If M_TARGET is not nullptr then mark all threads matching
> > +     M_PTID as no longer being resumed.  The expectation is that on the
> > +     exception path this will be called with M_TARGET still set to a valid
> > +     target.  If however, the threads were successfully set executing then
> > +     this->commit() will have been called, and M_TARGET will now be
> > +     nullptr.  */
> 
> I'd say "If the object was not committed" instead of "If M_TARGET is not
> nullptr".  M_TARGET being nullptr to represent the commit is an internal
> detail, and this comment is supposed to describe the interface.
> 
> > +  ~scoped_mark_thread_resumed ()
> > +  {
> > +    if (m_target != nullptr)
> > +      set_resumed (m_target, m_ptid, false);
> > +  }
> > +
> > +  /* Called once all of the threads have successfully be set executing (by
> > +     calling into the target code).  Clears M_TARGET as an indication that,
> > +     when this object is destructed, we should leave all matching threads
> > +     as being marked resumed.  */
> 
> Same idea here.  You could put the "Clear M_TARGET..." part inside the
> method body (to describe the implementation), while the comment above
> the method can describe the interface (e.g. "Calling commit makes it so
> threads are left as resumed on destruction.").
> 
> Simon

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 3/3] gdb: make thread_info executing and resumed state more consistent
  2021-09-29  8:09         ` Andrew Burgess
@ 2021-10-08 19:33           ` Simon Marchi via Gdb-patches
  0 siblings, 0 replies; 30+ messages in thread
From: Simon Marchi via Gdb-patches @ 2021-10-08 19:33 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches

On 2021-09-29 4:09 a.m., Andrew Burgess wrote:
> * Simon Marchi <simon.marchi@polymtl.ca> [2021-09-23 13:14:33 -0400]:
>
>>> I did think about this, but I guess I'm not quite sure how this ends
>>> up being any simpler than the two booleans with rules.
>>>
>>> My assumption is that we'd want to keep the API as
>>> executing/set_executing and resumed/set_resumed as this represents the
>>> questions we want to ask.
>>>
>>> As such something like set_executing would become:
>>>
>>>   void
>>>   thread_info::set_executing (bool e)
>>>   {
>>>     if (m_state == RESUMED_AND_TARGET_RESUMED)
>>>       return;
>>>
>>>     gdb_assert (m_state == RESUMED_BUT_NOT_TARGET_RESUMED);
>>>
>>>     m_state = RESUMED_AND_TARGET_RESUMED;
>>>   }
>>>
>>> Which doesn't feel any less complex to me.
>>>
>>> Of course, we could change the API so the user sets the state
>>> directly, like:
>>>
>>>   void
>>>   thread_info_::set_executing_resumed_state (enum state_type s)
>>>   {
>>>     /* ... */
>>>   }
>>>
>>> But then we'd _still_ end up having to assert the correct state
>>> transitions.
>>
>> The later is what I was thinking.
>>
>> What do you mean "assert the correct state transitions"?  With the enum
>> all possible transitions are valid.  I'm not sure if
>> RESUMED_AND_TARGET_RESUMED -> RESUMED_BUT_NOT_TARGET_RESUMED is actually
>> used, but it's not something prevented by your patch either.
>
> The RESUMED_AND_TARGET_RESUMED -> RESUMED_BUT_NOT_TARGET_RESUMED
> transition is definitely used, and is, I believe required with my
> patch.
>
> I don't know if there are many places in GDB that we actually sit in
> the RESUMED_BUT_NOT_TARGET_RESUMED state for long (that would
> currently be resumed=true,executing=false, right?) but my intention is
> that we have to go back through that state, i.e. we can't set resumed
> to false while executing is true.

The most prominent case I know of is when resuming threads that have a
pending status (an event that was pulled out of the target, but not
consumed, instead saved in the thread_info structure).  When resuming
such a thread, infrun just pretends to resume it: it marks it as
resumed=true, but does not call target_ops::resume on it, and therefore
leaves it at executing=false (this is where I think the terminology is
confusing).  We will go back to the event loop, and infrun will go "oh!
a thread just stopped!" and consume that event.  That will make the
thread go back to resumed=false,executing=false.

> From you original proposed states:
>
>   enum class thread_resumption_state
>   {
>     NOT_RESUMED,			/* 1 */
>     RESUMED_BUT_NOT_TARGET_RESUMED,	/* 2 */
>     RESUMED_AND_TARGET_RESUMED,		/* 3 */
>   };
>
> Under the current scheme the transition order should always be:
>
>   1 -> 2 -> 3 -> 2 -> 1
>
> Anything else should trigger an assertion.

I think that would be fine, but I don't see the value.  The 3 -> 1
transition happens when target_ops::wait returns an event for a
thread.  The thread is no longer executing on the target, and no longer
resumed in the eyes of infrun.  So we could go 3 -> 2 -> 1 but that just
seems like an extra step.

> Ideally, if I transitioned to the new scheme I'd (at least initially)
> want to keep assertions that force that transition scheme, so no
> transitions 1->3 or 3->1.
>
> However, there are places where set_resumed and set_executing are
> right next to each other.
>
> So maybe they would be merged into a single set_state call, which
> means the 1->3 or 3->1 transitions would be legal.  So, then we remove
> the asserts and allow any state transitions.
>
> But then, if we have a bug which GDB skips the logic that used to be
> responsible for "set_resumed" we'd never know, right?  When we hit the
> old set_executing call, this will now just set the state as if the
> resumed had happened...
>
> ...this seems less good to me.

If resumed and executing are kept as separate states, then yeah the
transition needs to go through 2, as it's not possible to go from
resumed=true,executing=true to resume=false,executing=false atomically.

> I guess given you've said you're not against what I have then for now
> I'd prefer to stick with the separate resumed/executing.  We can
> always change later - I think it would be best done in a separate
> patch anyway - I just want to try and explain my thinking.

Yeah, that's fine with me.  Of course, I'd like if Pedro could take a
look, but he has a gazillion things to do.

And, food for future thoughts / changes, while reading about the 3 -> 2
-> 1 vs 3 -> 1 transition, I thought: it makes sense for infrun to
manage the resumed flag, because it's the "owner" of that flag.  That
flag means whether infrun considers this thread is running (regardless
of whether this thread is actually executing on target or infrun just
pretends it is running, for its own internal pending status logic).  But
the executing flag means "has the target been asked to resume execution
for this thread and hasn't yet reported an event implying that this
thread's execution on the target has halted".  So it seems to me that
the management of the executing flag could be done entirely in the
target_ops API frontier, in target_resume and target_wait.

target_resume already sets executing=true, which makes sense: we ask the
target to resume execution of the thread.  I think that the mirror
operation could be done in target_wait.  Let's say a target reports a
TARGET_WAITKIND_STOPPED for a thread, target_wait would mark this thread
as executing=false, because the target has reported an event that
implies that execution of that thread has stopped.  Basically, I'm
saying that the job of mark_non_executing_threads should maybe be done
by target_wait, except the set_resumed call at the end (that is still
infrun's job).  That would avoid the possibility of pulling an event out
of the target and forgetting to set executing=false, leading to problems
later.  And if doing so, the transition would always naturally be 3 -> 2
-> 1, because 3 -> 2 would be done by the target API, and later 2 ->
1 would be done by infrun.

Simon

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCHv3] gdb: make thread_info executing and resumed state more consistent
  2021-08-30 20:03 ` [PATCH 3/3] gdb: make thread_info executing and resumed state more consistent Andrew Burgess
  2021-09-01 15:09   ` Simon Marchi via Gdb-patches
@ 2022-01-13 18:34   ` Andrew Burgess via Gdb-patches
  2022-01-14 17:10     ` Simon Marchi via Gdb-patches
  2022-04-21 16:45     ` [PATCHv4 0/2] Make " Andrew Burgess via Gdb-patches
  1 sibling, 2 replies; 30+ messages in thread
From: Andrew Burgess via Gdb-patches @ 2022-01-13 18:34 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess

From: Andrew Burgess <andrew.burgess@embecosm.com>

I finally got back around to working on this patch, and have a new
version that I'd like to propose.

The biggest change in this version is that all of the thread creation
functions now have a new parameter which controls if the thread is
started resumed or not.

There was also a great discussion last time about whether the
executing and resumed flags (within thread_info) should be combined
into a single enum.  Simon argued in favour of this change, while I
remain unconvinced.

For now, I'd like to propose that the enum change be deferred.  The
patch as it stands is already pretty large, and changing how we manage
the two flags would only make the patch larger.  The change as I have
it right now maintains the flags as they are, but makes their use
consistent.  If we later want to change the flags to an enum then it
feels like this would be better done as a separate step.

There are still things that I would like to improve in the area of
this code, I'm still not completely happy with how the thread state is
managed around the target_ops::create_inferior call, but I though the
code as it stands isn't great, at least things are consistent after
this patch.

I'm as sure as I feel I can be that I've not broken anything for
Linux, but it's almost certain that something will be broken for other
targets.  I've details the additional testing I've done at the end of
my commit message.

My commit message also includes a ChangeLog like log, in this I've
tried to mention those areas of the change that I know are untested,
or lightly tested.

I welcome all review feedback, as well as any additional testing that
people might like to do.

Thanks,
Andrew

---

This commit was inspired by this comment from Simon:

  https://sourceware.org/pipermail/gdb-patches/2021-July/180694.html

The comment is about two thread_info flags m_executing and m_resumed.
The m_resumed flag indicates that at the infrun level GDB has set the
thread running, while the m_executing flag indicates that the thread
is actually running at the target level.

It is very common that a thread can be m_resumed, but not m_executing,
that is, core GDB thinks the thread is, or should be, running, but at
the target level the thread isn't currently running.

The comment Simon made was in reply to a patch I posted where I found
a case where a thread was marked m_executing, but not m_resumed, that
is, at the infrun level GDB thought the thread was stopped, but at the
target level the thread was actually running.  Simon suggests that
this feels like an invalid state, and after thinking about it, I
agree.

So, the goal of this commit is to add some asserts to GDB.  The core
idea here is that the resumed and executing flags should only change
in the following pattern, to begin with everything is set false:

  Resumed: false
  Executing: false

Then infrun marks the thread resumed:

  Resumed: true
  Executing: false

Then a target starts the thread executing:

  Resumed: true
  Executing: true

The thread stops, the target spots this and marks the thread no longer
executing:

  Resumed: true
  Executing: false

And finally, infrun acknowledges that the thread is now no longer
resumed:

  Resumed: false
  Executing: false

Notice that at no point is resumed false, while executing is true.

And so we can add these asserts:

 1. The resumed flag should only change state when the executing flag
 is false, and

 2. The executing flag should only change state when the resumed flag
 is true.

I added these asserts and ....

.... it turns out these rules are broken all over the place in GDB, we
have problems like:

 (a) When new threads appear they are marked executing, but not
 resumed, and

 (b) In some places we mark a single thread as resumed, but then
 actually set multiple threads executing.

For (a) it could be argued that this is a legitimate state - this is
actually the problem I addressed in the original patch that Simon was
replying too, however, we don't need to support this as a separate
state, so if we can make this case follow the expected set of state
transitions then it allows us to reduce the number of states that GDB
can be in, which I think is a good thing.

Case (b) seems to just be a bug to me.

My initial approach was to retain the idea that threads are always
created in the non-executing, non-resumed state, and then find all the
places where new threads are created (which should be in the resumed
state), and mark the thread resumed in that case.

However, after looking at the changes for a while, it felt like it
would be simpler to create threads as resumed by default and instead
change the threads back to non-resumed in the few cases where this was
appropriate.  The appropriate case being (as far as I can tell), just
the initial threads created as part of starting up a new inferior.

So, that's what this patch does.  The thread creation routines now
take a flag to indicate if the new thread should be created resumed or
not.  Almost all threads are started in the resumed state, except for
a few cases associated with initial target creation.

In an ideal world, I would have liked that all threads created as part
of the ::create_inferior process would also be created in the
non-resumed state, but that doesn't seem easily achievable right now.
Though I could easily see changing the Linux target, other targets that
I can't test will be harder to get right.  So, for now, after calling
::create_process I assert that the threads are currently resumed, and
then mark the threads as non-resumed.

I do have a plan that I might be able to make further improvements in
the ::create_inferior area, however, I want to see whether this patch
is accepted first before investing further time on this.  I think that
where this patch gets to is good enough for now.

On Testing:

I've tested this primarily on x86-64 GNU/Linux with the unix,
native-gdbserver, and native-extended-gdbserver boards, and see no
regressions.

I have also tried to test some other targets, though the testing has
been pretty minimal:

I installed FreeBSD in an x86-64 VM.  I can build GDB fine, but when I
try to run dejagnu the VM falls over with an out of swap space error,
no matter how much swap I give the machine.  However, before falling
over a few hundred tests do run, and I see no regressions in those
tests.  I've also manually checked that the gdb.base/attach.exp test
works (to do some basic attach testing).  So I'm reasonably confident
that this target should be mostly OK.

As I was working on GNU/Hurd for another bug I had an i386 GNU/Hurd VM
available, so I built GDB in here too.  Due to other issues with this
target the dejagnu testing is pretty useless here, but I checked that
I can start multi-threaded targets, step/continue past thread
creation, and also that I can attach to a multi-threaded target.

I have also built this branch on Windows, using mingw.  I was unable
to get dejagnu testing working on this target, but again I did some
basic testing that GDB could start up with multi-threaded inferiors,
and correctly see new threads as they appear.

I also built a target with a simulator, and checked that I could
startup and run basic tests their too.

I did try making use of the GCC machine farm to test on AIX and
Solaris, but I was unable to get GDB building on any of the machines I
tried in the farm.

Here is a description of all the individual changes:

  * aix-thread.c (sync_threadlists): New thread starts resumed, this
  change was untested.
  * bsd-kvm.c (bsd_kvm_target_open): New thread starts not-resumed,
  this change was untested.
  * bsd-uthread.c (bsd_uthread_target::wait): New thread starts
  resumed, this change was untested.
  (bsd_uthread_target::update_thread_list): Likewise.
  * corelow.c (add_to_thread_list): New threads start non-resumed.
  (core_target_open): Likewise.
  * darwin-nat.c (darwin_nat_target::check_new_threads): New thread
  starts resumed, this change was untested.
  * fbsd-nat.c (fbsd_add_threads): New threads start resumed.
  (fbsd_nat_target::wait): Likewise.
  * fork-child.c (gdb_startup_inferior): All threads should be
  marked resumed at this point.
  * gdbthread.h (thread_info::set_stop_pc): When setting the stop_pc
  a thread should be neither resumed, or executing.
  (clear_stop_pc): Due to where this method is called, the thread
  should be resumed, but definitely executing.  Though it's tempting
  to say we don't care about the resumed status, if we do ever call
  this function before the thread is resumed then that's a
  significant change, and having the assert fail will draw attention
  to that, and give us reason to think about what we're doing.
  (add_thread): Add additional parameter.
  (add_thread_silent): Likewise.
  (add_thread_with_info): Likewise.
  * gnu-nat.c (gnu_nat_target::inf_validate_procs): New threads are
  started resumed.  Only minimal testing of GNU/Hurd was done.
  (gnu_nat_target::create_inferior): Likewise.
  (gnu_nat_target::attach): Force threads back to non-resumed after
  an attach.  This is a hack, but avoids me having to make
  significant changes to GNU/Hurd thread management, which I'm
  reluctant to do given the difficulty testing the target.
  * go32-nat.c (go32_nat_target::create_inferior): New threads are
  started resumed, this change was untested.
  * inf-ptrace.c (inf_ptrace_target::create_inferior): New threads
  are staarted resumed.
  (inf_ptrace_target::attach): Likewise.
  * infcmd.c (post_create_inferior): Current thread should not be
  resumed at this point. Additionally, only set the stop_pc once per
  stop, there's an updated comment, extra debug output, and some of
  the code is re-indented.
  (run_command_1): Mark threads non-resumed after starting up the
  inferior as part of the run command.
  * infrun.c (follow_fork_inferior): After a fork all threads in the
  child should already have been marked as non-resumed.
  (follow_exec): Upon entry the thread performing the exec should
  already be marked as non-resumed.  After the exec the selected
  thread should also be non-resumed.
  (struct scoped_mark_thread_resumed): This new class is used to
  ensure that all the required threads are marked resumed when
  required, this addresses issue (b) above.  I make use of this new
  class in...
  (do_target_resume): Use scoped_mark_thread_resumed to mark all
  threads resumed prior to actually calling into the target to resume
  the threads.  Placing this call here allows me to remove some calls
  to thread_info::set_resumed() in other places...
  (resume_1): Remove calls to thread_info::set_resumed() from here.
  (handle_one): New threads are started resumed.
  (handle_inferior_event): Likewise.  Also assert that the thread is
  not resumed when handling an exec event.
  (finish_step_over): When we need to place a thread back into the
  resumed state so that we can later find its pending event, we must
  mark the thread resumed after setting the stop_pc, see the asserts
  added to set_stop_pc for why.
  (keep_going_stepped_thread): Remove a call to set_resumed thanks
  to our changes in do_target_resume.
  (stop_all_threads): Add some additional debug output.
  * linux-nat.c (attach_proc_task_lwp_callback): New threads are
  added resumed.
  (linux_handle_extended_wait): Likewise.
  (linux_nat_filter_event): Likewise.
  * linux-thread-db.c (record_thread): Likewise.
  * netbsd-nat.c (nbsd_add_threads): Likewise, this change was
  untested.
  (nbsd_nat_target::wait): Likewise.
  * nto-procfs.c (nto_procfs_target::update_thread_list): Likewise.
  * obsd-nat.c (obsd_nat_target::update_thread_list): Likewise.
  (obsd_nat_target::wait): Likewise.
  * process-stratum-target.c
  (process_stratum_target::follow_exec): After an exec, the new
  thread is add non-resumed.
  (process_stratum_target::follow_fork): Likewise after a fork.
  * procfs.c (do_attach): New threads are created resumed, this is
  untested.
  (procfs_target::wait): Likewise.
  (procfs_target::create_inferior): Likewise.
  (procfs_notice_thread): Likewise.
  * ravenscar-thread.c
  (ravenscar_thread_target::add_active_thread): New threads are
  created resumed, this is untested.
  (ravenscar_thread_target::add_thread): Likewise.
  * remote-sim.c (gdbsim_target::create_inferior): New thread is
  created resumed.
  * remote.c (remote_target::remote_add_thread): Likewise.
  (remote_target::add_current_inferior_and_thread): Add extra
  parameter, use this to control if the thread is started resumed or
  not.
  (remote_target::process_initial_stop_replies): Mark threads
  non-resumed.
  (remote_target::start_remote_1): Create thread resumed.
  * sol-thread.c (sol_thread_target::wait): Create thread resumed,
  this is untested.
  (sol_update_thread_list_callback): Likewise.
  * thread.c (add_thread_silent): Add extra parameter, print
  additional thread debug, mark the new thread resumed or not based
  on the parameter.
  (add_thread_with_info): Add an extra parameter, pass it through to
  add_thread_silent.
  (add_thread): Likewise.
  (thread_info::set_executing): Short cut the case where the
  executing flag is not changing state.  A thread must be resumed
  before it can be executing.  Print some additional debug
  information.
  (thread_info::set_resumed): A thread should not be executing when
  we adjust its resumed status.  Also, print some additional debug
  information.
  * tracectf.c (ctf_target_open): New thread is created non-resumed.
  * tracefile-tfile.c (tfile_target_open): Likewise.
  * windows-nat.c (windows_add_thread): New threads are created
  resumed, this has had only minimal testing.
---
 gdb/aix-thread.c             |   4 +-
 gdb/bsd-kvm.c                |   2 +-
 gdb/bsd-uthread.c            |   4 +-
 gdb/corelow.c                |   9 ++-
 gdb/darwin-nat.c             |   2 +-
 gdb/fbsd-nat.c               |   4 +-
 gdb/fork-child.c             |   3 +
 gdb/gdbthread.h              |  24 +++++---
 gdb/gnu-nat.c                |  13 ++++-
 gdb/go32-nat.c               |   2 +-
 gdb/inf-ptrace.c             |   4 +-
 gdb/infcmd.c                 |  75 +++++++++++++++++++-----
 gdb/infrun.c                 | 107 ++++++++++++++++++++++++++++++-----
 gdb/linux-nat.c              |   6 +-
 gdb/linux-thread-db.c        |   2 +-
 gdb/netbsd-nat.c             |   4 +-
 gdb/nto-procfs.c             |   2 +-
 gdb/obsd-nat.c               |   4 +-
 gdb/process-stratum-target.c |   4 +-
 gdb/procfs.c                 |  12 ++--
 gdb/ravenscar-thread.c       |   4 +-
 gdb/remote-sim.c             |   2 +-
 gdb/remote.c                 |  21 ++++---
 gdb/sol-thread.c             |   4 +-
 gdb/thread.c                 |  40 ++++++++++---
 gdb/tracectf.c               |   3 +-
 gdb/tracefile-tfile.c        |   2 +-
 gdb/windows-nat.c            |   4 +-
 28 files changed, 272 insertions(+), 95 deletions(-)

diff --git a/gdb/aix-thread.c b/gdb/aix-thread.c
index 6a4b469788a..cb571dcf894 100644
--- a/gdb/aix-thread.c
+++ b/gdb/aix-thread.c
@@ -809,7 +809,7 @@ sync_threadlists (void)
 	    = current_inferior ()->process_target ();
 	  thread = add_thread_with_info (proc_target,
 					 ptid_t (infpid, 0, pbuf[pi].pthid),
-					 priv);
+					 priv, true);
 
 	  pi++;
 	}
@@ -843,7 +843,7 @@ sync_threadlists (void)
 	    {
 	      process_stratum_target *proc_target
 		= current_inferior ()->process_target ();
-	      thread = add_thread (proc_target, pptid);
+	      thread = add_thread (proc_target, pptid, true);
 
 	      aix_thread_info *priv = new aix_thread_info;
 	      thread->priv.reset (priv);
diff --git a/gdb/bsd-kvm.c b/gdb/bsd-kvm.c
index 354df04ec0e..e3f230d828f 100644
--- a/gdb/bsd-kvm.c
+++ b/gdb/bsd-kvm.c
@@ -136,7 +136,7 @@ bsd_kvm_target_open (const char *arg, int from_tty)
   core_kd = temp_kd;
   current_inferior ()->push_target (&bsd_kvm_ops);
 
-  thread_info *thr = add_thread_silent (&bsd_kvm_ops, bsd_kvm_ptid);
+  thread_info *thr = add_thread_silent (&bsd_kvm_ops, bsd_kvm_ptid, false);
   switch_to_thread (thr);
 
   target_fetch_registers (get_current_regcache (), -1);
diff --git a/gdb/bsd-uthread.c b/gdb/bsd-uthread.c
index 5d5978d66ac..f6915c36aa5 100644
--- a/gdb/bsd-uthread.c
+++ b/gdb/bsd-uthread.c
@@ -422,7 +422,7 @@ bsd_uthread_target::wait (ptid_t ptid, struct target_waitstatus *status,
   /* Don't let the core see a ptid without a corresponding thread.  */
   thread_info *thread = find_thread_ptid (beneath, ptid);
   if (thread == NULL || thread->state == THREAD_EXITED)
-    add_thread (beneath, ptid);
+    add_thread (beneath, ptid, true);
 
   return ptid;
 }
@@ -480,7 +480,7 @@ bsd_uthread_target::update_thread_list ()
 	  if (inferior_ptid.tid () == 0)
 	    thread_change_ptid (proc_target, inferior_ptid, ptid);
 	  else
-	    add_thread (proc_target, ptid);
+	    add_thread (proc_target, ptid, true);
 	}
 
       addr = bsd_uthread_read_memory_address (addr + offset);
diff --git a/gdb/corelow.c b/gdb/corelow.c
index 1579e6bc2b8..9e3868530f9 100644
--- a/gdb/corelow.c
+++ b/gdb/corelow.c
@@ -347,7 +347,8 @@ add_to_thread_list (asection *asect, asection *reg_sect)
 
   ptid_t ptid (pid, lwpid);
 
-  thread_info *thr = add_thread (inf->process_target (), ptid);
+  /* Pass false to indicate the thread should be added non-resumed.  */
+  thread_info *thr = add_thread (inf->process_target (), ptid, false);
 
 /* Warning, Will Robinson, looking at BFD private data! */
 
@@ -505,7 +506,7 @@ core_target_open (const char *arg, int from_tty)
       if (thread == NULL)
 	{
 	  inferior_appeared (current_inferior (), CORELOW_PID);
-	  thread = add_thread_silent (target, ptid_t (CORELOW_PID));
+	  thread = add_thread_silent (target, ptid_t (CORELOW_PID), false);
 	}
 
       switch_to_thread (thread);
@@ -514,6 +515,10 @@ core_target_open (const char *arg, int from_tty)
   if (current_program_space->exec_bfd () == nullptr)
     locate_exec_from_corefile_build_id (core_bfd, from_tty);
 
+  /* Threads in a core file are not started resumed.  */
+  for (thread_info *thread : current_inferior ()->threads ())
+    gdb_assert (!thread->resumed ());
+
   post_create_inferior (from_tty);
 
   /* Now go through the target stack looking for threads since there
diff --git a/gdb/darwin-nat.c b/gdb/darwin-nat.c
index d96ce1a6c65..6e343b8b3df 100644
--- a/gdb/darwin-nat.c
+++ b/gdb/darwin-nat.c
@@ -351,7 +351,7 @@ darwin_nat_target::check_new_threads (inferior *inf)
 	  pti->msg_state = DARWIN_RUNNING;
 
 	  /* Add the new thread.  */
-	  add_thread_with_info (this, ptid_t (inf->pid, 0, new_id), pti);
+	  add_thread_with_info (this, ptid_t (inf->pid, 0, new_id), pti, true);
 	  new_thread_vec.push_back (pti);
 	  new_ix++;
 	  continue;
diff --git a/gdb/fbsd-nat.c b/gdb/fbsd-nat.c
index ae5af02693e..5380e257a8a 100644
--- a/gdb/fbsd-nat.c
+++ b/gdb/fbsd-nat.c
@@ -905,7 +905,7 @@ fbsd_add_threads (fbsd_nat_target *target, pid_t pid)
 	    continue;
 #endif
 	  fbsd_lwp_debug_printf ("adding thread for LWP %u", lwps[i]);
-	  add_thread (target, ptid);
+	  add_thread (target, ptid, true);
 	}
     }
 }
@@ -1250,7 +1250,7 @@ fbsd_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
 		{
 		  fbsd_lwp_debug_printf ("adding thread for LWP %u",
 					 pl.pl_lwpid);
-		  add_thread (this, wptid);
+		  add_thread (this, wptid, true);
 		}
 	      ourstatus->set_spurious ();
 	      return wptid;
diff --git a/gdb/fork-child.c b/gdb/fork-child.c
index 89895238c24..95f1608b10f 100644
--- a/gdb/fork-child.c
+++ b/gdb/fork-child.c
@@ -126,6 +126,9 @@ gdb_startup_inferior (pid_t pid, int num_traps)
   inferior *inf = current_inferior ();
   process_stratum_target *proc_target = inf->process_target ();
 
+  for (thread_info *thread : inf->threads ())
+    gdb_assert (thread->resumed ());
+
   ptid_t ptid = startup_inferior (proc_target, pid, num_traps, NULL, NULL);
 
   /* Mark all threads non-executing.  */
diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index 9921dae7a71..a47349879e7 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -367,6 +367,8 @@ class thread_info : public refcounted_object,
 
   void set_stop_pc (CORE_ADDR stop_pc)
   {
+    gdb_assert (!m_resumed);
+    gdb_assert (!m_executing);
     m_suspend.stop_pc = stop_pc;
   }
 
@@ -374,6 +376,11 @@ class thread_info : public refcounted_object,
 
   void clear_stop_pc ()
   {
+    /* This method is called from within thread_info::set_executing, and
+       so, at that point the thread should always be resumed, but not yet
+       executing.  */
+    gdb_assert (m_resumed);
+    gdb_assert (!m_executing);
     m_suspend.stop_pc.reset ();
   }
 
@@ -574,22 +581,25 @@ using inferior_ref
 /* Create an empty thread list, or empty the existing one.  */
 extern void init_thread_list (void);
 
-/* Add a thread to the thread list, print a message
-   that a new thread is found, and return the pointer to
-   the new thread.  Caller my use this pointer to 
-   initialize the private thread data.  */
+/* Add a thread to the thread list, print a message that a new thread is
+   found, and return the pointer to the new thread.  Caller my use this
+   pointer to initialize the private thread data.  When RESUMED_P is true
+   the thread is created in a resumed state, otherwise, the thread is
+   created in a non-resumed state.  */
 extern struct thread_info *add_thread (process_stratum_target *targ,
-				       ptid_t ptid);
+				       ptid_t ptid, bool resumed_p);
 
 /* Same as add_thread, but does not print a message about new
    thread.  */
 extern struct thread_info *add_thread_silent (process_stratum_target *targ,
-					      ptid_t ptid);
+					      ptid_t ptid,
+					      bool resumed_p);
 
 /* Same as add_thread, and sets the private info.  */
 extern struct thread_info *add_thread_with_info (process_stratum_target *targ,
 						 ptid_t ptid,
-						 private_thread_info *);
+						 private_thread_info *,
+						 bool resumed_p);
 
 /* Delete thread THREAD and notify of thread exit.  If the thread is
    currently not deletable, don't actually delete it but still tag it
diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c
index 9c53e3c0c2f..2a95986f84d 100644
--- a/gdb/gnu-nat.c
+++ b/gdb/gnu-nat.c
@@ -1085,9 +1085,9 @@ gnu_nat_target::inf_validate_procs (struct inf *inf)
 	      thread_change_ptid (this, inferior_ptid, ptid);
 	    else if (inf->pending_execs != 0)
 	      /* This is a shell thread.  */
-	      add_thread_silent (this, ptid);
+	      add_thread_silent (this, ptid, true);
 	    else
-	      add_thread (this, ptid);
+	      add_thread (this, ptid, true);
 	  }
       }
 
@@ -2120,7 +2120,7 @@ gnu_nat_target::create_inferior (const char *exec_file,
   /* We have something that executes now.  We'll be running through
      the shell at this point (if startup-with-shell is true), but the
      pid shouldn't change.  */
-  thread_info *thr = add_thread_silent (this, ptid_t (pid));
+  thread_info *thr = add_thread_silent (this, ptid_t (pid), true);
   switch_to_thread (thr);
 
   /* Attach to the now stopped child, which is actually a shell...  */
@@ -2187,6 +2187,13 @@ gnu_nat_target::attach (const char *args, int from_tty)
 
   inf_update_procs (inf);
 
+  /* After attaching all threads are stopped.  It would be better if
+     the threads were added in the stopped state, the only reason this
+     is not currently done is a lack of understanding of how threads
+     are managed on HURD.  */
+  for (thread_info *thr : current_inferior ()->non_exited_threads ())
+    thr->set_resumed (false);
+
   thread_info *thr
     = find_thread_ptid (this, ptid_t (pid, inf_pick_first_thread ()));
   switch_to_thread (thr);
diff --git a/gdb/go32-nat.c b/gdb/go32-nat.c
index 91fae3dd7f4..441b58cd46d 100644
--- a/gdb/go32-nat.c
+++ b/gdb/go32-nat.c
@@ -755,7 +755,7 @@ go32_nat_target::create_inferior (const char *exec_file,
   if (!inf->target_is_pushed (this))
     inf->push_target (this);
 
-  thread_info *thr = add_thread_silent (ptid_t (SOME_PID));
+  thread_info *thr = add_thread_silent (ptid_t (SOME_PID), true);
   switch_to_thread (thr);
 
   clear_proceed_status (0);
diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c
index 6e4706a3d20..be4c3f1c3f7 100644
--- a/gdb/inf-ptrace.c
+++ b/gdb/inf-ptrace.c
@@ -94,7 +94,7 @@ inf_ptrace_target::create_inferior (const char *exec_file,
   /* We have something that executes now.  We'll be running through
      the shell at this point (if startup-with-shell is true), but the
      pid shouldn't change.  */
-  thread_info *thr = add_thread_silent (this, ptid);
+  thread_info *thr = add_thread_silent (this, ptid, true);
   switch_to_thread (thr);
 
   unpusher.release ();
@@ -164,7 +164,7 @@ inf_ptrace_target::attach (const char *args, int from_tty)
 
   /* Always add a main thread.  If some target extends the ptrace
      target, it should decorate the ptid later with more info.  */
-  thread_info *thr = add_thread_silent (this, ptid_t (pid));
+  thread_info *thr = add_thread_silent (this, ptid_t (pid), true);
   switch_to_thread (thr);
 
   /* Don't consider the thread stopped until we've processed its
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 9f4ed8bff13..8fdd07eb199 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -238,28 +238,62 @@ post_create_inferior (int from_tty)
   /* Be sure we own the terminal in case write operations are performed.  */ 
   target_terminal::ours_for_output ();
 
+  if (debug_infrun)
+    {
+      infrun_debug_printf ("threads in the newly created inferior:");
+      for (thread_info *thread : current_inferior ()->non_exited_threads ())
+	infrun_debug_printf ("  thread %s, executing = %d, resumed = %d, "
+			     "state = %s",
+			     thread->ptid.to_string ().c_str (),
+			     thread->executing (),
+			     thread->resumed (),
+			     thread_state_string (thread->state));
+    }
+
+  /* When attaching to a multi-threaded process the "first" thread will be
+     stopped as part of the attach.  We then call stop_all_threads, which
+     will request that all threads stop.  When the first stop is processed
+     we will end up in here.
+
+     So, we expect that the "first" thread of the inferior should be
+     stopped, as well as one other random thread.  All of the other threads
+     should still be considered resumed, but will have a stop event
+     incoming.
+
+     As a consequence, we only make an assertion here about the currently
+     selected thread of the inferior.  Of the remaining threads, we only
+     expect one to be stopped, but we don't assert that.  */
+  gdb_assert (!inferior_thread ()->resumed ());
+
   /* If the target hasn't taken care of this already, do it now.
      Targets which need to access registers during to_open,
      to_create_inferior, or to_attach should do it earlier; but many
      don't need to.  */
   target_find_description ();
 
-  /* Now that we know the register layout, retrieve current PC.  But
-     if the PC is unavailable (e.g., we're opening a core file with
-     missing registers info), ignore it.  */
+  /* Now that we know the register layout, update the stop_pc if it is not
+     already set.  If GDB attached to a running process then the stop_pc
+     will have been set while processing the stop events triggered during
+     the attach.  If this is a core file, or we're just starting a new
+     process, then the stop_pc will not currently be set.
+
+     But, if the PC is unavailable (e.g., we're opening a core file with
+     missing registers info), ignore it.  Obviously, if we're trying to
+     debug a running process and we can't read the PC then this is bad and
+     shouldn't be ignored, but we'll soon hit errors trying to read the PC
+     elsewhere in GDB, so ignoring this here is fine.  */
   thread_info *thr = inferior_thread ();
-
-  thr->clear_stop_pc ();
-  try
-    {
-      regcache *rc = get_thread_regcache (thr);
-      thr->set_stop_pc (regcache_read_pc (rc));
-    }
-  catch (const gdb_exception_error &ex)
-    {
-      if (ex.error != NOT_AVAILABLE_ERROR)
-	throw;
-    }
+  if (!thr->stop_pc_p ())
+    try
+      {
+	regcache *rc = get_thread_regcache (thr);
+	thr->set_stop_pc (regcache_read_pc (rc));
+      }
+    catch (const gdb_exception_error &ex)
+      {
+	if (ex.error != NOT_AVAILABLE_ERROR)
+	  throw;
+      }
 
   if (current_program_space->exec_bfd ())
     {
@@ -453,6 +487,17 @@ run_command_1 (const char *args, int from_tty, enum run_how run_how)
      shouldn't refer to run_target again.  */
   run_target = NULL;
 
+  /* Threads are created as resumed, but not executing.  We now want to
+     mark the thread as non-resumed.  The thread will be moved back into
+     the resumed state later when we call proceed, however, if that fails
+     then we want to ensure the thread is left in a non-resumed state.  */
+  for (thread_info *thread : current_inferior ()->threads ())
+    {
+      gdb_assert (thread->resumed ());
+      gdb_assert (!thread->executing ());
+      thread->set_resumed (false);
+    }
+
   /* We're starting off a new process.  When we get out of here, in
      non-stop mode, finish the state of all threads of that process,
      but leave other threads alone, as they may be stopped in internal
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 793d83a17a6..53b1d0d43b3 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -599,7 +599,13 @@ holding the child stopped.  Try \"set detach-on-fork\" or \
   /* If there is a child inferior, target_follow_fork must have created a thread
      for it.  */
   if (child_inf != nullptr)
-    gdb_assert (!child_inf->thread_list.empty ());
+    {
+      gdb_assert (!child_inf->thread_list.empty ());
+
+      /* Any added thread should have been marked non-resumed already.  */
+      for (thread_info *thread : child_inf->threads ())
+	gdb_assert (!thread->resumed ());
+    }
 
   /* Clear the parent thread's pending follow field.  Do this before calling
      target_detach, so that the target can differentiate the two following
@@ -1115,6 +1121,7 @@ follow_exec (ptid_t ptid, const char *exec_file_target)
      breakpoint or similar, it's gone now.  We cannot truly
      step-to-next statement through an exec().  */
   thread_info *th = inferior_thread ();
+  gdb_assert (!th->resumed ());
   th->control.step_resume_breakpoint = NULL;
   th->control.exception_resume_breakpoint = NULL;
   th->control.single_step_breakpoints = NULL;
@@ -1196,6 +1203,11 @@ follow_exec (ptid_t ptid, const char *exec_file_target)
   gdb_assert (current_inferior () == inf);
   gdb_assert (current_program_space == inf->pspace);
 
+  /* After the exec, all threads in the inferior should be in a non-resumed
+     state.  */
+  for (thread_info *thread : inf->non_exited_threads ())
+    gdb_assert (!thread->resumed ());
+
   /* Attempt to open the exec file.  SYMFILE_DEFER_BP_RESET is used
      because the proper displacement for a PIE (Position Independent
      Executable) main symbol file will only be computed by
@@ -2143,6 +2155,54 @@ internal_resume_ptid (int user_step)
     return user_visible_resume_ptid (user_step);
 }
 
+/* Before calling into target code to set inferior threads executing we
+   must mark all threads as resumed.  If an exception is thrown while
+   trying to set the threads executing then we should mark the threads as
+   non-resumed.
+
+   Create an instance of this struct before calling the target_* API to
+   set the threads executing.  If the targets are successfully set
+   executing then call the .commit() method.  In all other cases, any
+   threads that were marked resumed will be returned to their non-resumed
+   state.  */
+
+struct scoped_mark_thread_resumed
+{
+  /* Constructor.  All threads matching PTID will be marked as resumed.  */
+  scoped_mark_thread_resumed (process_stratum_target *targ, ptid_t ptid)
+    : m_target (targ), m_ptid (ptid)
+  {
+    gdb_assert (m_target != nullptr);
+    set_resumed (m_target, m_ptid, true);
+  }
+
+  /* Destructor.  If this instance was not committed (by calling the commit
+     method) then mark all threads matching M_PTID as no longer being
+     resumed.  */
+  ~scoped_mark_thread_resumed ()
+  {
+    if (m_target != nullptr)
+      set_resumed (m_target, m_ptid, false);
+  }
+
+  /* Called once all of the threads have successfully be set executing (by
+     calling the target_* API).  After this call the threads this object
+     marked as resumed will be left in the resumed state when the
+     destructor runs.  */
+  void commit ()
+  {
+    m_target = nullptr;
+  }
+
+private:
+
+  /* The target used for marking threads as resumed or non-resumed.  */
+  process_stratum_target *m_target;
+
+  /* The thread (or threads) to mark as resumed.  */
+  ptid_t m_ptid;
+};
+
 /* Wrapper for target_resume, that handles infrun-specific
    bookkeeping.  */
 
@@ -2151,6 +2211,11 @@ do_target_resume (ptid_t resume_ptid, bool step, enum gdb_signal sig)
 {
   struct thread_info *tp = inferior_thread ();
 
+  /* Create a scoped_mark_thread_resumed to mark all threads matching
+     RESUME_PTID as resumed.  */
+  process_stratum_target *curr_target = current_inferior ()->process_target ();
+  scoped_mark_thread_resumed scoped_resume (curr_target, resume_ptid);
+
   gdb_assert (!tp->stop_requested);
 
   /* Install inferior's terminal modes.  */
@@ -2189,6 +2254,9 @@ do_target_resume (ptid_t resume_ptid, bool step, enum gdb_signal sig)
 
   if (target_can_async_p ())
     target_async (1);
+
+  /* Call commit so SCOPED_RESUME leaves threads marked as resumed.  */
+  scoped_resume.commit ();
 }
 
 /* Resume the inferior.  SIG is the signal to give the inferior
@@ -2348,7 +2416,6 @@ resume_1 (enum gdb_signal sig)
 
 	      resume_ptid = internal_resume_ptid (user_step);
 	      do_target_resume (resume_ptid, false, GDB_SIGNAL_0);
-	      tp->set_resumed (true);
 	      return;
 	    }
 	}
@@ -2557,7 +2624,6 @@ resume_1 (enum gdb_signal sig)
     }
 
   do_target_resume (resume_ptid, step, sig);
-  tp->set_resumed (true);
 }
 
 /* Resume the inferior.  SIG is the signal to give the inferior
@@ -4822,7 +4888,7 @@ handle_one (const wait_one_event &event)
 	     Don't bother adding if it individually exited.  */
 	  if (t == nullptr
 	      && event.ws.kind () != TARGET_WAITKIND_THREAD_EXITED)
-	    t = add_thread (event.target, event.ptid);
+	    t = add_thread (event.target, event.ptid, true);
 	}
 
       if (t != nullptr)
@@ -4840,7 +4906,7 @@ handle_one (const wait_one_event &event)
     {
       thread_info *t = find_thread_ptid (event.target, event.ptid);
       if (t == NULL)
-	t = add_thread (event.target, event.ptid);
+	t = add_thread (event.target, event.ptid, true);
 
       t->stop_requested = 0;
       t->set_executing (false);
@@ -4925,7 +4991,19 @@ stop_all_threads (void)
 
   gdb_assert (exists_non_stop_target ());
 
-  infrun_debug_printf ("starting");
+  INFRUN_SCOPED_DEBUG_ENTER_EXIT;
+
+  if (debug_infrun)
+    {
+      infrun_debug_printf ("non-exited threads:");
+      for (thread_info *thread : all_non_exited_threads ())
+	infrun_debug_printf ("  thread %s, executing = %d, resumed = %d, "
+			     "state = %s",
+			     thread->ptid.to_string ().c_str (),
+			     thread->executing (),
+			     thread->resumed (),
+			     thread_state_string (thread->state));
+    }
 
   scoped_restore_current_thread restore_thread;
 
@@ -5236,7 +5314,7 @@ handle_inferior_event (struct execution_control_state *ecs)
       ecs->event_thread = find_thread_ptid (ecs->target, ecs->ptid);
       /* If it's a new thread, add it to the thread database.  */
       if (ecs->event_thread == NULL)
-	ecs->event_thread = add_thread (ecs->target, ecs->ptid);
+	ecs->event_thread = add_thread (ecs->target, ecs->ptid, true);
 
       /* Disable range stepping.  If the next step request could use a
 	 range, this will be end up re-enabled then.  */
@@ -5651,6 +5729,10 @@ handle_inferior_event (struct execution_control_state *ecs)
 	 execd thread for that case (this is a nop otherwise).  */
       ecs->event_thread = inferior_thread ();
 
+      /* If we did switch threads above, then the new thread should still
+	 be in the non-resumed state.  */
+      gdb_assert (!ecs->event_thread->resumed ());
+
       ecs->event_thread->set_stop_pc
 	(regcache_read_pc (get_thread_regcache (ecs->event_thread)));
 
@@ -5895,12 +5977,6 @@ finish_step_over (struct execution_control_state *ecs)
 
 	  /* Record the event thread's event for later.  */
 	  save_waitstatus (tp, ecs->ws);
-	  /* This was cleared early, by handle_inferior_event.  Set it
-	     so this pending event is considered by
-	     do_target_wait.  */
-	  tp->set_resumed (true);
-
-	  gdb_assert (!tp->executing ());
 
 	  regcache = get_thread_regcache (tp);
 	  tp->set_stop_pc (regcache_read_pc (regcache));
@@ -5911,6 +5987,10 @@ finish_step_over (struct execution_control_state *ecs)
 			       tp->ptid.to_string ().c_str (),
 			       currently_stepping (tp));
 
+	  /* This was cleared early, by handle_inferior_event.  Set it so
+	     this pending event is considered by do_target_wait.  */
+	  tp->set_resumed (true);
+
 	  /* This in-line step-over finished; clear this so we won't
 	     start a new one.  This is what handle_signal_stop would
 	     do, if we returned false.  */
@@ -7560,7 +7640,6 @@ keep_going_stepped_thread (struct thread_info *tp)
 				     get_frame_address_space (frame),
 				     tp->stop_pc ());
 
-      tp->set_resumed (true);
       resume_ptid = internal_resume_ptid (tp->control.stepping_command);
       do_target_resume (resume_ptid, false, GDB_SIGNAL_0);
     }
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index b926fb5eba9..682098e6c5e 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -1141,7 +1141,7 @@ attach_proc_task_lwp_callback (ptid_t ptid)
 	  /* Also add the LWP to gdb's thread list, in case a
 	     matching libthread_db is not found (or the process uses
 	     raw clone).  */
-	  add_thread (linux_target, lp->ptid);
+	  add_thread (linux_target, lp->ptid, true);
 	  set_running (linux_target, lp->ptid, true);
 	  set_executing (linux_target, lp->ptid, true);
 	}
@@ -2030,7 +2030,7 @@ linux_handle_extended_wait (struct lwp_info *lp, int status)
 	      /* The process is not using thread_db.  Add the LWP to
 		 GDB's list.  */
 	      target_post_attach (new_lp->ptid.lwp ());
-	      add_thread (linux_target, new_lp->ptid);
+	      add_thread (linux_target, new_lp->ptid, true);
 	    }
 
 	  /* Even if we're stopping the thread for some reason
@@ -2912,7 +2912,7 @@ linux_nat_filter_event (int lwpid, int status)
       lp = add_lwp (ptid_t (lwpid, lwpid));
       lp->stopped = 1;
       lp->resumed = 1;
-      add_thread (linux_target, lp->ptid);
+      add_thread (linux_target, lp->ptid, true);
     }
 
   if (WIFSTOPPED (status) && !lp)
diff --git a/gdb/linux-thread-db.c b/gdb/linux-thread-db.c
index a0cfeb1685b..f1c61d3f91c 100644
--- a/gdb/linux-thread-db.c
+++ b/gdb/linux-thread-db.c
@@ -1373,7 +1373,7 @@ record_thread (struct thread_db_info *info,
      thread with this PTID, but it's marked exited, then the kernel
      reused the tid of an old thread.  */
   if (tp == NULL || tp->state == THREAD_EXITED)
-    tp = add_thread_with_info (info->process_target, ptid, priv);
+    tp = add_thread_with_info (info->process_target, ptid, priv, true);
   else
     tp->priv.reset (priv);
 
diff --git a/gdb/netbsd-nat.c b/gdb/netbsd-nat.c
index 1463305acc8..ab2004672ba 100644
--- a/gdb/netbsd-nat.c
+++ b/gdb/netbsd-nat.c
@@ -125,7 +125,7 @@ nbsd_add_threads (nbsd_nat_target *target, pid_t pid)
 	    if (inferior_ptid.lwp () == 0)
 	      thread_change_ptid (target, inferior_ptid, ptid);
 	    else
-	      add_thread (target, ptid);
+	      add_thread (target, ptid, true);
 	  }
       };
 
@@ -652,7 +652,7 @@ nbsd_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
 	  ourstatus->set_spurious ();
       else
 	{
-	  add_thread (this, wptid);
+	  add_thread (this, wptid, true);
 	  ourstatus->set_thread_created ();
 	}
       return wptid;
diff --git a/gdb/nto-procfs.c b/gdb/nto-procfs.c
index da0feaedff9..46d5cdae506 100644
--- a/gdb/nto-procfs.c
+++ b/gdb/nto-procfs.c
@@ -411,7 +411,7 @@ nto_procfs_target::update_thread_list ()
       ptid = ptid_t (pid, 0, tid);
       new_thread = find_thread_ptid (this, ptid);
       if (!new_thread)
-	new_thread = add_thread (ptid);
+	new_thread = add_thread (ptid, true);
       update_thread_private_data (new_thread, tid, status.state, 0);
       status.tid++;
     }
diff --git a/gdb/obsd-nat.c b/gdb/obsd-nat.c
index c313e807d9b..f3ff1a3720d 100644
--- a/gdb/obsd-nat.c
+++ b/gdb/obsd-nat.c
@@ -62,7 +62,7 @@ obsd_nat_target::update_thread_list ()
 	  if (inferior_ptid.lwp () == 0)
 	    thread_change_ptid (this, inferior_ptid, ptid);
 	  else
-	    add_thread (this, ptid);
+	    add_thread (this, ptid, true);
 	}
 
       if (ptrace (PT_GET_THREAD_NEXT, pid, (caddr_t)&pts, sizeof pts) == -1)
@@ -133,7 +133,7 @@ obsd_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
 	  if (in_thread_list (this, ptid_t (pid)))
 	    thread_change_ptid (this, ptid_t (pid), wptid);
 	  else
-	    add_thread (this, wptid);
+	    add_thread (this, wptid, true);
 	}
     }
   return wptid;
diff --git a/gdb/process-stratum-target.c b/gdb/process-stratum-target.c
index 50bb13e4b83..b9eb8fbc990 100644
--- a/gdb/process-stratum-target.c
+++ b/gdb/process-stratum-target.c
@@ -100,7 +100,7 @@ process_stratum_target::follow_exec (inferior *follow_inf, ptid_t ptid,
 	 may decide to unpush itself from the original inferior's target stack
 	 after that, at its discretion.  */
       follow_inf->push_target (orig_inf->process_target ());
-      thread_info *t = add_thread (follow_inf->process_target (), ptid);
+      thread_info *t = add_thread (follow_inf->process_target (), ptid, false);
 
       /* Leave the new inferior / thread as the current inferior / thread.  */
       switch_to_thread (t);
@@ -118,7 +118,7 @@ process_stratum_target::follow_fork (inferior *child_inf, ptid_t child_ptid,
   if (child_inf != nullptr)
     {
       child_inf->push_target (this);
-      add_thread_silent (this, child_ptid);
+      add_thread_silent (this, child_ptid, false);
     }
 }
 
diff --git a/gdb/procfs.c b/gdb/procfs.c
index 840201d1897..14e3ada3d5a 100644
--- a/gdb/procfs.c
+++ b/gdb/procfs.c
@@ -1863,7 +1863,7 @@ do_attach (ptid_t ptid)
 
   /* Add it to gdb's thread list.  */
   ptid = ptid_t (pi->pid, lwpid, 0);
-  thread_info *thr = add_thread (&the_procfs_target, ptid);
+  thread_info *thr = add_thread (&the_procfs_target, ptid, true);
   switch_to_thread (thr);
 }
 
@@ -2221,7 +2221,7 @@ procfs_target::wait (ptid_t ptid, struct target_waitstatus *status,
 		    temp_ptid = ptid_t (pi->pid, temp_tid, 0);
 		    /* If not in GDB's thread list, add it.  */
 		    if (!in_thread_list (this, temp_ptid))
-		      add_thread (this, temp_ptid);
+		      add_thread (this, temp_ptid, true);
 
 		    target_continue_no_signal (ptid);
 		    goto wait_again;
@@ -2280,7 +2280,7 @@ procfs_target::wait (ptid_t ptid, struct target_waitstatus *status,
 		    /* If not in GDB's thread list, add it.  */
 		    temp_ptid = ptid_t (pi->pid, temp_tid, 0);
 		    if (!in_thread_list (this, temp_ptid))
-		      add_thread (this, temp_ptid);
+		      add_thread (this, temp_ptid, true);
 
 		    status->set_stopped (GDB_SIGNAL_0);
 		    return retval;
@@ -2311,7 +2311,7 @@ procfs_target::wait (ptid_t ptid, struct target_waitstatus *status,
 		  /* We have a new thread.  We need to add it both to
 		     GDB's list and to our own.  If we don't create a
 		     procinfo, resume may be unhappy later.  */
-		  add_thread (this, retval);
+		  add_thread (this, retval, true);
 		  if (find_procinfo (retval.pid (),
 				     retval.lwp ()) == NULL)
 		    create_procinfo (retval.pid (),
@@ -2847,7 +2847,7 @@ procfs_target::create_inferior (const char *exec_file,
   /* We have something that executes now.  We'll be running through
      the shell at this point (if startup-with-shell is true), but the
      pid shouldn't change.  */
-  thread_info *thr = add_thread_silent (this, ptid_t (pid));
+  thread_info *thr = add_thread_silent (this, ptid_t (pid), true);
   switch_to_thread (thr);
 
   procfs_init_inferior (pid);
@@ -2862,7 +2862,7 @@ procfs_notice_thread (procinfo *pi, procinfo *thread, void *ptr)
 
   thread_info *thr = find_thread_ptid (&the_procfs_target, gdb_threadid);
   if (thr == NULL || thr->state == THREAD_EXITED)
-    add_thread (&the_procfs_target, gdb_threadid);
+    add_thread (&the_procfs_target, gdb_threadid, true);
 
   return 0;
 }
diff --git a/gdb/ravenscar-thread.c b/gdb/ravenscar-thread.c
index 5f040cece07..5ca9617e0bc 100644
--- a/gdb/ravenscar-thread.c
+++ b/gdb/ravenscar-thread.c
@@ -283,7 +283,7 @@ ravenscar_thread_target::add_active_thread ()
   thread_info *active_thr = find_thread_ptid (proc_target, active_ptid);
   if (active_thr == nullptr)
     {
-      active_thr = ::add_thread (proc_target, active_ptid);
+      active_thr = ::add_thread (proc_target, active_ptid, true);
       m_cpu_map[active_ptid.tid ()] = base_cpu;
     }
   return active_thr;
@@ -420,7 +420,7 @@ ravenscar_thread_target::add_thread (struct ada_task_info *task)
 {
   if (find_thread_ptid (current_inferior (), task->ptid) == NULL)
     {
-      ::add_thread (current_inferior ()->process_target (), task->ptid);
+      ::add_thread (current_inferior ()->process_target (), task->ptid, true);
       m_cpu_map[task->ptid.tid ()] = task->base_cpu;
     }
 }
diff --git a/gdb/remote-sim.c b/gdb/remote-sim.c
index 3637fdb18bf..06322fc2dc6 100644
--- a/gdb/remote-sim.c
+++ b/gdb/remote-sim.c
@@ -660,7 +660,7 @@ gdbsim_target::create_inferior (const char *exec_file,
 
   inferior_appeared (current_inferior (),
 		     sim_data->remote_sim_ptid.pid ());
-  thread_info *thr = add_thread_silent (this, sim_data->remote_sim_ptid);
+  thread_info *thr = add_thread_silent (this, sim_data->remote_sim_ptid, true);
   switch_to_thread (thr);
 
   insert_breakpoints ();	/* Needed to get correct instruction
diff --git a/gdb/remote.c b/gdb/remote.c
index b126532af45..0589da29c3e 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -740,7 +740,8 @@ class remote_target : public process_stratum_target
   int remote_resume_with_vcont (ptid_t ptid, int step,
 				gdb_signal siggnal);
 
-  thread_info *add_current_inferior_and_thread (const char *wait_status);
+  thread_info *add_current_inferior_and_thread (const char *wait_status,
+						bool resumed_p);
 
   ptid_t wait_ns (ptid_t ptid, struct target_waitstatus *status,
 		  target_wait_flags options);
@@ -2568,16 +2569,17 @@ remote_target::remote_add_thread (ptid_t ptid, bool running, bool executing,
      might be confusing to the user.  Be silent then, preserving the
      age old behavior.  */
   if (rs->starting_up || silent_p)
-    thread = add_thread_silent (this, ptid);
+    thread = add_thread_silent (this, ptid, true);
   else
-    thread = add_thread (this, ptid);
+    thread = add_thread (this, ptid, true);
 
   /* 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_resumed (this, ptid, running);
+  set_executing (this, ptid, executing);
 
   return thread;
 }
@@ -4470,7 +4472,8 @@ remote_target::get_current_thread (const char *wait_status)
    The function returns pointer to the main thread of the inferior. */
 
 thread_info *
-remote_target::add_current_inferior_and_thread (const char *wait_status)
+remote_target::add_current_inferior_and_thread (const char *wait_status,
+						bool resumed_p)
 {
   struct remote_state *rs = get_remote_state ();
   bool fake_pid_p = false;
@@ -4501,7 +4504,7 @@ remote_target::add_current_inferior_and_thread (const char *wait_status)
   /* Add the main thread and switch to it.  Don't try reading
      registers yet, since we haven't fetched the target description
      yet.  */
-  thread_info *tp = add_thread_silent (this, curr_ptid);
+  thread_info *tp = add_thread_silent (this, curr_ptid, resumed_p);
   switch_to_thread_no_regs (tp);
 
   return tp;
@@ -4611,6 +4614,7 @@ remote_target::process_initial_stop_replies (int from_tty)
 	evthread->set_pending_waitstatus (ws);
 
       set_executing (this, event_ptid, false);
+      set_resumed (this, event_ptid, false);
       set_running (this, event_ptid, false);
       get_remote_thread_info (evthread)->set_not_resumed ();
     }
@@ -4905,7 +4909,8 @@ remote_target::start_remote_1 (int from_tty, int extended_p)
 	  /* Target has no concept of threads at all.  GDB treats
 	     non-threaded target as single-threaded; add a main
 	     thread.  */
-	  thread_info *tp = add_current_inferior_and_thread (wait_status);
+	  thread_info *tp
+	    = add_current_inferior_and_thread (wait_status, true);
 	  get_remote_thread_info (tp)->set_resumed ();
 	}
       else
@@ -10488,7 +10493,7 @@ Remote replied unexpectedly while setting startup-with-shell: %s"),
 
   /* vRun's success return is a stop reply.  */
   stop_reply = run_worked ? rs->buf.data () : NULL;
-  add_current_inferior_and_thread (stop_reply);
+  add_current_inferior_and_thread (stop_reply, true);
 
   /* Get updated offsets, if the stub uses qOffsets.  */
   get_offsets ();
diff --git a/gdb/sol-thread.c b/gdb/sol-thread.c
index 44e990b6e5f..e551a613d28 100644
--- a/gdb/sol-thread.c
+++ b/gdb/sol-thread.c
@@ -456,7 +456,7 @@ sol_thread_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
 	    {
 	      process_stratum_target *proc_target
 		= current_inferior ()->process_target ();
-	      add_thread (proc_target, rtnval);
+	      add_thread (proc_target, rtnval, true);
 	    }
 	}
     }
@@ -1008,7 +1008,7 @@ sol_update_thread_list_callback (const td_thrhandle_t *th, void *ignored)
     {
       process_stratum_target *proc_target
 	= current_inferior ()->process_target ();
-      add_thread (proc_target, ptid);
+      add_thread (proc_target, ptid, true);
     }
 
   return 0;
diff --git a/gdb/thread.c b/gdb/thread.c
index c43f6613145..c94364ba3f9 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -261,15 +261,15 @@ new_thread (struct inferior *inf, ptid_t ptid)
 }
 
 struct thread_info *
-add_thread_silent (process_stratum_target *targ, ptid_t ptid)
+add_thread_silent (process_stratum_target *targ, ptid_t ptid, bool resumed_p)
 {
   gdb_assert (targ != nullptr);
 
   inferior *inf = find_inferior_ptid (targ, ptid);
 
-  threads_debug_printf ("add thread to inferior %d, ptid %s, target %s",
-			inf->num, ptid.to_string ().c_str (),
-			targ->shortname ());
+  threads_debug_printf
+    ("add thread to inferior %d, ptid %s, target %s, resumed_p = %d",
+     inf->num, ptid.to_string ().c_str (), targ->shortname (), resumed_p);
 
   /* We may have an old thread with the same id in the thread list.
      If we do, it must be dead, otherwise we wouldn't be adding a new
@@ -280,6 +280,14 @@ add_thread_silent (process_stratum_target *targ, ptid_t ptid)
     delete_thread (tp);
 
   tp = new_thread (inf, ptid);
+
+  /* Upon creation, all threads are non-executing, and non-resumed.  Before
+     notifying observers of the new thread, we set the resumed flag to the
+     desired value.  */
+  gdb_assert (!tp->executing ());
+  tp->set_resumed (resumed_p);
+
+  /* Announce the new thread to all observers.  */
   gdb::observers::new_thread.notify (tp);
 
   return tp;
@@ -287,9 +295,9 @@ add_thread_silent (process_stratum_target *targ, ptid_t ptid)
 
 struct thread_info *
 add_thread_with_info (process_stratum_target *targ, ptid_t ptid,
-		      private_thread_info *priv)
+		      private_thread_info *priv, bool resumed_p)
 {
-  thread_info *result = add_thread_silent (targ, ptid);
+  thread_info *result = add_thread_silent (targ, ptid, resumed_p);
 
   result->priv.reset (priv);
 
@@ -301,9 +309,9 @@ add_thread_with_info (process_stratum_target *targ, ptid_t ptid,
 }
 
 struct thread_info *
-add_thread (process_stratum_target *targ, ptid_t ptid)
+add_thread (process_stratum_target *targ, ptid_t ptid, bool resumed_p)
 {
-  return add_thread_with_info (targ, ptid, NULL);
+  return add_thread_with_info (targ, ptid, NULL, resumed_p);
 }
 
 private_thread_info::~private_thread_info () = default;
@@ -342,9 +350,18 @@ thread_info::deletable () const
 void
 thread_info::set_executing (bool executing)
 {
-  m_executing = executing;
+  if (executing == m_executing)
+    return;
+
+  gdb_assert (m_resumed);
+
   if (executing)
     this->clear_stop_pc ();
+
+  threads_debug_printf ("ptid = %s, executing = %d",
+			this->ptid.to_string ().c_str (),
+			executing);
+  m_executing = executing;
 }
 
 /* See gdbthread.h.  */
@@ -355,6 +372,8 @@ thread_info::set_resumed (bool resumed)
   if (resumed == m_resumed)
     return;
 
+  gdb_assert (!m_executing);
+
   process_stratum_target *proc_target = this->inf->process_target ();
 
   /* If we transition from resumed to not resumed, we might need to remove
@@ -362,6 +381,9 @@ thread_info::set_resumed (bool resumed)
   if (!resumed)
     proc_target->maybe_remove_resumed_with_pending_wait_status (this);
 
+  threads_debug_printf ("ptid = %s, resumed = %d",
+			this->ptid.to_string ().c_str (),
+			resumed);
   m_resumed = resumed;
 
   /* If we transition from not resumed to resumed, we might need to add
diff --git a/gdb/tracectf.c b/gdb/tracectf.c
index f0cc5ce7bcb..26940be0069 100644
--- a/gdb/tracectf.c
+++ b/gdb/tracectf.c
@@ -1169,7 +1169,8 @@ ctf_target_open (const char *dirname, int from_tty)
 
   inferior_appeared (current_inferior (), CTF_PID);
 
-  thread_info *thr = add_thread_silent (&ctf_ops, ptid_t (CTF_PID));
+  /* Pass false to indicate the thread starts in a non-resumed state.  */
+  thread_info *thr = add_thread_silent (&ctf_ops, ptid_t (CTF_PID), false);
   switch_to_thread (thr);
 
   merge_uploaded_trace_state_variables (&uploaded_tsvs);
diff --git a/gdb/tracefile-tfile.c b/gdb/tracefile-tfile.c
index dae90bc439a..0926832f8d7 100644
--- a/gdb/tracefile-tfile.c
+++ b/gdb/tracefile-tfile.c
@@ -557,7 +557,7 @@ tfile_target_open (const char *arg, int from_tty)
 
   inferior_appeared (current_inferior (), TFILE_PID);
 
-  thread_info *thr = add_thread_silent (&tfile_ops, ptid_t (TFILE_PID));
+  thread_info *thr = add_thread_silent (&tfile_ops, ptid_t (TFILE_PID), false);
   switch_to_thread (thr);
 
   if (ts->traceframe_count <= 0)
diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
index bdf6ac93c49..134a55ae391 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -380,9 +380,9 @@ windows_add_thread (ptid_t ptid, HANDLE h, void *tlb, bool main_thread_p)
      the main thread silently (in reality, this thread is really
      more of a process to the user than a thread).  */
   if (main_thread_p)
-    add_thread_silent (&the_windows_nat_target, ptid);
+    add_thread_silent (&the_windows_nat_target, ptid, true);
   else
-    add_thread (&the_windows_nat_target, ptid);
+    add_thread (&the_windows_nat_target, ptid, true);
 
   /* It's simplest to always set this and update the debug
      registers.  */
-- 
2.25.4


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCHv3] gdb: make thread_info executing and resumed state more consistent
  2022-01-13 18:34   ` [PATCHv3] " Andrew Burgess via Gdb-patches
@ 2022-01-14 17:10     ` Simon Marchi via Gdb-patches
  2022-02-24 15:52       ` Andrew Burgess via Gdb-patches
  2022-04-21 16:45     ` [PATCHv4 0/2] Make " Andrew Burgess via Gdb-patches
  1 sibling, 1 reply; 30+ messages in thread
From: Simon Marchi via Gdb-patches @ 2022-01-14 17:10 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches; +Cc: Andrew Burgess

On 2022-01-13 1:34 p.m., Andrew Burgess wrote:
> From: Andrew Burgess <andrew.burgess@embecosm.com>
>
> I finally got back around to working on this patch, and have a new
> version that I'd like to propose.
>
> The biggest change in this version is that all of the thread creation
> functions now have a new parameter which controls if the thread is
> started resumed or not.
>
> There was also a great discussion last time about whether the
> executing and resumed flags (within thread_info) should be combined
> into a single enum.  Simon argued in favour of this change, while I
> remain unconvinced.
>
> For now, I'd like to propose that the enum change be deferred.  The
> patch as it stands is already pretty large, and changing how we manage
> the two flags would only make the patch larger.  The change as I have
> it right now maintains the flags as they are, but makes their use
> consistent.  If we later want to change the flags to an enum then it
> feels like this would be better done as a separate step.
>
> There are still things that I would like to improve in the area of
> this code, I'm still not completely happy with how the thread state is
> managed around the target_ops::create_inferior call, but I though the
> code as it stands isn't great, at least things are consistent after
> this patch.
>
> I'm as sure as I feel I can be that I've not broken anything for
> Linux, but it's almost certain that something will be broken for other
> targets.  I've details the additional testing I've done at the end of
> my commit message.
>
> My commit message also includes a ChangeLog like log, in this I've
> tried to mention those areas of the change that I know are untested,
> or lightly tested.
>
> I welcome all review feedback, as well as any additional testing that
> people might like to do.
>
> Thanks,
> Andrew
>
> ---
>
> This commit was inspired by this comment from Simon:
>
>   https://sourceware.org/pipermail/gdb-patches/2021-July/180694.html
>
> The comment is about two thread_info flags m_executing and m_resumed.
> The m_resumed flag indicates that at the infrun level GDB has set the
> thread running, while the m_executing flag indicates that the thread
> is actually running at the target level.
>
> It is very common that a thread can be m_resumed, but not m_executing,
> that is, core GDB thinks the thread is, or should be, running, but at
> the target level the thread isn't currently running.
>
> The comment Simon made was in reply to a patch I posted where I found
> a case where a thread was marked m_executing, but not m_resumed, that
> is, at the infrun level GDB thought the thread was stopped, but at the
> target level the thread was actually running.  Simon suggests that
> this feels like an invalid state, and after thinking about it, I
> agree.
>
> So, the goal of this commit is to add some asserts to GDB.  The core
> idea here is that the resumed and executing flags should only change
> in the following pattern, to begin with everything is set false:
>
>   Resumed: false
>   Executing: false
>
> Then infrun marks the thread resumed:
>
>   Resumed: true
>   Executing: false
>
> Then a target starts the thread executing:
>
>   Resumed: true
>   Executing: true
>
> The thread stops, the target spots this and marks the thread no longer
> executing:
>
>   Resumed: true
>   Executing: false
>
> And finally, infrun acknowledges that the thread is now no longer
> resumed:
>
>   Resumed: false
>   Executing: false
>
> Notice that at no point is resumed false, while executing is true.
>
> And so we can add these asserts:
>
>  1. The resumed flag should only change state when the executing flag
>  is false, and
>
>  2. The executing flag should only change state when the resumed flag
>  is true.
>
> I added these asserts and ....
>
> .... it turns out these rules are broken all over the place in GDB, we
> have problems like:
>
>  (a) When new threads appear they are marked executing, but not
>  resumed, and
>
>  (b) In some places we mark a single thread as resumed, but then
>  actually set multiple threads executing.
>
> For (a) it could be argued that this is a legitimate state - this is
> actually the problem I addressed in the original patch that Simon was
> replying too, however, we don't need to support this as a separate
> state, so if we can make this case follow the expected set of state
> transitions then it allows us to reduce the number of states that GDB
> can be in, which I think is a good thing.
>
> Case (b) seems to just be a bug to me.
>
> My initial approach was to retain the idea that threads are always
> created in the non-executing, non-resumed state, and then find all the
> places where new threads are created (which should be in the resumed
> state), and mark the thread resumed in that case.
>
> However, after looking at the changes for a while, it felt like it
> would be simpler to create threads as resumed by default and instead
> change the threads back to non-resumed in the few cases where this was
> appropriate.  The appropriate case being (as far as I can tell), just
> the initial threads created as part of starting up a new inferior.
>
> So, that's what this patch does.  The thread creation routines now
> take a flag to indicate if the new thread should be created resumed or
> not.  Almost all threads are started in the resumed state, except for
> a few cases associated with initial target creation.
>
> In an ideal world, I would have liked that all threads created as part
> of the ::create_inferior process would also be created in the
> non-resumed state, but that doesn't seem easily achievable right now.
> Though I could easily see changing the Linux target, other targets that
> I can't test will be harder to get right.  So, for now, after calling
> ::create_process I assert that the threads are currently resumed, and
> then mark the threads as non-resumed.
>
> I do have a plan that I might be able to make further improvements in
> the ::create_inferior area, however, I want to see whether this patch
> is accepted first before investing further time on this.  I think that
> where this patch gets to is good enough for now.
>
> On Testing:
>
> I've tested this primarily on x86-64 GNU/Linux with the unix,
> native-gdbserver, and native-extended-gdbserver boards, and see no
> regressions.
>
> I have also tried to test some other targets, though the testing has
> been pretty minimal:
>
> I installed FreeBSD in an x86-64 VM.  I can build GDB fine, but when I
> try to run dejagnu the VM falls over with an out of swap space error,
> no matter how much swap I give the machine.  However, before falling
> over a few hundred tests do run, and I see no regressions in those
> tests.  I've also manually checked that the gdb.base/attach.exp test
> works (to do some basic attach testing).  So I'm reasonably confident
> that this target should be mostly OK.
>
> As I was working on GNU/Hurd for another bug I had an i386 GNU/Hurd VM
> available, so I built GDB in here too.  Due to other issues with this
> target the dejagnu testing is pretty useless here, but I checked that
> I can start multi-threaded targets, step/continue past thread
> creation, and also that I can attach to a multi-threaded target.
>
> I have also built this branch on Windows, using mingw.  I was unable
> to get dejagnu testing working on this target, but again I did some
> basic testing that GDB could start up with multi-threaded inferiors,
> and correctly see new threads as they appear.
>
> I also built a target with a simulator, and checked that I could
> startup and run basic tests their too.
>
> I did try making use of the GCC machine farm to test on AIX and
> Solaris, but I was unable to get GDB building on any of the machines I
> tried in the farm.

Hi Andrew,

I see nothing in the patch that stands out as obviously wrong.  But like
you, I have a hard time convincing myself what is the right resumed
state to pass to add_thread at each place.  And I'm not sure that just
staring at the code longer will help much.  It's hard to know without
actually testing.

For example, I am not sure that passing "true" in all update_thread_list
methods is correct.  update_thread_list is sometimes called when
everything is stopped, on all-stop targets.  So in that context, I
suppose that new threads discovered this way should be created
non-resumed.

However, I think you did a pretty good job of testing what you could,
given the context.

Simon

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCHv3] gdb: make thread_info executing and resumed state more consistent
  2022-01-14 17:10     ` Simon Marchi via Gdb-patches
@ 2022-02-24 15:52       ` Andrew Burgess via Gdb-patches
  2022-03-03 19:42         ` Simon Marchi via Gdb-patches
  2022-03-30  9:19         ` Andrew Burgess via Gdb-patches
  0 siblings, 2 replies; 30+ messages in thread
From: Andrew Burgess via Gdb-patches @ 2022-02-24 15:52 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches; +Cc: Andrew Burgess

Simon Marchi via Gdb-patches <gdb-patches@sourceware.org> writes:

> On 2022-01-13 1:34 p.m., Andrew Burgess wrote:
>> From: Andrew Burgess <andrew.burgess@embecosm.com>
>>
>> I finally got back around to working on this patch, and have a new
>> version that I'd like to propose.
>>
>> The biggest change in this version is that all of the thread creation
>> functions now have a new parameter which controls if the thread is
>> started resumed or not.
>>
>> There was also a great discussion last time about whether the
>> executing and resumed flags (within thread_info) should be combined
>> into a single enum.  Simon argued in favour of this change, while I
>> remain unconvinced.
>>
>> For now, I'd like to propose that the enum change be deferred.  The
>> patch as it stands is already pretty large, and changing how we manage
>> the two flags would only make the patch larger.  The change as I have
>> it right now maintains the flags as they are, but makes their use
>> consistent.  If we later want to change the flags to an enum then it
>> feels like this would be better done as a separate step.
>>
>> There are still things that I would like to improve in the area of
>> this code, I'm still not completely happy with how the thread state is
>> managed around the target_ops::create_inferior call, but I though the
>> code as it stands isn't great, at least things are consistent after
>> this patch.
>>
>> I'm as sure as I feel I can be that I've not broken anything for
>> Linux, but it's almost certain that something will be broken for other
>> targets.  I've details the additional testing I've done at the end of
>> my commit message.
>>
>> My commit message also includes a ChangeLog like log, in this I've
>> tried to mention those areas of the change that I know are untested,
>> or lightly tested.
>>
>> I welcome all review feedback, as well as any additional testing that
>> people might like to do.
>>
>> Thanks,
>> Andrew
>>
>> ---
>>
>> This commit was inspired by this comment from Simon:
>>
>>   https://sourceware.org/pipermail/gdb-patches/2021-July/180694.html
>>
>> The comment is about two thread_info flags m_executing and m_resumed.
>> The m_resumed flag indicates that at the infrun level GDB has set the
>> thread running, while the m_executing flag indicates that the thread
>> is actually running at the target level.
>>
>> It is very common that a thread can be m_resumed, but not m_executing,
>> that is, core GDB thinks the thread is, or should be, running, but at
>> the target level the thread isn't currently running.
>>
>> The comment Simon made was in reply to a patch I posted where I found
>> a case where a thread was marked m_executing, but not m_resumed, that
>> is, at the infrun level GDB thought the thread was stopped, but at the
>> target level the thread was actually running.  Simon suggests that
>> this feels like an invalid state, and after thinking about it, I
>> agree.
>>
>> So, the goal of this commit is to add some asserts to GDB.  The core
>> idea here is that the resumed and executing flags should only change
>> in the following pattern, to begin with everything is set false:
>>
>>   Resumed: false
>>   Executing: false
>>
>> Then infrun marks the thread resumed:
>>
>>   Resumed: true
>>   Executing: false
>>
>> Then a target starts the thread executing:
>>
>>   Resumed: true
>>   Executing: true
>>
>> The thread stops, the target spots this and marks the thread no longer
>> executing:
>>
>>   Resumed: true
>>   Executing: false
>>
>> And finally, infrun acknowledges that the thread is now no longer
>> resumed:
>>
>>   Resumed: false
>>   Executing: false
>>
>> Notice that at no point is resumed false, while executing is true.
>>
>> And so we can add these asserts:
>>
>>  1. The resumed flag should only change state when the executing flag
>>  is false, and
>>
>>  2. The executing flag should only change state when the resumed flag
>>  is true.
>>
>> I added these asserts and ....
>>
>> .... it turns out these rules are broken all over the place in GDB, we
>> have problems like:
>>
>>  (a) When new threads appear they are marked executing, but not
>>  resumed, and
>>
>>  (b) In some places we mark a single thread as resumed, but then
>>  actually set multiple threads executing.
>>
>> For (a) it could be argued that this is a legitimate state - this is
>> actually the problem I addressed in the original patch that Simon was
>> replying too, however, we don't need to support this as a separate
>> state, so if we can make this case follow the expected set of state
>> transitions then it allows us to reduce the number of states that GDB
>> can be in, which I think is a good thing.
>>
>> Case (b) seems to just be a bug to me.
>>
>> My initial approach was to retain the idea that threads are always
>> created in the non-executing, non-resumed state, and then find all the
>> places where new threads are created (which should be in the resumed
>> state), and mark the thread resumed in that case.
>>
>> However, after looking at the changes for a while, it felt like it
>> would be simpler to create threads as resumed by default and instead
>> change the threads back to non-resumed in the few cases where this was
>> appropriate.  The appropriate case being (as far as I can tell), just
>> the initial threads created as part of starting up a new inferior.
>>
>> So, that's what this patch does.  The thread creation routines now
>> take a flag to indicate if the new thread should be created resumed or
>> not.  Almost all threads are started in the resumed state, except for
>> a few cases associated with initial target creation.
>>
>> In an ideal world, I would have liked that all threads created as part
>> of the ::create_inferior process would also be created in the
>> non-resumed state, but that doesn't seem easily achievable right now.
>> Though I could easily see changing the Linux target, other targets that
>> I can't test will be harder to get right.  So, for now, after calling
>> ::create_process I assert that the threads are currently resumed, and
>> then mark the threads as non-resumed.
>>
>> I do have a plan that I might be able to make further improvements in
>> the ::create_inferior area, however, I want to see whether this patch
>> is accepted first before investing further time on this.  I think that
>> where this patch gets to is good enough for now.
>>
>> On Testing:
>>
>> I've tested this primarily on x86-64 GNU/Linux with the unix,
>> native-gdbserver, and native-extended-gdbserver boards, and see no
>> regressions.
>>
>> I have also tried to test some other targets, though the testing has
>> been pretty minimal:
>>
>> I installed FreeBSD in an x86-64 VM.  I can build GDB fine, but when I
>> try to run dejagnu the VM falls over with an out of swap space error,
>> no matter how much swap I give the machine.  However, before falling
>> over a few hundred tests do run, and I see no regressions in those
>> tests.  I've also manually checked that the gdb.base/attach.exp test
>> works (to do some basic attach testing).  So I'm reasonably confident
>> that this target should be mostly OK.
>>
>> As I was working on GNU/Hurd for another bug I had an i386 GNU/Hurd VM
>> available, so I built GDB in here too.  Due to other issues with this
>> target the dejagnu testing is pretty useless here, but I checked that
>> I can start multi-threaded targets, step/continue past thread
>> creation, and also that I can attach to a multi-threaded target.
>>
>> I have also built this branch on Windows, using mingw.  I was unable
>> to get dejagnu testing working on this target, but again I did some
>> basic testing that GDB could start up with multi-threaded inferiors,
>> and correctly see new threads as they appear.
>>
>> I also built a target with a simulator, and checked that I could
>> startup and run basic tests their too.
>>
>> I did try making use of the GCC machine farm to test on AIX and
>> Solaris, but I was unable to get GDB building on any of the machines I
>> tried in the farm.
>
> Hi Andrew,
>
> I see nothing in the patch that stands out as obviously wrong.  But like
> you, I have a hard time convincing myself what is the right resumed
> state to pass to add_thread at each place.  And I'm not sure that just
> staring at the code longer will help much.  It's hard to know without
> actually testing.
>
> For example, I am not sure that passing "true" in all update_thread_list
> methods is correct.  update_thread_list is sometimes called when
> everything is stopped, on all-stop targets.  So in that context, I
> suppose that new threads discovered this way should be created
> non-resumed.
>
> However, I think you did a pretty good job of testing what you could,
> given the context.

Simon,

Thanks for the feedback, and sorry for not following up sooner.  This
got pushed down my list of priorities.

Given how close we are to the GDB 12 branch point, my current plan is to
wait until shortly after we branch, and then update, retest, and push
this patch.

That will give us (me) as much time as possible to help resolve any
problems that this introduces.  I'm expecting there will be some issues
on the targets I've not tested as much, but hopefully they should be
easy enough to resolve.

Obviously the above plan can change if people object.

Thanks,
Andrew


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCHv3] gdb: make thread_info executing and resumed state more consistent
  2022-02-24 15:52       ` Andrew Burgess via Gdb-patches
@ 2022-03-03 19:42         ` Simon Marchi via Gdb-patches
  2022-03-07  7:39           ` Aktemur, Tankut Baris via Gdb-patches
  2022-03-30  9:19         ` Andrew Burgess via Gdb-patches
  1 sibling, 1 reply; 30+ messages in thread
From: Simon Marchi via Gdb-patches @ 2022-03-03 19:42 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches; +Cc: Andrew Burgess

> Simon,
>
> Thanks for the feedback, and sorry for not following up sooner.  This
> got pushed down my list of priorities.
>
> Given how close we are to the GDB 12 branch point, my current plan is to
> wait until shortly after we branch, and then update, retest, and push
> this patch.
>
> That will give us (me) as much time as possible to help resolve any
> problems that this introduces.  I'm expecting there will be some issues
> on the targets I've not tested as much, but hopefully they should be
> easy enough to resolve.
>
> Obviously the above plan can change if people object.

This is fine with me.

I was reminded of this patch because of some bug a colleague hit, which
I recorded here:

  https://sourceware.org/bugzilla/show_bug.cgi?id=28942

In short, the linux-nat target adds threads in the non-resumed state,
and that confuses GDB when a thread hits a breakpoint, that breakpoint
has a condition, and that condition contains an inferior function call.
GDB ends up trying to resume a thread that it thinks is non-resumed but
is actually resumed.

Simon

^ permalink raw reply	[flat|nested] 30+ messages in thread

* RE: [PATCHv3] gdb: make thread_info executing and resumed state more consistent
  2022-03-03 19:42         ` Simon Marchi via Gdb-patches
@ 2022-03-07  7:39           ` Aktemur, Tankut Baris via Gdb-patches
  0 siblings, 0 replies; 30+ messages in thread
From: Aktemur, Tankut Baris via Gdb-patches @ 2022-03-07  7:39 UTC (permalink / raw)
  To: Simon Marchi, Andrew Burgess; +Cc: Andrew Burgess, gdb-patches

On Thursday, March 3, 2022 8:43 PM, Simon Marchi wrote:
> > Simon,
> >
> > Thanks for the feedback, and sorry for not following up sooner.  This
> > got pushed down my list of priorities.
> >
> > Given how close we are to the GDB 12 branch point, my current plan is to
> > wait until shortly after we branch, and then update, retest, and push
> > this patch.
> >
> > That will give us (me) as much time as possible to help resolve any
> > problems that this introduces.  I'm expecting there will be some issues
> > on the targets I've not tested as much, but hopefully they should be
> > easy enough to resolve.
> >
> > Obviously the above plan can change if people object.
> 
> This is fine with me.
> 
> I was reminded of this patch because of some bug a colleague hit, which
> I recorded here:
> 
>   https://sourceware.org/bugzilla/show_bug.cgi?id=28942
> 
> In short, the linux-nat target adds threads in the non-resumed state,
> and that confuses GDB when a thread hits a breakpoint, that breakpoint
> has a condition, and that condition contains an inferior function call.
> GDB ends up trying to resume a thread that it thinks is non-resumed but
> is actually resumed.

Hi,

A highly-related patch series was this:

  https://sourceware.org/pipermail/gdb-patches/2021-February/176214.html 

Perhaps there are a few useful things that still apply to the current master.
CC'ing Natalia Saiapova, who had submitted the series.

Thanks
-Baris


Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de <http://www.intel.de>
Managing Directors: Christin Eisenschmid, Sharon Heck, Tiffany Doon Silva  
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCHv3] gdb: make thread_info executing and resumed state more consistent
  2022-02-24 15:52       ` Andrew Burgess via Gdb-patches
  2022-03-03 19:42         ` Simon Marchi via Gdb-patches
@ 2022-03-30  9:19         ` Andrew Burgess via Gdb-patches
  1 sibling, 0 replies; 30+ messages in thread
From: Andrew Burgess via Gdb-patches @ 2022-03-30  9:19 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches; +Cc: Andrew Burgess

Andrew Burgess <aburgess@redhat.com> writes:

> Simon Marchi via Gdb-patches <gdb-patches@sourceware.org> writes:
>
>> On 2022-01-13 1:34 p.m., Andrew Burgess wrote:
>>> From: Andrew Burgess <andrew.burgess@embecosm.com>
>>>
>>> I finally got back around to working on this patch, and have a new
>>> version that I'd like to propose.
>>>
>>> The biggest change in this version is that all of the thread creation
>>> functions now have a new parameter which controls if the thread is
>>> started resumed or not.
>>>
>>> There was also a great discussion last time about whether the
>>> executing and resumed flags (within thread_info) should be combined
>>> into a single enum.  Simon argued in favour of this change, while I
>>> remain unconvinced.
>>>
>>> For now, I'd like to propose that the enum change be deferred.  The
>>> patch as it stands is already pretty large, and changing how we manage
>>> the two flags would only make the patch larger.  The change as I have
>>> it right now maintains the flags as they are, but makes their use
>>> consistent.  If we later want to change the flags to an enum then it
>>> feels like this would be better done as a separate step.
>>>
>>> There are still things that I would like to improve in the area of
>>> this code, I'm still not completely happy with how the thread state is
>>> managed around the target_ops::create_inferior call, but I though the
>>> code as it stands isn't great, at least things are consistent after
>>> this patch.
>>>
>>> I'm as sure as I feel I can be that I've not broken anything for
>>> Linux, but it's almost certain that something will be broken for other
>>> targets.  I've details the additional testing I've done at the end of
>>> my commit message.
>>>
>>> My commit message also includes a ChangeLog like log, in this I've
>>> tried to mention those areas of the change that I know are untested,
>>> or lightly tested.
>>>
>>> I welcome all review feedback, as well as any additional testing that
>>> people might like to do.
>>>
>>> Thanks,
>>> Andrew
>>>
>>> ---
>>>
>>> This commit was inspired by this comment from Simon:
>>>
>>>   https://sourceware.org/pipermail/gdb-patches/2021-July/180694.html
>>>
>>> The comment is about two thread_info flags m_executing and m_resumed.
>>> The m_resumed flag indicates that at the infrun level GDB has set the
>>> thread running, while the m_executing flag indicates that the thread
>>> is actually running at the target level.
>>>
>>> It is very common that a thread can be m_resumed, but not m_executing,
>>> that is, core GDB thinks the thread is, or should be, running, but at
>>> the target level the thread isn't currently running.
>>>
>>> The comment Simon made was in reply to a patch I posted where I found
>>> a case where a thread was marked m_executing, but not m_resumed, that
>>> is, at the infrun level GDB thought the thread was stopped, but at the
>>> target level the thread was actually running.  Simon suggests that
>>> this feels like an invalid state, and after thinking about it, I
>>> agree.
>>>
>>> So, the goal of this commit is to add some asserts to GDB.  The core
>>> idea here is that the resumed and executing flags should only change
>>> in the following pattern, to begin with everything is set false:
>>>
>>>   Resumed: false
>>>   Executing: false
>>>
>>> Then infrun marks the thread resumed:
>>>
>>>   Resumed: true
>>>   Executing: false
>>>
>>> Then a target starts the thread executing:
>>>
>>>   Resumed: true
>>>   Executing: true
>>>
>>> The thread stops, the target spots this and marks the thread no longer
>>> executing:
>>>
>>>   Resumed: true
>>>   Executing: false
>>>
>>> And finally, infrun acknowledges that the thread is now no longer
>>> resumed:
>>>
>>>   Resumed: false
>>>   Executing: false
>>>
>>> Notice that at no point is resumed false, while executing is true.
>>>
>>> And so we can add these asserts:
>>>
>>>  1. The resumed flag should only change state when the executing flag
>>>  is false, and
>>>
>>>  2. The executing flag should only change state when the resumed flag
>>>  is true.
>>>
>>> I added these asserts and ....
>>>
>>> .... it turns out these rules are broken all over the place in GDB, we
>>> have problems like:
>>>
>>>  (a) When new threads appear they are marked executing, but not
>>>  resumed, and
>>>
>>>  (b) In some places we mark a single thread as resumed, but then
>>>  actually set multiple threads executing.
>>>
>>> For (a) it could be argued that this is a legitimate state - this is
>>> actually the problem I addressed in the original patch that Simon was
>>> replying too, however, we don't need to support this as a separate
>>> state, so if we can make this case follow the expected set of state
>>> transitions then it allows us to reduce the number of states that GDB
>>> can be in, which I think is a good thing.
>>>
>>> Case (b) seems to just be a bug to me.
>>>
>>> My initial approach was to retain the idea that threads are always
>>> created in the non-executing, non-resumed state, and then find all the
>>> places where new threads are created (which should be in the resumed
>>> state), and mark the thread resumed in that case.
>>>
>>> However, after looking at the changes for a while, it felt like it
>>> would be simpler to create threads as resumed by default and instead
>>> change the threads back to non-resumed in the few cases where this was
>>> appropriate.  The appropriate case being (as far as I can tell), just
>>> the initial threads created as part of starting up a new inferior.
>>>
>>> So, that's what this patch does.  The thread creation routines now
>>> take a flag to indicate if the new thread should be created resumed or
>>> not.  Almost all threads are started in the resumed state, except for
>>> a few cases associated with initial target creation.
>>>
>>> In an ideal world, I would have liked that all threads created as part
>>> of the ::create_inferior process would also be created in the
>>> non-resumed state, but that doesn't seem easily achievable right now.
>>> Though I could easily see changing the Linux target, other targets that
>>> I can't test will be harder to get right.  So, for now, after calling
>>> ::create_process I assert that the threads are currently resumed, and
>>> then mark the threads as non-resumed.
>>>
>>> I do have a plan that I might be able to make further improvements in
>>> the ::create_inferior area, however, I want to see whether this patch
>>> is accepted first before investing further time on this.  I think that
>>> where this patch gets to is good enough for now.
>>>
>>> On Testing:
>>>
>>> I've tested this primarily on x86-64 GNU/Linux with the unix,
>>> native-gdbserver, and native-extended-gdbserver boards, and see no
>>> regressions.
>>>
>>> I have also tried to test some other targets, though the testing has
>>> been pretty minimal:
>>>
>>> I installed FreeBSD in an x86-64 VM.  I can build GDB fine, but when I
>>> try to run dejagnu the VM falls over with an out of swap space error,
>>> no matter how much swap I give the machine.  However, before falling
>>> over a few hundred tests do run, and I see no regressions in those
>>> tests.  I've also manually checked that the gdb.base/attach.exp test
>>> works (to do some basic attach testing).  So I'm reasonably confident
>>> that this target should be mostly OK.
>>>
>>> As I was working on GNU/Hurd for another bug I had an i386 GNU/Hurd VM
>>> available, so I built GDB in here too.  Due to other issues with this
>>> target the dejagnu testing is pretty useless here, but I checked that
>>> I can start multi-threaded targets, step/continue past thread
>>> creation, and also that I can attach to a multi-threaded target.
>>>
>>> I have also built this branch on Windows, using mingw.  I was unable
>>> to get dejagnu testing working on this target, but again I did some
>>> basic testing that GDB could start up with multi-threaded inferiors,
>>> and correctly see new threads as they appear.
>>>
>>> I also built a target with a simulator, and checked that I could
>>> startup and run basic tests their too.
>>>
>>> I did try making use of the GCC machine farm to test on AIX and
>>> Solaris, but I was unable to get GDB building on any of the machines I
>>> tried in the farm.
>>
>> Hi Andrew,
>>
>> I see nothing in the patch that stands out as obviously wrong.  But like
>> you, I have a hard time convincing myself what is the right resumed
>> state to pass to add_thread at each place.  And I'm not sure that just
>> staring at the code longer will help much.  It's hard to know without
>> actually testing.
>>
>> For example, I am not sure that passing "true" in all update_thread_list
>> methods is correct.  update_thread_list is sometimes called when
>> everything is stopped, on all-stop targets.  So in that context, I
>> suppose that new threads discovered this way should be created
>> non-resumed.
>>
>> However, I think you did a pretty good job of testing what you could,
>> given the context.
>
> Simon,
>
> Thanks for the feedback, and sorry for not following up sooner.  This
> got pushed down my list of priorities.
>
> Given how close we are to the GDB 12 branch point, my current plan is to
> wait until shortly after we branch, and then update, retest, and push
> this patch.
>
> That will give us (me) as much time as possible to help resolve any
> problems that this introduces.  I'm expecting there will be some issues
> on the targets I've not tested as much, but hopefully they should be
> easy enough to resolve.

Now GDB 12 has branched, I'm planning to rebase and retest this patch,
and then merge it!

This is just a warning.  I expect it to take a few days for the rebase
and retest, so if there are any objections, now is the time to shout
about it.

I'm fully expecting that this patch will cause some regressions - it
impacts all targets, some of which I can't test at all, others I can
only do limited testing on.  I'm fully committed to help debug issues
relating to this patch over the coming months.

I'll post again just prior to pushing.

Thanks,
Andrew


^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCHv4 0/2] Make thread_info executing and resumed state more consistent
  2022-01-13 18:34   ` [PATCHv3] " Andrew Burgess via Gdb-patches
  2022-01-14 17:10     ` Simon Marchi via Gdb-patches
@ 2022-04-21 16:45     ` Andrew Burgess via Gdb-patches
  2022-04-21 16:45       ` [PATCHv4 1/2] gdb: add some additional thread status debug output Andrew Burgess via Gdb-patches
                         ` (3 more replies)
  1 sibling, 4 replies; 30+ messages in thread
From: Andrew Burgess via Gdb-patches @ 2022-04-21 16:45 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess

And I'm back on this patch again!

I've rebased this onto current master and done some testing.  I
haven't found any regressions, but as I've said before, this change
touches every target, and my testing on anything other than GNU/Linux
(x86-64) is pretty thin, so I'm fully expecting this to introduce some
issues - these issues _should_ be limited to assertion failures when
threads are not in the expected states, I would hope there's no
crashes being introduced.

There's been no significant changes since v3.  I have split out a
little bit of the debug printing code (the new #1 patch), but the
second patch is pretty much the same as v3.

V3 was given a cautious OK, but I wanted to advertise this patch again
in case anyone wants to object before I merge this.

All feedback is welcome.

Thanks,
Andrew

---

Andrew Burgess (2):
  gdb: add some additional thread status debug output
  gdb: make thread_info executing and resumed state more consistent

 gdb/aix-thread.c             |  4 +-
 gdb/bsd-kvm.c                |  2 +-
 gdb/bsd-uthread.c            |  4 +-
 gdb/corelow.c                |  9 +++-
 gdb/darwin-nat.c             |  2 +-
 gdb/fbsd-nat.c               |  4 +-
 gdb/fork-child.c             |  3 ++
 gdb/gdbthread.h              | 24 ++++++---
 gdb/gnu-nat.c                | 13 +++--
 gdb/go32-nat.c               |  2 +-
 gdb/inf-ptrace.c             |  4 +-
 gdb/infcmd.c                 | 84 +++++++++++++++++++++----------
 gdb/infrun.c                 | 96 +++++++++++++++++++++++++++++++-----
 gdb/infrun.h                 | 26 ++++++++++
 gdb/linux-nat.c              |  8 +--
 gdb/linux-thread-db.c        |  2 +-
 gdb/netbsd-nat.c             |  4 +-
 gdb/nto-procfs.c             |  2 +-
 gdb/obsd-nat.c               |  4 +-
 gdb/process-stratum-target.c |  4 +-
 gdb/procfs.c                 | 12 ++---
 gdb/ravenscar-thread.c       |  4 +-
 gdb/remote-sim.c             |  2 +-
 gdb/remote.c                 | 21 +++++---
 gdb/sol-thread.c             |  4 +-
 gdb/thread.c                 | 40 +++++++++++----
 gdb/tracectf.c               |  3 +-
 gdb/tracefile-tfile.c        |  2 +-
 gdb/windows-nat.c            | 12 ++++-
 29 files changed, 295 insertions(+), 106 deletions(-)

-- 
2.25.4


^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCHv4 1/2] gdb: add some additional thread status debug output
  2022-04-21 16:45     ` [PATCHv4 0/2] Make " Andrew Burgess via Gdb-patches
@ 2022-04-21 16:45       ` Andrew Burgess via Gdb-patches
  2022-04-21 20:35         ` Lancelot SIX via Gdb-patches
  2022-04-21 16:45       ` [PATCHv4 2/2] gdb: make thread_info executing and resumed state more consistent Andrew Burgess via Gdb-patches
                         ` (2 subsequent siblings)
  3 siblings, 1 reply; 30+ messages in thread
From: Andrew Burgess via Gdb-patches @ 2022-04-21 16:45 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess

While working on this patch:

  https://sourceware.org/pipermail/gdb-patches/2022-January/185109.html

I found it really useful to print the executing/resumed status of all
threads (or all threads in a particular inferior) at various
places (e.g. when a new inferior is started, when GDB attaches, etc).

This debug was original part of the above patch, but I wanted to
rewrite this as a separate patch and move the code into a new function
in infrun.h, which is what this patch does.

Unless 'set debug infrun on' is in effect, then there should be no
user visible changes after this commit.
---
 gdb/infcmd.c | 19 ++++++++-----------
 gdb/infrun.c |  3 +++
 gdb/infrun.h | 26 ++++++++++++++++++++++++++
 3 files changed, 37 insertions(+), 11 deletions(-)

diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 84eb6e5d79b..1beade2acec 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -238,6 +238,9 @@ post_create_inferior (int from_tty)
   /* Be sure we own the terminal in case write operations are performed.  */ 
   target_terminal::ours_for_output ();
 
+  infrun_debug_show_threads ("threads in the newly created inferior",
+			     current_inferior ()->non_exited_threads ());
+
   /* If the target hasn't taken care of this already, do it now.
      Targets which need to access registers during to_open,
      to_create_inferior, or to_attach should do it earlier; but many
@@ -454,6 +457,9 @@ run_command_1 (const char *args, int from_tty, enum run_how run_how)
      shouldn't refer to run_target again.  */
   run_target = NULL;
 
+  infrun_debug_show_threads ("immediately after create_process",
+			     current_inferior ()->non_exited_threads ());
+
   /* We're starting off a new process.  When we get out of here, in
      non-stop mode, finish the state of all threads of that process,
      but leave other threads alone, as they may be stopped in internal
@@ -2589,17 +2595,8 @@ attach_command (const char *args, int from_tty)
      shouldn't refer to attach_target again.  */
   attach_target = NULL;
 
-  if (debug_infrun)
-    {
-      infrun_debug_printf ("immediately after attach:");
-      for (thread_info *thread : inferior->non_exited_threads ())
-	infrun_debug_printf ("  thread %s, executing = %d, resumed = %d, "
-			     "state = %s",
-			     thread->ptid.to_string ().c_str (),
-			     thread->executing (),
-			     thread->resumed (),
-			     thread_state_string (thread->state));
-    }
+  infrun_debug_show_threads ("immediately after attach",
+			     current_inferior ()->non_exited_threads ());
 
   /* Enable async mode if it is supported by the target.  */
   if (target_can_async_p ())
diff --git a/gdb/infrun.c b/gdb/infrun.c
index c311240b78c..a814f5cbc2b 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -5043,6 +5043,9 @@ stop_all_threads (const char *reason, inferior *inf)
   INFRUN_SCOPED_DEBUG_START_END ("reason=%s, inf=%d", reason,
 				 inf != nullptr ? inf->num : -1);
 
+  infrun_debug_show_threads ("non-exited threads",
+			     all_non_exited_threads ());
+
   scoped_restore_current_thread restore_thread;
 
   /* Enable thread events on relevant targets.  */
diff --git a/gdb/infrun.h b/gdb/infrun.h
index 9685f3a9775..1421fa4050a 100644
--- a/gdb/infrun.h
+++ b/gdb/infrun.h
@@ -48,6 +48,32 @@ extern bool debug_infrun;
 #define INFRUN_SCOPED_DEBUG_ENTER_EXIT \
   scoped_debug_enter_exit (debug_infrun, "infrun")
 
+/* A infrun debug helper routine to print out all the threads in the set
+   THREADS (which should be a range type that returns thread_info*
+   objects).
+
+   The TITLE is a string that is printed before the list of threads.
+
+   Output is only produced when 'set debug infrun on'.  */
+
+template<typename ThreadRange>
+static inline void
+infrun_debug_show_threads (const char *title, ThreadRange threads)
+{
+  if (debug_infrun)
+    {
+      infrun_debug_printf ("%s:", (title));
+      for (thread_info *thread : threads)
+	infrun_debug_printf ("  thread %s, executing = %d, resumed = %d, "
+			     "state = %s",
+			     thread->ptid.to_string ().c_str (),
+			     thread->executing (),
+			     thread->resumed (),
+			     thread_state_string (thread->state));
+    }
+}
+
+
 /* Nonzero if we want to give control to the user when we're notified
    of shared library events by the dynamic linker.  */
 extern int stop_on_solib_events;
-- 
2.25.4


^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCHv4 2/2] gdb: make thread_info executing and resumed state more consistent
  2022-04-21 16:45     ` [PATCHv4 0/2] Make " Andrew Burgess via Gdb-patches
  2022-04-21 16:45       ` [PATCHv4 1/2] gdb: add some additional thread status debug output Andrew Burgess via Gdb-patches
@ 2022-04-21 16:45       ` Andrew Burgess via Gdb-patches
  2022-04-26 13:28       ` Nidal Faour via Gdb-patches
  2022-08-08 11:04       ` [PATCHv4 0/2] Make " Craig Blackmore
  3 siblings, 0 replies; 30+ messages in thread
From: Andrew Burgess via Gdb-patches @ 2022-04-21 16:45 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess

From: Andrew Burgess <andrew.burgess@embecosm.com>

This commit was inspired by this comment from Simon:

  https://sourceware.org/pipermail/gdb-patches/2021-July/180694.html

The comment is about two thread_info flags m_executing and m_resumed.
The m_resumed flag indicates that at the infrun level GDB has set the
thread running, while the m_executing flag indicates that the thread
is actually running at the target level.

It is very common that a thread can be m_resumed, but not m_executing,
that is, core GDB thinks the thread is, or should be, running, but at
the target level the thread isn't currently running.

The comment Simon made was in reply to a patch I posted where I found
a case where a thread was marked m_executing, but not m_resumed, that
is, at the infrun level GDB thought the thread was stopped, but at the
target level the thread was actually running.  Simon suggests that
this feels like an invalid state, and after thinking about it, I
agree.

So, the goal of this commit is to add some asserts to GDB.  The core
idea here is that the resumed and executing flags should only change
in the following pattern, to begin with everything is set false:

  Resumed: false
  Executing: false

Then infrun marks the thread resumed:

  Resumed: true
  Executing: false

Then a target starts the thread executing:

  Resumed: true
  Executing: true

The thread stops, the target spots this and marks the thread no longer
executing:

  Resumed: true
  Executing: false

And finally, infrun acknowledges that the thread is now no longer
resumed:

  Resumed: false
  Executing: false

Notice that at no point is resumed false, while executing is true.

And so we can add these asserts:

 1. The resumed flag should only change state when the executing flag
 is false, and

 2. The executing flag should only change state when the resumed flag
 is true.

I added these asserts and ....

.... it turns out these rules are broken all over the place in GDB, we
have problems like:

 (a) When new threads appear they are marked executing, but not
 resumed, and

 (b) In some places we mark a single thread as resumed, but then
 actually set multiple threads executing.

For (a) it could be argued that this is a legitimate state - this is
actually the problem I addressed in the original patch that Simon was
replying too, however, we don't need to support this as a separate
state, so if we can make this case follow the expected set of state
transitions then it allows us to reduce the number of states that GDB
can be in, which I think is a good thing.

Case (b) seems to just be a bug to me.

My initial approach was to retain the idea that threads are always
created in the non-executing, non-resumed state, and then find all the
places where new threads are created (which should be in the resumed
state), and mark the thread resumed in that case.

However, after looking at the changes for a while, it felt like it
would be simpler to create threads as resumed by default and instead
change the threads back to non-resumed in the few cases where this was
appropriate.  The appropriate case being (as far as I can tell), just
the initial threads created as part of starting up a new inferior.

So, that's what this patch does.  The thread creation routines now
take a flag to indicate if the new thread should be created resumed or
not.  Almost all threads are started in the resumed state, except for
a few cases associated with initial target creation.

In an ideal world, I would have liked that all threads created as part
of the ::create_inferior process would also be created in the
non-resumed state, but that doesn't seem easily achievable right now.
Though I could easily see changing the Linux target, other targets that
I can't test will be harder to get right.  So, for now, after calling
::create_process I assert that the threads are currently resumed, and
then mark the threads as non-resumed.

I do have a plan that I might be able to make further improvements in
the ::create_inferior area, however, I want to see whether this patch
is accepted first before investing further time on this.  I think that
where this patch gets to is good enough for now.

On Testing:

I've tested this primarily on x86-64 GNU/Linux with the unix,
native-gdbserver, and native-extended-gdbserver boards, and see no
regressions.

I have also tried to test some other targets, though the testing has
been pretty minimal:

I installed FreeBSD in an x86-64 VM.  I can build GDB fine, but when I
try to run dejagnu the VM falls over with an out of swap space error,
no matter how much swap I give the machine.  However, before falling
over a few hundred tests do run, and I see no regressions in those
tests.  I've also manually checked that the gdb.base/attach.exp test
works (to do some basic attach testing).  So I'm reasonably confident
that this target should be mostly OK.

As I was working on GNU/Hurd for another bug I had an i386 GNU/Hurd VM
available, so I built GDB in here too.  Due to other issues with this
target the dejagnu testing is pretty useless here, but I checked that
I can start multi-threaded targets, step/continue past thread
creation, and also that I can attach to a multi-threaded target.

I have also built this branch on Windows, using mingw.  I was unable
to get dejagnu testing working on this target, but again I did some
basic testing that GDB could start up with multi-threaded inferiors,
and correctly see new threads as they appear.

I also built a target with a simulator, and checked that I could
startup and run basic tests their too.

I did try making use of the GCC machine farm to test on AIX and
Solaris, but I was unable to get GDB building on any of the machines I
tried in the farm.

Here is a description of all the individual changes:

  * aix-thread.c (sync_threadlists): New thread starts resumed, this
  change was untested.
  * bsd-kvm.c (bsd_kvm_target_open): New thread starts not-resumed,
  this change was untested.
  * bsd-uthread.c (bsd_uthread_target::wait): New thread starts
  resumed, this change was untested.
  (bsd_uthread_target::update_thread_list): Likewise.
  * corelow.c (add_to_thread_list): New threads start non-resumed.
  (core_target_open): Likewise.
  * darwin-nat.c (darwin_nat_target::check_new_threads): New thread
  starts resumed, this change was untested.
  * fbsd-nat.c (fbsd_add_threads): New threads start resumed.
  (fbsd_nat_target::wait): Likewise.
  * fork-child.c (gdb_startup_inferior): All threads should be
  marked resumed at this point.
  * gdbthread.h (thread_info::set_stop_pc): When setting the stop_pc
  a thread should be neither resumed, or executing.
  (clear_stop_pc): Due to where this method is called, the thread
  should be resumed, but definitely executing.  Though it's tempting
  to say we don't care about the resumed status, if we do ever call
  this function before the thread is resumed then that's a
  significant change, and having the assert fail will draw attention
  to that, and give us reason to think about what we're doing.
  (add_thread): Add additional parameter.
  (add_thread_silent): Likewise.
  (add_thread_with_info): Likewise.
  * gnu-nat.c (gnu_nat_target::inf_validate_procs): New threads are
  started resumed.  Only minimal testing of GNU/Hurd was done.
  (gnu_nat_target::create_inferior): Likewise.
  (gnu_nat_target::attach): Force threads back to non-resumed after
  an attach.  This is a hack, but avoids me having to make
  significant changes to GNU/Hurd thread management, which I'm
  reluctant to do given the difficulty testing the target.
  * go32-nat.c (go32_nat_target::create_inferior): New threads are
  started resumed, this change was untested.
  * inf-ptrace.c (inf_ptrace_target::create_inferior): New threads
  are staarted resumed.
  (inf_ptrace_target::attach): Likewise.
  * infcmd.c (post_create_inferior): Current thread should not be
  resumed at this point. Additionally, only set the stop_pc once per
  stop, there's an updated comment, extra debug output, and some of
  the code is re-indented.
  (run_command_1): Mark threads non-resumed after starting up the
  inferior as part of the run command.
  * infrun.c (follow_fork_inferior): After a fork all threads in the
  child should already have been marked as non-resumed.
  (follow_exec): Upon entry the thread performing the exec should
  already be marked as non-resumed.  After the exec the selected
  thread should also be non-resumed.
  (struct scoped_mark_thread_resumed): This new class is used to
  ensure that all the required threads are marked resumed when
  required, this addresses issue (b) above.  I make use of this new
  class in...
  (do_target_resume): Use scoped_mark_thread_resumed to mark all
  threads resumed prior to actually calling into the target to resume
  the threads.  Placing this call here allows me to remove some calls
  to thread_info::set_resumed() in other places...
  (resume_1): Remove calls to thread_info::set_resumed() from here.
  (handle_one): New threads are started resumed.
  (handle_inferior_event): Likewise.  Also assert that the thread is
  not resumed when handling an exec event.
  (finish_step_over): When we need to place a thread back into the
  resumed state so that we can later find its pending event, we must
  mark the thread resumed after setting the stop_pc, see the asserts
  added to set_stop_pc for why.
  (keep_going_stepped_thread): Remove a call to set_resumed thanks
  to our changes in do_target_resume.
  (stop_all_threads): Add some additional debug output.
  * linux-nat.c (attach_proc_task_lwp_callback): New threads are
  added resumed.
  (linux_handle_extended_wait): Likewise.
  (linux_nat_filter_event): Likewise.
  * linux-thread-db.c (record_thread): Likewise.
  * netbsd-nat.c (nbsd_add_threads): Likewise, this change was
  untested.
  (nbsd_nat_target::wait): Likewise.
  * nto-procfs.c (nto_procfs_target::update_thread_list): Likewise.
  * obsd-nat.c (obsd_nat_target::update_thread_list): Likewise.
  (obsd_nat_target::wait): Likewise.
  * process-stratum-target.c
  (process_stratum_target::follow_exec): After an exec, the new
  thread is add non-resumed.
  (process_stratum_target::follow_fork): Likewise after a fork.
  * procfs.c (do_attach): New threads are created resumed, this is
  untested.
  (procfs_target::wait): Likewise.
  (procfs_target::create_inferior): Likewise.
  (procfs_notice_thread): Likewise.
  * ravenscar-thread.c
  (ravenscar_thread_target::add_active_thread): New threads are
  created resumed, this is untested.
  (ravenscar_thread_target::add_thread): Likewise.
  * remote-sim.c (gdbsim_target::create_inferior): New thread is
  created resumed.
  * remote.c (remote_target::remote_add_thread): Likewise.
  (remote_target::add_current_inferior_and_thread): Add extra
  parameter, use this to control if the thread is started resumed or
  not.
  (remote_target::process_initial_stop_replies): Mark threads
  non-resumed.
  (remote_target::start_remote_1): Create thread resumed.
  * sol-thread.c (sol_thread_target::wait): Create thread resumed,
  this is untested.
  (sol_update_thread_list_callback): Likewise.
  * thread.c (add_thread_silent): Add extra parameter, print
  additional thread debug, mark the new thread resumed or not based
  on the parameter.
  (add_thread_with_info): Add an extra parameter, pass it through to
  add_thread_silent.
  (add_thread): Likewise.
  (thread_info::set_executing): Short cut the case where the
  executing flag is not changing state.  A thread must be resumed
  before it can be executing.  Print some additional debug
  information.
  (thread_info::set_resumed): A thread should not be executing when
  we adjust its resumed status.  Also, print some additional debug
  information.
  * tracectf.c (ctf_target_open): New thread is created non-resumed.
  * tracefile-tfile.c (tfile_target_open): Likewise.
  * windows-nat.c (windows_add_thread): New threads are created
  resumed, this has had only minimal testing.
---
 gdb/aix-thread.c             |  4 +-
 gdb/bsd-kvm.c                |  2 +-
 gdb/bsd-uthread.c            |  4 +-
 gdb/corelow.c                |  9 +++-
 gdb/darwin-nat.c             |  2 +-
 gdb/fbsd-nat.c               |  4 +-
 gdb/fork-child.c             |  3 ++
 gdb/gdbthread.h              | 24 +++++++---
 gdb/gnu-nat.c                | 13 +++--
 gdb/go32-nat.c               |  2 +-
 gdb/inf-ptrace.c             |  4 +-
 gdb/infcmd.c                 | 65 +++++++++++++++++++------
 gdb/infrun.c                 | 93 +++++++++++++++++++++++++++++++-----
 gdb/linux-nat.c              |  8 ++--
 gdb/linux-thread-db.c        |  2 +-
 gdb/netbsd-nat.c             |  4 +-
 gdb/nto-procfs.c             |  2 +-
 gdb/obsd-nat.c               |  4 +-
 gdb/process-stratum-target.c |  4 +-
 gdb/procfs.c                 | 12 ++---
 gdb/ravenscar-thread.c       |  4 +-
 gdb/remote-sim.c             |  2 +-
 gdb/remote.c                 | 21 ++++----
 gdb/sol-thread.c             |  4 +-
 gdb/thread.c                 | 40 ++++++++++++----
 gdb/tracectf.c               |  3 +-
 gdb/tracefile-tfile.c        |  2 +-
 gdb/windows-nat.c            | 12 ++++-
 28 files changed, 258 insertions(+), 95 deletions(-)

diff --git a/gdb/aix-thread.c b/gdb/aix-thread.c
index 4e41cde6694..bd785e86375 100644
--- a/gdb/aix-thread.c
+++ b/gdb/aix-thread.c
@@ -809,7 +809,7 @@ sync_threadlists (void)
 	    = current_inferior ()->process_target ();
 	  thread = add_thread_with_info (proc_target,
 					 ptid_t (infpid, 0, pbuf[pi].pthid),
-					 priv);
+					 priv, true);
 
 	  pi++;
 	}
@@ -843,7 +843,7 @@ sync_threadlists (void)
 	    {
 	      process_stratum_target *proc_target
 		= current_inferior ()->process_target ();
-	      thread = add_thread (proc_target, pptid);
+	      thread = add_thread (proc_target, pptid, true);
 
 	      aix_thread_info *priv = new aix_thread_info;
 	      thread->priv.reset (priv);
diff --git a/gdb/bsd-kvm.c b/gdb/bsd-kvm.c
index 45c7f116472..d791317420c 100644
--- a/gdb/bsd-kvm.c
+++ b/gdb/bsd-kvm.c
@@ -136,7 +136,7 @@ bsd_kvm_target_open (const char *arg, int from_tty)
   core_kd = temp_kd;
   current_inferior ()->push_target (&bsd_kvm_ops);
 
-  thread_info *thr = add_thread_silent (&bsd_kvm_ops, bsd_kvm_ptid);
+  thread_info *thr = add_thread_silent (&bsd_kvm_ops, bsd_kvm_ptid, false);
   switch_to_thread (thr);
 
   target_fetch_registers (get_current_regcache (), -1);
diff --git a/gdb/bsd-uthread.c b/gdb/bsd-uthread.c
index 759b562cdd0..ea60f0afd49 100644
--- a/gdb/bsd-uthread.c
+++ b/gdb/bsd-uthread.c
@@ -422,7 +422,7 @@ bsd_uthread_target::wait (ptid_t ptid, struct target_waitstatus *status,
   /* Don't let the core see a ptid without a corresponding thread.  */
   thread_info *thread = find_thread_ptid (beneath, ptid);
   if (thread == NULL || thread->state == THREAD_EXITED)
-    add_thread (beneath, ptid);
+    add_thread (beneath, ptid, true);
 
   return ptid;
 }
@@ -480,7 +480,7 @@ bsd_uthread_target::update_thread_list ()
 	  if (inferior_ptid.tid () == 0)
 	    thread_change_ptid (proc_target, inferior_ptid, ptid);
 	  else
-	    add_thread (proc_target, ptid);
+	    add_thread (proc_target, ptid, true);
 	}
 
       addr = bsd_uthread_read_memory_address (addr + offset);
diff --git a/gdb/corelow.c b/gdb/corelow.c
index 8c33fb7ebb2..0d041d4030d 100644
--- a/gdb/corelow.c
+++ b/gdb/corelow.c
@@ -365,7 +365,8 @@ add_to_thread_list (asection *asect, asection *reg_sect)
 
   ptid_t ptid (pid, lwpid);
 
-  thread_info *thr = add_thread (inf->process_target (), ptid);
+  /* Pass false to indicate the thread should be added non-resumed.  */
+  thread_info *thr = add_thread (inf->process_target (), ptid, false);
 
 /* Warning, Will Robinson, looking at BFD private data! */
 
@@ -544,7 +545,7 @@ core_target_open (const char *arg, int from_tty)
       if (thread == NULL)
 	{
 	  inferior_appeared (current_inferior (), CORELOW_PID);
-	  thread = add_thread_silent (target, ptid_t (CORELOW_PID));
+	  thread = add_thread_silent (target, ptid_t (CORELOW_PID), false);
 	}
 
       switch_to_thread (thread);
@@ -553,6 +554,10 @@ core_target_open (const char *arg, int from_tty)
   if (current_program_space->exec_bfd () == nullptr)
     locate_exec_from_corefile_build_id (core_bfd, from_tty);
 
+  /* Threads in a core file are not started resumed.  */
+  for (thread_info *thread : current_inferior ()->threads ())
+    gdb_assert (!thread->resumed ());
+
   post_create_inferior (from_tty);
 
   /* Now go through the target stack looking for threads since there
diff --git a/gdb/darwin-nat.c b/gdb/darwin-nat.c
index 17723656930..b3d24a5d990 100644
--- a/gdb/darwin-nat.c
+++ b/gdb/darwin-nat.c
@@ -351,7 +351,7 @@ darwin_nat_target::check_new_threads (inferior *inf)
 	  pti->msg_state = DARWIN_RUNNING;
 
 	  /* Add the new thread.  */
-	  add_thread_with_info (this, ptid_t (inf->pid, 0, new_id), pti);
+	  add_thread_with_info (this, ptid_t (inf->pid, 0, new_id), pti, true);
 	  new_thread_vec.push_back (pti);
 	  new_ix++;
 	  continue;
diff --git a/gdb/fbsd-nat.c b/gdb/fbsd-nat.c
index 8e5107c26f8..8fd54ba5b8c 100644
--- a/gdb/fbsd-nat.c
+++ b/gdb/fbsd-nat.c
@@ -908,7 +908,7 @@ fbsd_add_threads (fbsd_nat_target *target, pid_t pid)
 	    continue;
 #endif
 	  fbsd_lwp_debug_printf ("adding thread for LWP %u", lwps[i]);
-	  add_thread (target, ptid);
+	  add_thread (target, ptid, true);
 	}
     }
 }
@@ -1331,7 +1331,7 @@ fbsd_nat_target::wait_1 (ptid_t ptid, struct target_waitstatus *ourstatus,
 		{
 		  fbsd_lwp_debug_printf ("adding thread for LWP %u",
 					 pl.pl_lwpid);
-		  add_thread (this, wptid);
+		  add_thread (this, wptid, true);
 		}
 	      ourstatus->set_spurious ();
 	      return wptid;
diff --git a/gdb/fork-child.c b/gdb/fork-child.c
index 89003fa617d..c1c41d8eb69 100644
--- a/gdb/fork-child.c
+++ b/gdb/fork-child.c
@@ -126,6 +126,9 @@ gdb_startup_inferior (pid_t pid, int num_traps)
   inferior *inf = current_inferior ();
   process_stratum_target *proc_target = inf->process_target ();
 
+  for (thread_info *thread : inf->threads ())
+    gdb_assert (thread->resumed ());
+
   ptid_t ptid = startup_inferior (proc_target, pid, num_traps, NULL, NULL);
 
   /* Mark all threads non-executing.  */
diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index 1a33eb61221..2d3e8794939 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -368,6 +368,8 @@ class thread_info : public refcounted_object,
 
   void set_stop_pc (CORE_ADDR stop_pc)
   {
+    gdb_assert (!m_resumed);
+    gdb_assert (!m_executing);
     m_suspend.stop_pc = stop_pc;
   }
 
@@ -375,6 +377,11 @@ class thread_info : public refcounted_object,
 
   void clear_stop_pc ()
   {
+    /* This method is called from within thread_info::set_executing, and
+       so, at that point the thread should always be resumed, but not yet
+       executing.  */
+    gdb_assert (m_resumed);
+    gdb_assert (!m_executing);
     m_suspend.stop_pc.reset ();
   }
 
@@ -601,22 +608,25 @@ using inferior_ref
 /* Create an empty thread list, or empty the existing one.  */
 extern void init_thread_list (void);
 
-/* Add a thread to the thread list, print a message
-   that a new thread is found, and return the pointer to
-   the new thread.  Caller my use this pointer to 
-   initialize the private thread data.  */
+/* Add a thread to the thread list, print a message that a new thread is
+   found, and return the pointer to the new thread.  Caller my use this
+   pointer to initialize the private thread data.  When RESUMED_P is true
+   the thread is created in a resumed state, otherwise, the thread is
+   created in a non-resumed state.  */
 extern struct thread_info *add_thread (process_stratum_target *targ,
-				       ptid_t ptid);
+				       ptid_t ptid, bool resumed_p);
 
 /* Same as add_thread, but does not print a message about new
    thread.  */
 extern struct thread_info *add_thread_silent (process_stratum_target *targ,
-					      ptid_t ptid);
+					      ptid_t ptid,
+					      bool resumed_p);
 
 /* Same as add_thread, and sets the private info.  */
 extern struct thread_info *add_thread_with_info (process_stratum_target *targ,
 						 ptid_t ptid,
-						 private_thread_info *);
+						 private_thread_info *,
+						 bool resumed_p);
 
 /* Delete thread THREAD and notify of thread exit.  If the thread is
    currently not deletable, don't actually delete it but still tag it
diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c
index 72314824278..19d2c46021e 100644
--- a/gdb/gnu-nat.c
+++ b/gdb/gnu-nat.c
@@ -1085,9 +1085,9 @@ gnu_nat_target::inf_validate_procs (struct inf *inf)
 	      thread_change_ptid (this, inferior_ptid, ptid);
 	    else if (inf->pending_execs != 0)
 	      /* This is a shell thread.  */
-	      add_thread_silent (this, ptid);
+	      add_thread_silent (this, ptid, true);
 	    else
-	      add_thread (this, ptid);
+	      add_thread (this, ptid, true);
 	  }
       }
 
@@ -2120,7 +2120,7 @@ gnu_nat_target::create_inferior (const char *exec_file,
   /* We have something that executes now.  We'll be running through
      the shell at this point (if startup-with-shell is true), but the
      pid shouldn't change.  */
-  thread_info *thr = add_thread_silent (this, ptid_t (pid));
+  thread_info *thr = add_thread_silent (this, ptid_t (pid), true);
   switch_to_thread (thr);
 
   /* Attach to the now stopped child, which is actually a shell...  */
@@ -2187,6 +2187,13 @@ gnu_nat_target::attach (const char *args, int from_tty)
 
   inf_update_procs (inf);
 
+  /* After attaching all threads are stopped.  It would be better if the
+     threads were added in the non-resumed state, but this is not currently
+     the case (the reason for this is just lack of understanding of how
+     threads are managed on HURD).  So we fix up the state here.  */
+  for (thread_info *thr : current_inferior ()->non_exited_threads ())
+    thr->set_resumed (false);
+
   thread_info *thr
     = find_thread_ptid (this, ptid_t (pid, inf_pick_first_thread ()));
   switch_to_thread (thr);
diff --git a/gdb/go32-nat.c b/gdb/go32-nat.c
index 475425d9f3b..7bae000c2dd 100644
--- a/gdb/go32-nat.c
+++ b/gdb/go32-nat.c
@@ -755,7 +755,7 @@ go32_nat_target::create_inferior (const char *exec_file,
   if (!inf->target_is_pushed (this))
     inf->push_target (this);
 
-  thread_info *thr = add_thread_silent (ptid_t (SOME_PID));
+  thread_info *thr = add_thread_silent (ptid_t (SOME_PID), true);
   switch_to_thread (thr);
 
   clear_proceed_status (0);
diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c
index b9767978744..858c99f2ec8 100644
--- a/gdb/inf-ptrace.c
+++ b/gdb/inf-ptrace.c
@@ -97,7 +97,7 @@ inf_ptrace_target::create_inferior (const char *exec_file,
   /* We have something that executes now.  We'll be running through
      the shell at this point (if startup-with-shell is true), but the
      pid shouldn't change.  */
-  thread_info *thr = add_thread_silent (this, ptid);
+  thread_info *thr = add_thread_silent (this, ptid, true);
   switch_to_thread (thr);
 
   unpusher.release ();
@@ -167,7 +167,7 @@ inf_ptrace_target::attach (const char *args, int from_tty)
 
   /* Always add a main thread.  If some target extends the ptrace
      target, it should decorate the ptid later with more info.  */
-  thread_info *thr = add_thread_silent (this, ptid_t (pid));
+  thread_info *thr = add_thread_silent (this, ptid_t (pid), true);
   switch_to_thread (thr);
 
   /* Don't consider the thread stopped until we've processed its
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 1beade2acec..fe29a1ef214 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -241,28 +241,50 @@ post_create_inferior (int from_tty)
   infrun_debug_show_threads ("threads in the newly created inferior",
 			     current_inferior ()->non_exited_threads ());
 
+  /* When attaching to a multi-threaded process the "first" thread will be
+     stopped as part of the attach.  We then call stop_all_threads, which
+     will request that all threads stop.  When the first stop is processed
+     we will end up in here.
+
+     So, we expect that the "first" thread of the inferior should be
+     stopped, as well as one other random thread.  All of the other threads
+     should still be considered resumed, but will have a stop event
+     incoming.
+
+     As a consequence, we only make an assertion here about the currently
+     selected thread of the inferior.  Of the remaining threads, we only
+     expect one to be stopped, but we don't assert that.  */
+  gdb_assert (!inferior_thread ()->resumed ());
+
   /* If the target hasn't taken care of this already, do it now.
      Targets which need to access registers during to_open,
      to_create_inferior, or to_attach should do it earlier; but many
      don't need to.  */
   target_find_description ();
 
-  /* Now that we know the register layout, retrieve current PC.  But
-     if the PC is unavailable (e.g., we're opening a core file with
-     missing registers info), ignore it.  */
+  /* Now that we know the register layout, update the stop_pc if it is not
+     already set.  If GDB attached to a running process then the stop_pc
+     will have been set while processing the stop events triggered during
+     the attach.  If this is a core file, or we're just starting a new
+     process, then the stop_pc will not currently be set.
+
+     But, if the PC is unavailable (e.g., we're opening a core file with
+     missing registers info), ignore it.  Obviously, if we're trying to
+     debug a running process and we can't read the PC then this is bad and
+     shouldn't be ignored, but we'll soon hit errors trying to read the PC
+     elsewhere in GDB, so ignoring this here is fine.  */
   thread_info *thr = inferior_thread ();
-
-  thr->clear_stop_pc ();
-  try
-    {
-      regcache *rc = get_thread_regcache (thr);
-      thr->set_stop_pc (regcache_read_pc (rc));
-    }
-  catch (const gdb_exception_error &ex)
-    {
-      if (ex.error != NOT_AVAILABLE_ERROR)
-	throw;
-    }
+  if (!thr->stop_pc_p ())
+    try
+      {
+	regcache *rc = get_thread_regcache (thr);
+	thr->set_stop_pc (regcache_read_pc (rc));
+      }
+    catch (const gdb_exception_error &ex)
+      {
+	if (ex.error != NOT_AVAILABLE_ERROR)
+	  throw;
+      }
 
   if (current_program_space->exec_bfd ())
     {
@@ -460,6 +482,19 @@ run_command_1 (const char *args, int from_tty, enum run_how run_how)
   infrun_debug_show_threads ("immediately after create_process",
 			     current_inferior ()->non_exited_threads ());
 
+  /* All threads in the new inferior should be resumed, but not executing.
+     We now mark the thread(s) as non-resumed.
+
+     The thread will be marked resumed again later when we call proceed,
+     however, if that fails then we want to ensure the thread is left in a
+     non-resumed state.  */
+  for (thread_info *thread : current_inferior ()->threads ())
+    {
+      gdb_assert (thread->resumed ());
+      gdb_assert (!thread->executing ());
+      thread->set_resumed (false);
+    }
+
   /* We're starting off a new process.  When we get out of here, in
      non-stop mode, finish the state of all threads of that process,
      but leave other threads alone, as they may be stopped in internal
diff --git a/gdb/infrun.c b/gdb/infrun.c
index a814f5cbc2b..b5d1f126bdc 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -608,7 +608,13 @@ holding the child stopped.  Try \"set detach-on-fork\" or \
   /* If there is a child inferior, target_follow_fork must have created a thread
      for it.  */
   if (child_inf != nullptr)
-    gdb_assert (!child_inf->thread_list.empty ());
+    {
+      gdb_assert (!child_inf->thread_list.empty ());
+
+      /* Any added thread should have been marked non-resumed already.  */
+      for (thread_info *thread : child_inf->threads ())
+	gdb_assert (!thread->resumed ());
+    }
 
   /* Clear the parent thread's pending follow field.  Do this before calling
      target_detach, so that the target can differentiate the two following
@@ -1175,6 +1181,7 @@ follow_exec (ptid_t ptid, const char *exec_file_target)
      breakpoint or similar, it's gone now.  We cannot truly
      step-to-next statement through an exec().  */
   thread_info *th = inferior_thread ();
+  gdb_assert (!th->resumed ());
   th->control.step_resume_breakpoint = NULL;
   th->control.exception_resume_breakpoint = NULL;
   th->control.single_step_breakpoints = NULL;
@@ -1256,6 +1263,11 @@ follow_exec (ptid_t ptid, const char *exec_file_target)
   gdb_assert (current_inferior () == inf);
   gdb_assert (current_program_space == inf->pspace);
 
+  /* After the exec, all threads in the inferior should be in a non-resumed
+     state.  */
+  for (thread_info *thread : inf->non_exited_threads ())
+    gdb_assert (!thread->resumed ());
+
   /* Attempt to open the exec file.  SYMFILE_DEFER_BP_RESET is used
      because the proper displacement for a PIE (Position Independent
      Executable) main symbol file will only be computed by
@@ -2249,6 +2261,54 @@ internal_resume_ptid (int user_step)
   return user_visible_resume_ptid (user_step);
 }
 
+/* Before calling into target code to set inferior threads executing we
+   must mark all threads as resumed.  If an exception is thrown while
+   trying to set the threads executing then we should mark the threads as
+   non-resumed.
+
+   Create an instance of this struct before calling the target_* API to
+   set the threads executing.  If the targets are successfully set
+   executing then call the .commit() method.  In all other cases, any
+   threads that were marked resumed will be returned to their non-resumed
+   state.  */
+
+struct scoped_mark_thread_resumed
+{
+  /* Constructor.  All threads matching PTID will be marked as resumed.  */
+  scoped_mark_thread_resumed (process_stratum_target *targ, ptid_t ptid)
+    : m_target (targ), m_ptid (ptid)
+  {
+    gdb_assert (m_target != nullptr);
+    set_resumed (m_target, m_ptid, true);
+  }
+
+  /* Destructor.  If this instance was not committed (by calling the commit
+     method) then mark all threads matching M_PTID as no longer being
+     resumed.  */
+  ~scoped_mark_thread_resumed ()
+  {
+    if (m_target != nullptr)
+      set_resumed (m_target, m_ptid, false);
+  }
+
+  /* Called once all of the threads have successfully be set executing (by
+     calling the target_* API).  After this call the threads this object
+     marked as resumed will be left in the resumed state when the
+     destructor runs.  */
+  void commit ()
+  {
+    m_target = nullptr;
+  }
+
+private:
+
+  /* The target used for marking threads as resumed or non-resumed.  */
+  process_stratum_target *m_target;
+
+  /* The thread (or threads) to mark as resumed.  */
+  ptid_t m_ptid;
+};
+
 /* Wrapper for target_resume, that handles infrun-specific
    bookkeeping.  */
 
@@ -2257,6 +2317,11 @@ do_target_resume (ptid_t resume_ptid, bool step, enum gdb_signal sig)
 {
   struct thread_info *tp = inferior_thread ();
 
+  /* Create a scoped_mark_thread_resumed to mark all threads matching
+     RESUME_PTID as resumed.  */
+  process_stratum_target *curr_target = current_inferior ()->process_target ();
+  scoped_mark_thread_resumed scoped_resume (curr_target, resume_ptid);
+
   gdb_assert (!tp->stop_requested);
 
   /* Install inferior's terminal modes.  */
@@ -2296,6 +2361,9 @@ do_target_resume (ptid_t resume_ptid, bool step, enum gdb_signal sig)
 		       step, gdb_signal_to_symbol_string (sig));
 
   target_resume (resume_ptid, step, sig);
+
+  /* Call commit so SCOPED_RESUME leaves threads marked as resumed.  */
+  scoped_resume.commit ();
 }
 
 /* Resume the inferior.  SIG is the signal to give the inferior
@@ -2455,7 +2523,6 @@ resume_1 (enum gdb_signal sig)
 
 	      resume_ptid = internal_resume_ptid (user_step);
 	      do_target_resume (resume_ptid, false, GDB_SIGNAL_0);
-	      tp->set_resumed (true);
 	      return;
 	    }
 	}
@@ -2664,7 +2731,6 @@ resume_1 (enum gdb_signal sig)
     }
 
   do_target_resume (resume_ptid, step, sig);
-  tp->set_resumed (true);
 }
 
 /* Resume the inferior.  SIG is the signal to give the inferior
@@ -4938,7 +5004,7 @@ handle_one (const wait_one_event &event)
 	     Don't bother adding if it individually exited.  */
 	  if (t == nullptr
 	      && event.ws.kind () != TARGET_WAITKIND_THREAD_EXITED)
-	    t = add_thread (event.target, event.ptid);
+	    t = add_thread (event.target, event.ptid, true);
 	}
 
       if (t != nullptr)
@@ -4956,7 +5022,7 @@ handle_one (const wait_one_event &event)
     {
       thread_info *t = find_thread_ptid (event.target, event.ptid);
       if (t == NULL)
-	t = add_thread (event.target, event.ptid);
+	t = add_thread (event.target, event.ptid, true);
 
       t->stop_requested = 0;
       t->set_executing (false);
@@ -5367,7 +5433,7 @@ handle_inferior_event (struct execution_control_state *ecs)
       ecs->event_thread = find_thread_ptid (ecs->target, ecs->ptid);
       /* If it's a new thread, add it to the thread database.  */
       if (ecs->event_thread == NULL)
-	ecs->event_thread = add_thread (ecs->target, ecs->ptid);
+	ecs->event_thread = add_thread (ecs->target, ecs->ptid, true);
 
       /* Disable range stepping.  If the next step request could use a
 	 range, this will be end up re-enabled then.  */
@@ -5797,6 +5863,10 @@ handle_inferior_event (struct execution_control_state *ecs)
 	 execd thread for that case (this is a nop otherwise).  */
       ecs->event_thread = inferior_thread ();
 
+      /* If we did switch threads above, then the new thread should still
+	 be in the non-resumed state.  */
+      gdb_assert (!ecs->event_thread->resumed ());
+
       ecs->event_thread->set_stop_pc
 	(regcache_read_pc (get_thread_regcache (ecs->event_thread)));
 
@@ -6050,12 +6120,6 @@ finish_step_over (struct execution_control_state *ecs)
 
 	  /* Record the event thread's event for later.  */
 	  save_waitstatus (tp, ecs->ws);
-	  /* This was cleared early, by handle_inferior_event.  Set it
-	     so this pending event is considered by
-	     do_target_wait.  */
-	  tp->set_resumed (true);
-
-	  gdb_assert (!tp->executing ());
 
 	  regcache = get_thread_regcache (tp);
 	  tp->set_stop_pc (regcache_read_pc (regcache));
@@ -6066,6 +6130,10 @@ finish_step_over (struct execution_control_state *ecs)
 			       tp->ptid.to_string ().c_str (),
 			       currently_stepping (tp));
 
+	  /* This was cleared early, by handle_inferior_event.  Set it so
+	     this pending event is considered by do_target_wait.  */
+	  tp->set_resumed (true);
+
 	  /* This in-line step-over finished; clear this so we won't
 	     start a new one.  This is what handle_signal_stop would
 	     do, if we returned false.  */
@@ -7720,7 +7788,6 @@ keep_going_stepped_thread (struct thread_info *tp)
 				     get_frame_address_space (frame),
 				     tp->stop_pc ());
 
-      tp->set_resumed (true);
       resume_ptid = internal_resume_ptid (tp->control.stepping_command);
       do_target_resume (resume_ptid, false, GDB_SIGNAL_0);
     }
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index dff8d07d3f7..e1a38fb6efd 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -1041,7 +1041,7 @@ attach_proc_task_lwp_callback (ptid_t ptid)
 	  /* Also add the LWP to gdb's thread list, in case a
 	     matching libthread_db is not found (or the process uses
 	     raw clone).  */
-	  add_thread (linux_target, lp->ptid);
+	  add_thread (linux_target, lp->ptid, true);
 	  set_running (linux_target, lp->ptid, true);
 	  set_executing (linux_target, lp->ptid, true);
 	}
@@ -1924,7 +1924,7 @@ linux_handle_extended_wait (struct lwp_info *lp, int status)
 	      /* The process is not using thread_db.  Add the LWP to
 		 GDB's list.  */
 	      target_post_attach (new_lp->ptid.lwp ());
-	      add_thread (linux_target, new_lp->ptid);
+	      add_thread (linux_target, new_lp->ptid, true);
 	    }
 
 	  /* Even if we're stopping the thread for some reason
@@ -2793,7 +2793,7 @@ linux_nat_filter_event (int lwpid, int status)
 	      lp = add_lwp (ptid_t (lwpid, lwpid));
 	      lp->stopped = 1;
 	      lp->resumed = 1;
-	      add_thread (linux_target, lp->ptid);
+	      add_thread (linux_target, lp->ptid, true);
 	    }
 	  else
 	    {
@@ -2826,7 +2826,7 @@ linux_nat_filter_event (int lwpid, int status)
 
 		  lp = add_lwp (ptid_t (lwpid, lwpid));
 		  lp->resumed = 1;
-		  add_thread (linux_target, lp->ptid);
+		  add_thread (linux_target, lp->ptid, true);
 		  break;
 		}
 	    }
diff --git a/gdb/linux-thread-db.c b/gdb/linux-thread-db.c
index 11da82a1abc..6cbde7cbcb3 100644
--- a/gdb/linux-thread-db.c
+++ b/gdb/linux-thread-db.c
@@ -1366,7 +1366,7 @@ record_thread (struct thread_db_info *info,
      thread with this PTID, but it's marked exited, then the kernel
      reused the tid of an old thread.  */
   if (tp == NULL || tp->state == THREAD_EXITED)
-    tp = add_thread_with_info (info->process_target, ptid, priv);
+    tp = add_thread_with_info (info->process_target, ptid, priv, true);
   else
     tp->priv.reset (priv);
 
diff --git a/gdb/netbsd-nat.c b/gdb/netbsd-nat.c
index f2eeb3ff61e..0844559e352 100644
--- a/gdb/netbsd-nat.c
+++ b/gdb/netbsd-nat.c
@@ -125,7 +125,7 @@ nbsd_add_threads (nbsd_nat_target *target, pid_t pid)
 	    if (inferior_ptid.lwp () == 0)
 	      thread_change_ptid (target, inferior_ptid, ptid);
 	    else
-	      add_thread (target, ptid);
+	      add_thread (target, ptid, true);
 	  }
       };
 
@@ -651,7 +651,7 @@ nbsd_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
 	  ourstatus->set_spurious ();
       else
 	{
-	  add_thread (this, wptid);
+	  add_thread (this, wptid, true);
 	  ourstatus->set_thread_created ();
 	}
       return wptid;
diff --git a/gdb/nto-procfs.c b/gdb/nto-procfs.c
index 61374c9fad4..a71e86f3bee 100644
--- a/gdb/nto-procfs.c
+++ b/gdb/nto-procfs.c
@@ -411,7 +411,7 @@ nto_procfs_target::update_thread_list ()
       ptid = ptid_t (pid, 0, tid);
       new_thread = find_thread_ptid (this, ptid);
       if (!new_thread)
-	new_thread = add_thread (ptid);
+	new_thread = add_thread (ptid, true);
       update_thread_private_data (new_thread, tid, status.state, 0);
       status.tid++;
     }
diff --git a/gdb/obsd-nat.c b/gdb/obsd-nat.c
index c313e807d9b..f3ff1a3720d 100644
--- a/gdb/obsd-nat.c
+++ b/gdb/obsd-nat.c
@@ -62,7 +62,7 @@ obsd_nat_target::update_thread_list ()
 	  if (inferior_ptid.lwp () == 0)
 	    thread_change_ptid (this, inferior_ptid, ptid);
 	  else
-	    add_thread (this, ptid);
+	    add_thread (this, ptid, true);
 	}
 
       if (ptrace (PT_GET_THREAD_NEXT, pid, (caddr_t)&pts, sizeof pts) == -1)
@@ -133,7 +133,7 @@ obsd_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
 	  if (in_thread_list (this, ptid_t (pid)))
 	    thread_change_ptid (this, ptid_t (pid), wptid);
 	  else
-	    add_thread (this, wptid);
+	    add_thread (this, wptid, true);
 	}
     }
   return wptid;
diff --git a/gdb/process-stratum-target.c b/gdb/process-stratum-target.c
index 50bb13e4b83..b9eb8fbc990 100644
--- a/gdb/process-stratum-target.c
+++ b/gdb/process-stratum-target.c
@@ -100,7 +100,7 @@ process_stratum_target::follow_exec (inferior *follow_inf, ptid_t ptid,
 	 may decide to unpush itself from the original inferior's target stack
 	 after that, at its discretion.  */
       follow_inf->push_target (orig_inf->process_target ());
-      thread_info *t = add_thread (follow_inf->process_target (), ptid);
+      thread_info *t = add_thread (follow_inf->process_target (), ptid, false);
 
       /* Leave the new inferior / thread as the current inferior / thread.  */
       switch_to_thread (t);
@@ -118,7 +118,7 @@ process_stratum_target::follow_fork (inferior *child_inf, ptid_t child_ptid,
   if (child_inf != nullptr)
     {
       child_inf->push_target (this);
-      add_thread_silent (this, child_ptid);
+      add_thread_silent (this, child_ptid, false);
     }
 }
 
diff --git a/gdb/procfs.c b/gdb/procfs.c
index f6ca1345a21..5c42421470f 100644
--- a/gdb/procfs.c
+++ b/gdb/procfs.c
@@ -1864,7 +1864,7 @@ do_attach (ptid_t ptid)
 
   /* Add it to gdb's thread list.  */
   ptid = ptid_t (pi->pid, lwpid, 0);
-  thread_info *thr = add_thread (&the_procfs_target, ptid);
+  thread_info *thr = add_thread (&the_procfs_target, ptid, true);
   switch_to_thread (thr);
 }
 
@@ -2222,7 +2222,7 @@ procfs_target::wait (ptid_t ptid, struct target_waitstatus *status,
 		    temp_ptid = ptid_t (pi->pid, temp_tid, 0);
 		    /* If not in GDB's thread list, add it.  */
 		    if (!in_thread_list (this, temp_ptid))
-		      add_thread (this, temp_ptid);
+		      add_thread (this, temp_ptid, true);
 
 		    target_continue_no_signal (ptid);
 		    goto wait_again;
@@ -2281,7 +2281,7 @@ procfs_target::wait (ptid_t ptid, struct target_waitstatus *status,
 		    /* If not in GDB's thread list, add it.  */
 		    temp_ptid = ptid_t (pi->pid, temp_tid, 0);
 		    if (!in_thread_list (this, temp_ptid))
-		      add_thread (this, temp_ptid);
+		      add_thread (this, temp_ptid, true);
 
 		    status->set_stopped (GDB_SIGNAL_0);
 		    return retval;
@@ -2312,7 +2312,7 @@ procfs_target::wait (ptid_t ptid, struct target_waitstatus *status,
 		  /* We have a new thread.  We need to add it both to
 		     GDB's list and to our own.  If we don't create a
 		     procinfo, resume may be unhappy later.  */
-		  add_thread (this, retval);
+		  add_thread (this, retval, true);
 		  if (find_procinfo (retval.pid (),
 				     retval.lwp ()) == NULL)
 		    create_procinfo (retval.pid (),
@@ -2848,7 +2848,7 @@ procfs_target::create_inferior (const char *exec_file,
   /* We have something that executes now.  We'll be running through
      the shell at this point (if startup-with-shell is true), but the
      pid shouldn't change.  */
-  thread_info *thr = add_thread_silent (this, ptid_t (pid));
+  thread_info *thr = add_thread_silent (this, ptid_t (pid), true);
   switch_to_thread (thr);
 
   procfs_init_inferior (pid);
@@ -2863,7 +2863,7 @@ procfs_notice_thread (procinfo *pi, procinfo *thread, void *ptr)
 
   thread_info *thr = find_thread_ptid (&the_procfs_target, gdb_threadid);
   if (thr == NULL || thr->state == THREAD_EXITED)
-    add_thread (&the_procfs_target, gdb_threadid);
+    add_thread (&the_procfs_target, gdb_threadid, true);
 
   return 0;
 }
diff --git a/gdb/ravenscar-thread.c b/gdb/ravenscar-thread.c
index aae6e397327..e40eaaa0842 100644
--- a/gdb/ravenscar-thread.c
+++ b/gdb/ravenscar-thread.c
@@ -287,7 +287,7 @@ ravenscar_thread_target::add_active_thread ()
   thread_info *active_thr = find_thread_ptid (proc_target, active_ptid);
   if (active_thr == nullptr)
     {
-      active_thr = ::add_thread (proc_target, active_ptid);
+      active_thr = ::add_thread (proc_target, active_ptid, true);
       m_cpu_map[active_ptid.tid ()] = base_cpu;
     }
   return active_thr;
@@ -424,7 +424,7 @@ ravenscar_thread_target::add_thread (struct ada_task_info *task)
 {
   if (find_thread_ptid (current_inferior (), task->ptid) == NULL)
     {
-      ::add_thread (current_inferior ()->process_target (), task->ptid);
+      ::add_thread (current_inferior ()->process_target (), task->ptid, true);
       m_cpu_map[task->ptid.tid ()] = task->base_cpu;
     }
 }
diff --git a/gdb/remote-sim.c b/gdb/remote-sim.c
index 4b8afd27688..2b8fa15a634 100644
--- a/gdb/remote-sim.c
+++ b/gdb/remote-sim.c
@@ -661,7 +661,7 @@ gdbsim_target::create_inferior (const char *exec_file,
 
   inferior_appeared (current_inferior (),
 		     sim_data->remote_sim_ptid.pid ());
-  thread_info *thr = add_thread_silent (this, sim_data->remote_sim_ptid);
+  thread_info *thr = add_thread_silent (this, sim_data->remote_sim_ptid, true);
   switch_to_thread (thr);
 
   insert_breakpoints ();	/* Needed to get correct instruction
diff --git a/gdb/remote.c b/gdb/remote.c
index 75d6bf3919d..9559a8e3aae 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -740,7 +740,8 @@ class remote_target : public process_stratum_target
   int remote_resume_with_vcont (ptid_t ptid, int step,
 				gdb_signal siggnal);
 
-  thread_info *add_current_inferior_and_thread (const char *wait_status);
+  thread_info *add_current_inferior_and_thread (const char *wait_status,
+						bool resumed_p);
 
   ptid_t wait_ns (ptid_t ptid, struct target_waitstatus *status,
 		  target_wait_flags options);
@@ -2568,16 +2569,17 @@ remote_target::remote_add_thread (ptid_t ptid, bool running, bool executing,
      might be confusing to the user.  Be silent then, preserving the
      age old behavior.  */
   if (rs->starting_up || silent_p)
-    thread = add_thread_silent (this, ptid);
+    thread = add_thread_silent (this, ptid, true);
   else
-    thread = add_thread (this, ptid);
+    thread = add_thread (this, ptid, true);
 
   /* 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_resumed (this, ptid, running);
+  set_executing (this, ptid, executing);
 
   return thread;
 }
@@ -4471,7 +4473,8 @@ remote_target::get_current_thread (const char *wait_status)
    The function returns pointer to the main thread of the inferior. */
 
 thread_info *
-remote_target::add_current_inferior_and_thread (const char *wait_status)
+remote_target::add_current_inferior_and_thread (const char *wait_status,
+						bool resumed_p)
 {
   struct remote_state *rs = get_remote_state ();
   bool fake_pid_p = false;
@@ -4502,7 +4505,7 @@ remote_target::add_current_inferior_and_thread (const char *wait_status)
   /* Add the main thread and switch to it.  Don't try reading
      registers yet, since we haven't fetched the target description
      yet.  */
-  thread_info *tp = add_thread_silent (this, curr_ptid);
+  thread_info *tp = add_thread_silent (this, curr_ptid, resumed_p);
   switch_to_thread_no_regs (tp);
 
   return tp;
@@ -4612,6 +4615,7 @@ remote_target::process_initial_stop_replies (int from_tty)
 	evthread->set_pending_waitstatus (ws);
 
       set_executing (this, event_ptid, false);
+      set_resumed (this, event_ptid, false);
       set_running (this, event_ptid, false);
       get_remote_thread_info (evthread)->set_not_resumed ();
     }
@@ -4906,7 +4910,8 @@ remote_target::start_remote_1 (int from_tty, int extended_p)
 	  /* Target has no concept of threads at all.  GDB treats
 	     non-threaded target as single-threaded; add a main
 	     thread.  */
-	  thread_info *tp = add_current_inferior_and_thread (wait_status);
+	  thread_info *tp
+	    = add_current_inferior_and_thread (wait_status, true);
 	  get_remote_thread_info (tp)->set_resumed ();
 	}
       else
@@ -10476,7 +10481,7 @@ Remote replied unexpectedly while setting startup-with-shell: %s"),
 
   /* vRun's success return is a stop reply.  */
   stop_reply = run_worked ? rs->buf.data () : NULL;
-  add_current_inferior_and_thread (stop_reply);
+  add_current_inferior_and_thread (stop_reply, true);
 
   /* Get updated offsets, if the stub uses qOffsets.  */
   get_offsets ();
diff --git a/gdb/sol-thread.c b/gdb/sol-thread.c
index 18754f4f93b..5a70bd145cb 100644
--- a/gdb/sol-thread.c
+++ b/gdb/sol-thread.c
@@ -456,7 +456,7 @@ sol_thread_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
 	    {
 	      process_stratum_target *proc_target
 		= current_inferior ()->process_target ();
-	      add_thread (proc_target, rtnval);
+	      add_thread (proc_target, rtnval, true);
 	    }
 	}
     }
@@ -1008,7 +1008,7 @@ sol_update_thread_list_callback (const td_thrhandle_t *th, void *ignored)
     {
       process_stratum_target *proc_target
 	= current_inferior ()->process_target ();
-      add_thread (proc_target, ptid);
+      add_thread (proc_target, ptid, true);
     }
 
   return 0;
diff --git a/gdb/thread.c b/gdb/thread.c
index 378c5ee2d13..cb363dbef1c 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -260,15 +260,15 @@ new_thread (struct inferior *inf, ptid_t ptid)
 }
 
 struct thread_info *
-add_thread_silent (process_stratum_target *targ, ptid_t ptid)
+add_thread_silent (process_stratum_target *targ, ptid_t ptid, bool resumed_p)
 {
   gdb_assert (targ != nullptr);
 
   inferior *inf = find_inferior_ptid (targ, ptid);
 
-  threads_debug_printf ("add thread to inferior %d, ptid %s, target %s",
-			inf->num, ptid.to_string ().c_str (),
-			targ->shortname ());
+  threads_debug_printf
+    ("add thread to inferior %d, ptid %s, target %s, resumed_p = %d",
+     inf->num, ptid.to_string ().c_str (), targ->shortname (), resumed_p);
 
   /* We may have an old thread with the same id in the thread list.
      If we do, it must be dead, otherwise we wouldn't be adding a new
@@ -279,6 +279,14 @@ add_thread_silent (process_stratum_target *targ, ptid_t ptid)
     delete_thread (tp);
 
   tp = new_thread (inf, ptid);
+
+  /* Upon creation, all threads are non-executing, and non-resumed.  Before
+     notifying observers of the new thread, we set the resumed flag to the
+     desired value.  */
+  gdb_assert (!tp->executing ());
+  tp->set_resumed (resumed_p);
+
+  /* Announce the new thread to all observers.  */
   gdb::observers::new_thread.notify (tp);
 
   return tp;
@@ -286,9 +294,9 @@ add_thread_silent (process_stratum_target *targ, ptid_t ptid)
 
 struct thread_info *
 add_thread_with_info (process_stratum_target *targ, ptid_t ptid,
-		      private_thread_info *priv)
+		      private_thread_info *priv, bool resumed_p)
 {
-  thread_info *result = add_thread_silent (targ, ptid);
+  thread_info *result = add_thread_silent (targ, ptid, resumed_p);
 
   result->priv.reset (priv);
 
@@ -300,9 +308,9 @@ add_thread_with_info (process_stratum_target *targ, ptid_t ptid,
 }
 
 struct thread_info *
-add_thread (process_stratum_target *targ, ptid_t ptid)
+add_thread (process_stratum_target *targ, ptid_t ptid, bool resumed_p)
 {
-  return add_thread_with_info (targ, ptid, NULL);
+  return add_thread_with_info (targ, ptid, NULL, resumed_p);
 }
 
 private_thread_info::~private_thread_info () = default;
@@ -341,9 +349,18 @@ thread_info::deletable () const
 void
 thread_info::set_executing (bool executing)
 {
-  m_executing = executing;
+  if (executing == m_executing)
+    return;
+
+  gdb_assert (m_resumed);
+
   if (executing)
     this->clear_stop_pc ();
+
+  threads_debug_printf ("ptid = %s, executing = %d",
+			this->ptid.to_string ().c_str (),
+			executing);
+  m_executing = executing;
 }
 
 /* See gdbthread.h.  */
@@ -354,6 +371,8 @@ thread_info::set_resumed (bool resumed)
   if (resumed == m_resumed)
     return;
 
+  gdb_assert (!m_executing);
+
   process_stratum_target *proc_target = this->inf->process_target ();
 
   /* If we transition from resumed to not resumed, we might need to remove
@@ -361,6 +380,9 @@ thread_info::set_resumed (bool resumed)
   if (!resumed)
     proc_target->maybe_remove_resumed_with_pending_wait_status (this);
 
+  threads_debug_printf ("ptid = %s, resumed = %d",
+			this->ptid.to_string ().c_str (),
+			resumed);
   m_resumed = resumed;
 
   /* If we transition from not resumed to resumed, we might need to add
diff --git a/gdb/tracectf.c b/gdb/tracectf.c
index 155c8b7db06..cf3ea22d6b0 100644
--- a/gdb/tracectf.c
+++ b/gdb/tracectf.c
@@ -1169,7 +1169,8 @@ ctf_target_open (const char *dirname, int from_tty)
 
   inferior_appeared (current_inferior (), CTF_PID);
 
-  thread_info *thr = add_thread_silent (&ctf_ops, ptid_t (CTF_PID));
+  /* Pass false to indicate the thread starts in a non-resumed state.  */
+  thread_info *thr = add_thread_silent (&ctf_ops, ptid_t (CTF_PID), false);
   switch_to_thread (thr);
 
   merge_uploaded_trace_state_variables (&uploaded_tsvs);
diff --git a/gdb/tracefile-tfile.c b/gdb/tracefile-tfile.c
index f84ad2f4a3f..0fd90b23a94 100644
--- a/gdb/tracefile-tfile.c
+++ b/gdb/tracefile-tfile.c
@@ -557,7 +557,7 @@ tfile_target_open (const char *arg, int from_tty)
 
   inferior_appeared (current_inferior (), TFILE_PID);
 
-  thread_info *thr = add_thread_silent (&tfile_ops, ptid_t (TFILE_PID));
+  thread_info *thr = add_thread_silent (&tfile_ops, ptid_t (TFILE_PID), false);
   switch_to_thread (thr);
 
   if (ts->traceframe_count <= 0)
diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
index 1068558cd21..28aa1ae546c 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -384,9 +384,9 @@ windows_add_thread (ptid_t ptid, HANDLE h, void *tlb, bool main_thread_p)
      the main thread silently (in reality, this thread is really
      more of a process to the user than a thread).  */
   if (main_thread_p)
-    add_thread_silent (&the_windows_nat_target, ptid);
+    add_thread_silent (&the_windows_nat_target, ptid, true);
   else
-    add_thread (&the_windows_nat_target, ptid);
+    add_thread (&the_windows_nat_target, ptid, true);
 
   /* It's simplest to always set this and update the debug
      registers.  */
@@ -1907,6 +1907,14 @@ windows_nat_target::attach (const char *args, int from_tty)
 #endif
 
   do_initial_windows_stuff (pid, 1);
+
+  /* After attaching all threads are stopped.  It would be better if the
+     threads were added in the non-resumed state, but this is not currently
+     the case (the reason for this is just lack of understanding of how
+     threads are managed on Windows).  So we fix up the state here.  */
+  for (thread_info *thr : current_inferior ()->non_exited_threads ())
+    thr->set_resumed (false);
+
   target_terminal::ours ();
 }
 
-- 
2.25.4


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCHv4 1/2] gdb: add some additional thread status debug output
  2022-04-21 16:45       ` [PATCHv4 1/2] gdb: add some additional thread status debug output Andrew Burgess via Gdb-patches
@ 2022-04-21 20:35         ` Lancelot SIX via Gdb-patches
  2022-04-22 17:50           ` Andrew Burgess via Gdb-patches
  0 siblings, 1 reply; 30+ messages in thread
From: Lancelot SIX via Gdb-patches @ 2022-04-21 20:35 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches

Hi

I just have some minor remarks on this patch.  See below.

On Thu, Apr 21, 2022 at 05:45:55PM +0100, Andrew Burgess via Gdb-patches wrote:
> While working on this patch:
> 
>   https://sourceware.org/pipermail/gdb-patches/2022-January/185109.html
> 
> I found it really useful to print the executing/resumed status of all
> threads (or all threads in a particular inferior) at various
> places (e.g. when a new inferior is started, when GDB attaches, etc).
> 
> This debug was original part of the above patch, but I wanted to

original -> originally ?

> rewrite this as a separate patch and move the code into a new function
> in infrun.h, which is what this patch does.
> 
> Unless 'set debug infrun on' is in effect, then there should be no
> user visible changes after this commit.
> ---
>  gdb/infcmd.c | 19 ++++++++-----------
>  gdb/infrun.c |  3 +++
>  gdb/infrun.h | 26 ++++++++++++++++++++++++++
>  3 files changed, 37 insertions(+), 11 deletions(-)
> 
> diff --git a/gdb/infcmd.c b/gdb/infcmd.c
> index 84eb6e5d79b..1beade2acec 100644
> --- a/gdb/infcmd.c
> +++ b/gdb/infcmd.c
> @@ -238,6 +238,9 @@ post_create_inferior (int from_tty)
>    /* Be sure we own the terminal in case write operations are performed.  */ 
>    target_terminal::ours_for_output ();
>  
> +  infrun_debug_show_threads ("threads in the newly created inferior",
> +			     current_inferior ()->non_exited_threads ());
> +
>    /* If the target hasn't taken care of this already, do it now.
>       Targets which need to access registers during to_open,
>       to_create_inferior, or to_attach should do it earlier; but many
> @@ -454,6 +457,9 @@ run_command_1 (const char *args, int from_tty, enum run_how run_how)
>       shouldn't refer to run_target again.  */
>    run_target = NULL;
>  
> +  infrun_debug_show_threads ("immediately after create_process",
> +			     current_inferior ()->non_exited_threads ());
> +
>    /* We're starting off a new process.  When we get out of here, in
>       non-stop mode, finish the state of all threads of that process,
>       but leave other threads alone, as they may be stopped in internal
> @@ -2589,17 +2595,8 @@ attach_command (const char *args, int from_tty)
>       shouldn't refer to attach_target again.  */
>    attach_target = NULL;
>  
> -  if (debug_infrun)
> -    {
> -      infrun_debug_printf ("immediately after attach:");
> -      for (thread_info *thread : inferior->non_exited_threads ())
> -	infrun_debug_printf ("  thread %s, executing = %d, resumed = %d, "
> -			     "state = %s",
> -			     thread->ptid.to_string ().c_str (),
> -			     thread->executing (),
> -			     thread->resumed (),
> -			     thread_state_string (thread->state));
> -    }
> +  infrun_debug_show_threads ("immediately after attach",
> +			     current_inferior ()->non_exited_threads ());
>  
>    /* Enable async mode if it is supported by the target.  */
>    if (target_can_async_p ())
> diff --git a/gdb/infrun.c b/gdb/infrun.c
> index c311240b78c..a814f5cbc2b 100644
> --- a/gdb/infrun.c
> +++ b/gdb/infrun.c
> @@ -5043,6 +5043,9 @@ stop_all_threads (const char *reason, inferior *inf)
>    INFRUN_SCOPED_DEBUG_START_END ("reason=%s, inf=%d", reason,
>  				 inf != nullptr ? inf->num : -1);
>  
> +  infrun_debug_show_threads ("non-exited threads",
> +			     all_non_exited_threads ());
> +
>    scoped_restore_current_thread restore_thread;
>  
>    /* Enable thread events on relevant targets.  */
> diff --git a/gdb/infrun.h b/gdb/infrun.h
> index 9685f3a9775..1421fa4050a 100644
> --- a/gdb/infrun.h
> +++ b/gdb/infrun.h
> @@ -48,6 +48,32 @@ extern bool debug_infrun;
>  #define INFRUN_SCOPED_DEBUG_ENTER_EXIT \
>    scoped_debug_enter_exit (debug_infrun, "infrun")
>  
> +/* A infrun debug helper routine to print out all the threads in the set
> +   THREADS (which should be a range type that returns thread_info*
> +   objects).
> +
> +   The TITLE is a string that is printed before the list of threads.
> +
> +   Output is only produced when 'set debug infrun on'.  */
> +
> +template<typename ThreadRange>
> +static inline void
> +infrun_debug_show_threads (const char *title, ThreadRange threads)
> +{
> +  if (debug_infrun)
> +    {
> +      infrun_debug_printf ("%s:", (title));

I do not think the extra parens around title are necessary.

Best,
Lancelot

> +      for (thread_info *thread : threads)
> +	infrun_debug_printf ("  thread %s, executing = %d, resumed = %d, "
> +			     "state = %s",
> +			     thread->ptid.to_string ().c_str (),
> +			     thread->executing (),
> +			     thread->resumed (),
> +			     thread_state_string (thread->state));
> +    }
> +}
> +
> +
>  /* Nonzero if we want to give control to the user when we're notified
>     of shared library events by the dynamic linker.  */
>  extern int stop_on_solib_events;
> -- 
> 2.25.4
> 

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCHv4 1/2] gdb: add some additional thread status debug output
  2022-04-21 20:35         ` Lancelot SIX via Gdb-patches
@ 2022-04-22 17:50           ` Andrew Burgess via Gdb-patches
  2022-05-03 14:04             ` Andrew Burgess via Gdb-patches
  0 siblings, 1 reply; 30+ messages in thread
From: Andrew Burgess via Gdb-patches @ 2022-04-22 17:50 UTC (permalink / raw)
  To: Lancelot SIX; +Cc: gdb-patches

Lancelot SIX via Gdb-patches <gdb-patches@sourceware.org> writes:

> Hi
>
> I just have some minor remarks on this patch.  See below.
>
> On Thu, Apr 21, 2022 at 05:45:55PM +0100, Andrew Burgess via Gdb-patches wrote:
>> While working on this patch:
>> 
>>   https://sourceware.org/pipermail/gdb-patches/2022-January/185109.html
>> 
>> I found it really useful to print the executing/resumed status of all
>> threads (or all threads in a particular inferior) at various
>> places (e.g. when a new inferior is started, when GDB attaches, etc).
>> 
>> This debug was original part of the above patch, but I wanted to
>
> original -> originally ?
>
>> rewrite this as a separate patch and move the code into a new function
>> in infrun.h, which is what this patch does.
>> 
>> Unless 'set debug infrun on' is in effect, then there should be no
>> user visible changes after this commit.
>> ---
>>  gdb/infcmd.c | 19 ++++++++-----------
>>  gdb/infrun.c |  3 +++
>>  gdb/infrun.h | 26 ++++++++++++++++++++++++++
>>  3 files changed, 37 insertions(+), 11 deletions(-)
>> 
>> diff --git a/gdb/infcmd.c b/gdb/infcmd.c
>> index 84eb6e5d79b..1beade2acec 100644
>> --- a/gdb/infcmd.c
>> +++ b/gdb/infcmd.c
>> @@ -238,6 +238,9 @@ post_create_inferior (int from_tty)
>>    /* Be sure we own the terminal in case write operations are performed.  */ 
>>    target_terminal::ours_for_output ();
>>  
>> +  infrun_debug_show_threads ("threads in the newly created inferior",
>> +			     current_inferior ()->non_exited_threads ());
>> +
>>    /* If the target hasn't taken care of this already, do it now.
>>       Targets which need to access registers during to_open,
>>       to_create_inferior, or to_attach should do it earlier; but many
>> @@ -454,6 +457,9 @@ run_command_1 (const char *args, int from_tty, enum run_how run_how)
>>       shouldn't refer to run_target again.  */
>>    run_target = NULL;
>>  
>> +  infrun_debug_show_threads ("immediately after create_process",
>> +			     current_inferior ()->non_exited_threads ());
>> +
>>    /* We're starting off a new process.  When we get out of here, in
>>       non-stop mode, finish the state of all threads of that process,
>>       but leave other threads alone, as they may be stopped in internal
>> @@ -2589,17 +2595,8 @@ attach_command (const char *args, int from_tty)
>>       shouldn't refer to attach_target again.  */
>>    attach_target = NULL;
>>  
>> -  if (debug_infrun)
>> -    {
>> -      infrun_debug_printf ("immediately after attach:");
>> -      for (thread_info *thread : inferior->non_exited_threads ())
>> -	infrun_debug_printf ("  thread %s, executing = %d, resumed = %d, "
>> -			     "state = %s",
>> -			     thread->ptid.to_string ().c_str (),
>> -			     thread->executing (),
>> -			     thread->resumed (),
>> -			     thread_state_string (thread->state));
>> -    }
>> +  infrun_debug_show_threads ("immediately after attach",
>> +			     current_inferior ()->non_exited_threads ());
>>  
>>    /* Enable async mode if it is supported by the target.  */
>>    if (target_can_async_p ())
>> diff --git a/gdb/infrun.c b/gdb/infrun.c
>> index c311240b78c..a814f5cbc2b 100644
>> --- a/gdb/infrun.c
>> +++ b/gdb/infrun.c
>> @@ -5043,6 +5043,9 @@ stop_all_threads (const char *reason, inferior *inf)
>>    INFRUN_SCOPED_DEBUG_START_END ("reason=%s, inf=%d", reason,
>>  				 inf != nullptr ? inf->num : -1);
>>  
>> +  infrun_debug_show_threads ("non-exited threads",
>> +			     all_non_exited_threads ());
>> +
>>    scoped_restore_current_thread restore_thread;
>>  
>>    /* Enable thread events on relevant targets.  */
>> diff --git a/gdb/infrun.h b/gdb/infrun.h
>> index 9685f3a9775..1421fa4050a 100644
>> --- a/gdb/infrun.h
>> +++ b/gdb/infrun.h
>> @@ -48,6 +48,32 @@ extern bool debug_infrun;
>>  #define INFRUN_SCOPED_DEBUG_ENTER_EXIT \
>>    scoped_debug_enter_exit (debug_infrun, "infrun")
>>  
>> +/* A infrun debug helper routine to print out all the threads in the set
>> +   THREADS (which should be a range type that returns thread_info*
>> +   objects).
>> +
>> +   The TITLE is a string that is printed before the list of threads.
>> +
>> +   Output is only produced when 'set debug infrun on'.  */
>> +
>> +template<typename ThreadRange>
>> +static inline void
>> +infrun_debug_show_threads (const char *title, ThreadRange threads)
>> +{
>> +  if (debug_infrun)
>> +    {
>> +      infrun_debug_printf ("%s:", (title));
>
> I do not think the extra parens around title are necessary.

Thanks, I made these fixes locally.

Andrew

>
> Best,
> Lancelot
>
>> +      for (thread_info *thread : threads)
>> +	infrun_debug_printf ("  thread %s, executing = %d, resumed = %d, "
>> +			     "state = %s",
>> +			     thread->ptid.to_string ().c_str (),
>> +			     thread->executing (),
>> +			     thread->resumed (),
>> +			     thread_state_string (thread->state));
>> +    }
>> +}
>> +
>> +
>>  /* Nonzero if we want to give control to the user when we're notified
>>     of shared library events by the dynamic linker.  */
>>  extern int stop_on_solib_events;
>> -- 
>> 2.25.4
>> 


^ permalink raw reply	[flat|nested] 30+ messages in thread

* gdb: make thread_info executing and resumed state more consistent
  2022-04-21 16:45     ` [PATCHv4 0/2] Make " Andrew Burgess via Gdb-patches
  2022-04-21 16:45       ` [PATCHv4 1/2] gdb: add some additional thread status debug output Andrew Burgess via Gdb-patches
  2022-04-21 16:45       ` [PATCHv4 2/2] gdb: make thread_info executing and resumed state more consistent Andrew Burgess via Gdb-patches
@ 2022-04-26 13:28       ` Nidal Faour via Gdb-patches
  2022-08-08 11:04       ` [PATCHv4 0/2] Make " Craig Blackmore
  3 siblings, 0 replies; 30+ messages in thread
From: Nidal Faour via Gdb-patches @ 2022-04-26 13:28 UTC (permalink / raw)
  To: gdb-patches

Thanks Andrew for the effort.

I would like to see this change up-streamed, as we hit a real issue 
where the gdb lost context because the thread info state was not 
consistent (execute/resume)

Best regards,

Nidal



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCHv4 1/2] gdb: add some additional thread status debug output
  2022-04-22 17:50           ` Andrew Burgess via Gdb-patches
@ 2022-05-03 14:04             ` Andrew Burgess via Gdb-patches
  0 siblings, 0 replies; 30+ messages in thread
From: Andrew Burgess via Gdb-patches @ 2022-05-03 14:04 UTC (permalink / raw)
  To: Lancelot SIX; +Cc: gdb-patches

Andrew Burgess <aburgess@redhat.com> writes:

> Lancelot SIX via Gdb-patches <gdb-patches@sourceware.org> writes:
>
>> Hi
>>
>> I just have some minor remarks on this patch.  See below.
>>
>> On Thu, Apr 21, 2022 at 05:45:55PM +0100, Andrew Burgess via Gdb-patches wrote:
>>> While working on this patch:
>>> 
>>>   https://sourceware.org/pipermail/gdb-patches/2022-January/185109.html
>>> 
>>> I found it really useful to print the executing/resumed status of all
>>> threads (or all threads in a particular inferior) at various
>>> places (e.g. when a new inferior is started, when GDB attaches, etc).
>>> 
>>> This debug was original part of the above patch, but I wanted to
>>
>> original -> originally ?
>>
>>> rewrite this as a separate patch and move the code into a new function
>>> in infrun.h, which is what this patch does.
>>> 
>>> Unless 'set debug infrun on' is in effect, then there should be no
>>> user visible changes after this commit.
>>> ---
>>>  gdb/infcmd.c | 19 ++++++++-----------
>>>  gdb/infrun.c |  3 +++
>>>  gdb/infrun.h | 26 ++++++++++++++++++++++++++
>>>  3 files changed, 37 insertions(+), 11 deletions(-)
>>> 
>>> diff --git a/gdb/infcmd.c b/gdb/infcmd.c
>>> index 84eb6e5d79b..1beade2acec 100644
>>> --- a/gdb/infcmd.c
>>> +++ b/gdb/infcmd.c
>>> @@ -238,6 +238,9 @@ post_create_inferior (int from_tty)
>>>    /* Be sure we own the terminal in case write operations are performed.  */ 
>>>    target_terminal::ours_for_output ();
>>>  
>>> +  infrun_debug_show_threads ("threads in the newly created inferior",
>>> +			     current_inferior ()->non_exited_threads ());
>>> +
>>>    /* If the target hasn't taken care of this already, do it now.
>>>       Targets which need to access registers during to_open,
>>>       to_create_inferior, or to_attach should do it earlier; but many
>>> @@ -454,6 +457,9 @@ run_command_1 (const char *args, int from_tty, enum run_how run_how)
>>>       shouldn't refer to run_target again.  */
>>>    run_target = NULL;
>>>  
>>> +  infrun_debug_show_threads ("immediately after create_process",
>>> +			     current_inferior ()->non_exited_threads ());
>>> +
>>>    /* We're starting off a new process.  When we get out of here, in
>>>       non-stop mode, finish the state of all threads of that process,
>>>       but leave other threads alone, as they may be stopped in internal
>>> @@ -2589,17 +2595,8 @@ attach_command (const char *args, int from_tty)
>>>       shouldn't refer to attach_target again.  */
>>>    attach_target = NULL;
>>>  
>>> -  if (debug_infrun)
>>> -    {
>>> -      infrun_debug_printf ("immediately after attach:");
>>> -      for (thread_info *thread : inferior->non_exited_threads ())
>>> -	infrun_debug_printf ("  thread %s, executing = %d, resumed = %d, "
>>> -			     "state = %s",
>>> -			     thread->ptid.to_string ().c_str (),
>>> -			     thread->executing (),
>>> -			     thread->resumed (),
>>> -			     thread_state_string (thread->state));
>>> -    }
>>> +  infrun_debug_show_threads ("immediately after attach",
>>> +			     current_inferior ()->non_exited_threads ());
>>>  
>>>    /* Enable async mode if it is supported by the target.  */
>>>    if (target_can_async_p ())
>>> diff --git a/gdb/infrun.c b/gdb/infrun.c
>>> index c311240b78c..a814f5cbc2b 100644
>>> --- a/gdb/infrun.c
>>> +++ b/gdb/infrun.c
>>> @@ -5043,6 +5043,9 @@ stop_all_threads (const char *reason, inferior *inf)
>>>    INFRUN_SCOPED_DEBUG_START_END ("reason=%s, inf=%d", reason,
>>>  				 inf != nullptr ? inf->num : -1);
>>>  
>>> +  infrun_debug_show_threads ("non-exited threads",
>>> +			     all_non_exited_threads ());
>>> +
>>>    scoped_restore_current_thread restore_thread;
>>>  
>>>    /* Enable thread events on relevant targets.  */
>>> diff --git a/gdb/infrun.h b/gdb/infrun.h
>>> index 9685f3a9775..1421fa4050a 100644
>>> --- a/gdb/infrun.h
>>> +++ b/gdb/infrun.h
>>> @@ -48,6 +48,32 @@ extern bool debug_infrun;
>>>  #define INFRUN_SCOPED_DEBUG_ENTER_EXIT \
>>>    scoped_debug_enter_exit (debug_infrun, "infrun")
>>>  
>>> +/* A infrun debug helper routine to print out all the threads in the set
>>> +   THREADS (which should be a range type that returns thread_info*
>>> +   objects).
>>> +
>>> +   The TITLE is a string that is printed before the list of threads.
>>> +
>>> +   Output is only produced when 'set debug infrun on'.  */
>>> +
>>> +template<typename ThreadRange>
>>> +static inline void
>>> +infrun_debug_show_threads (const char *title, ThreadRange threads)
>>> +{
>>> +  if (debug_infrun)
>>> +    {
>>> +      infrun_debug_printf ("%s:", (title));
>>
>> I do not think the extra parens around title are necessary.
>
> Thanks, I made these fixes locally.

I've gone ahead and pushed just this patch for now.

Thanks,
Andrew


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCHv4 0/2] Make thread_info executing and resumed state more consistent
  2022-04-21 16:45     ` [PATCHv4 0/2] Make " Andrew Burgess via Gdb-patches
                         ` (2 preceding siblings ...)
  2022-04-26 13:28       ` Nidal Faour via Gdb-patches
@ 2022-08-08 11:04       ` Craig Blackmore
  2022-08-08 12:01         ` Andrew Burgess via Gdb-patches
  3 siblings, 1 reply; 30+ messages in thread
From: Craig Blackmore @ 2022-08-08 11:04 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches


On 21/04/2022 17:45, Andrew Burgess via Gdb-patches wrote:
> And I'm back on this patch again!
>
> I've rebased this onto current master and done some testing.  I
> haven't found any regressions, but as I've said before, this change
> touches every target, and my testing on anything other than GNU/Linux
> (x86-64) is pretty thin, so I'm fully expecting this to introduce some
> issues - these issues _should_ be limited to assertion failures when
> threads are not in the expected states, I would hope there's no
> crashes being introduced.
>
> There's been no significant changes since v3.  I have split out a
> little bit of the debug printing code (the new #1 patch), but the
> second patch is pretty much the same as v3.
>
> V3 was given a cautious OK, but I wanted to advertise this patch again
> in case anyone wants to object before I merge this.

Hi Andrew,

Do you still intend to merge the second patch in this series?

Thanks,

Craig

> All feedback is welcome.
>
> Thanks,
> Andrew
>
> ---
>
> Andrew Burgess (2):
>    gdb: add some additional thread status debug output
>    gdb: make thread_info executing and resumed state more consistent
>
>   gdb/aix-thread.c             |  4 +-
>   gdb/bsd-kvm.c                |  2 +-
>   gdb/bsd-uthread.c            |  4 +-
>   gdb/corelow.c                |  9 +++-
>   gdb/darwin-nat.c             |  2 +-
>   gdb/fbsd-nat.c               |  4 +-
>   gdb/fork-child.c             |  3 ++
>   gdb/gdbthread.h              | 24 ++++++---
>   gdb/gnu-nat.c                | 13 +++--
>   gdb/go32-nat.c               |  2 +-
>   gdb/inf-ptrace.c             |  4 +-
>   gdb/infcmd.c                 | 84 +++++++++++++++++++++----------
>   gdb/infrun.c                 | 96 +++++++++++++++++++++++++++++++-----
>   gdb/infrun.h                 | 26 ++++++++++
>   gdb/linux-nat.c              |  8 +--
>   gdb/linux-thread-db.c        |  2 +-
>   gdb/netbsd-nat.c             |  4 +-
>   gdb/nto-procfs.c             |  2 +-
>   gdb/obsd-nat.c               |  4 +-
>   gdb/process-stratum-target.c |  4 +-
>   gdb/procfs.c                 | 12 ++---
>   gdb/ravenscar-thread.c       |  4 +-
>   gdb/remote-sim.c             |  2 +-
>   gdb/remote.c                 | 21 +++++---
>   gdb/sol-thread.c             |  4 +-
>   gdb/thread.c                 | 40 +++++++++++----
>   gdb/tracectf.c               |  3 +-
>   gdb/tracefile-tfile.c        |  2 +-
>   gdb/windows-nat.c            | 12 ++++-
>   29 files changed, 295 insertions(+), 106 deletions(-)
>

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCHv4 0/2] Make thread_info executing and resumed state more consistent
  2022-08-08 11:04       ` [PATCHv4 0/2] Make " Craig Blackmore
@ 2022-08-08 12:01         ` Andrew Burgess via Gdb-patches
  0 siblings, 0 replies; 30+ messages in thread
From: Andrew Burgess via Gdb-patches @ 2022-08-08 12:01 UTC (permalink / raw)
  To: Craig Blackmore, gdb-patches

Craig Blackmore <craig.blackmore@embecosm.com> writes:

> On 21/04/2022 17:45, Andrew Burgess via Gdb-patches wrote:
>> And I'm back on this patch again!
>>
>> I've rebased this onto current master and done some testing.  I
>> haven't found any regressions, but as I've said before, this change
>> touches every target, and my testing on anything other than GNU/Linux
>> (x86-64) is pretty thin, so I'm fully expecting this to introduce some
>> issues - these issues _should_ be limited to assertion failures when
>> threads are not in the expected states, I would hope there's no
>> crashes being introduced.
>>
>> There's been no significant changes since v3.  I have split out a
>> little bit of the debug printing code (the new #1 patch), but the
>> second patch is pretty much the same as v3.
>>
>> V3 was given a cautious OK, but I wanted to advertise this patch again
>> in case anyone wants to object before I merge this.
>
> Hi Andrew,
>
> Do you still intend to merge the second patch in this series?

I do intend to return to this work, but I have another patch that I need
to get finished first before I'll have any free time to look at this.

When I do go back to this work I'm tempted to start fresh.  I was always
a little unsure about all the changes to the new thread creation code
(setting the resumed/executing flags in new threads), and I'm hoping
that if I start fresh then I might be able to come up with something
that feels a little cleaner.

That said, I'd certainly be supportive if anyone wanted to take this
patch on and move it forward.

Thanks,
Andrew


^ permalink raw reply	[flat|nested] 30+ messages in thread

end of thread, other threads:[~2022-08-08 12:02 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-30 20:03 [PATCH 0/3] Changes to thread state tracking Andrew Burgess
2021-08-30 20:03 ` [PATCH 1/3] gdb: make thread_info::executing private Andrew Burgess
2021-09-01 13:53   ` Simon Marchi via Gdb-patches
2021-09-07 11:46     ` Andrew Burgess
2021-08-30 20:03 ` [PATCH 2/3] gdb: make thread_suspend_state::stop_pc optional Andrew Burgess
2021-09-01 14:23   ` Simon Marchi via Gdb-patches
2021-09-07 13:21     ` Andrew Burgess
2021-09-07 14:10       ` Simon Marchi via Gdb-patches
2021-09-08  9:50         ` Andrew Burgess
2021-08-30 20:03 ` [PATCH 3/3] gdb: make thread_info executing and resumed state more consistent Andrew Burgess
2021-09-01 15:09   ` Simon Marchi via Gdb-patches
2021-09-22 11:21     ` Andrew Burgess
2021-09-23 17:14       ` Simon Marchi via Gdb-patches
2021-09-29  8:09         ` Andrew Burgess
2021-10-08 19:33           ` Simon Marchi via Gdb-patches
2022-01-13 18:34   ` [PATCHv3] " Andrew Burgess via Gdb-patches
2022-01-14 17:10     ` Simon Marchi via Gdb-patches
2022-02-24 15:52       ` Andrew Burgess via Gdb-patches
2022-03-03 19:42         ` Simon Marchi via Gdb-patches
2022-03-07  7:39           ` Aktemur, Tankut Baris via Gdb-patches
2022-03-30  9:19         ` Andrew Burgess via Gdb-patches
2022-04-21 16:45     ` [PATCHv4 0/2] Make " Andrew Burgess via Gdb-patches
2022-04-21 16:45       ` [PATCHv4 1/2] gdb: add some additional thread status debug output Andrew Burgess via Gdb-patches
2022-04-21 20:35         ` Lancelot SIX via Gdb-patches
2022-04-22 17:50           ` Andrew Burgess via Gdb-patches
2022-05-03 14:04             ` Andrew Burgess via Gdb-patches
2022-04-21 16:45       ` [PATCHv4 2/2] gdb: make thread_info executing and resumed state more consistent Andrew Burgess via Gdb-patches
2022-04-26 13:28       ` Nidal Faour via Gdb-patches
2022-08-08 11:04       ` [PATCHv4 0/2] Make " Craig Blackmore
2022-08-08 12:01         ` Andrew Burgess via Gdb-patches

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox