Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Pedro Alves <pedro@palves.net>
To: gdb-patches@sourceware.org
Subject: [PATCH v2 05/47] thread_info::executing+resumed -> thread_info::internal_state
Date: Mon, 19 May 2025 14:22:26 +0100	[thread overview]
Message-ID: <20250519132308.3553663-6-pedro@palves.net> (raw)
In-Reply-To: <20250519132308.3553663-1-pedro@palves.net>

While working on Windows non-stop support, I ran into a
very-hard-to-track-down bug.

The problem turned out to be that
infrun.c:proceed_resume_thread_checked resumed an already-executing
thread because the thread was marked as "executing=true,
resumed=false", and that function only skips resuming threads that are
marked resumed=true.  The consequence was that GDB corrupted the
registers of the Windows DLL loader threads, eventually leading to a
GDB+inferior deadlock.

Originally, the "resumed" flag was only ever set when infrun decided
is was ready to process a thread's pending wait status.  infrun has
since evolved to set the resumed flag when we set a thread's executing
flag too.  We are not always consistent throughout in guaranteeing
that a thread is marked resumed=true whenever it is marked
executing=true, though.  For instance, no target code that supports
non-stop mode (linux-nat, remote, and windows-nat with this series) is
making sure that new threads are marked resumed=true when they are
added to the thread list.  They are only marked as {state=running,
executing=true}, the "resumed" flag is not touched.

Making proceed_resume_thread_checked check thr->executing() in
addition to thr->resumed(), feels like papering over a combination of
states that shouldn't happen nowadays.

OTOH, having to have the target backends mark new threads as
resumed=true just feels like too many different states (three) to set:

  add_thread (...);
  set_running (...);
  set_executing (...);
  set_resumed (...);

Yuck.  I think we can do better.

We really have too many "state tracking" flags in a thread.
Basically:

 - whether a thread is "running/stopped/exited" (from the user's
   perspective).  This is the thread_info::state field.

 - whether a thread is "executing" (infrun asked the target to set the
   thread executing).  This is thread_info::executing().

 - whether a thread is "resumed" (infrun wants the thread to be
   resumed, but maybe can't yet because the thread has a pending wait
   status).  This is thread_info::resumed()

"running", "executing", and "resumed" are almost synonyms, so this can
be highly confusing English-wise too.

For "running" vs "executing", in comments, we tipically need to
explain that "running/stopped/exited" is for the user/frontend
perspective, while "executing true/false" is for gdb's internal run
control.

(Also, "executing or not" can also mean something else in GDB's
codebase -- "target has execution" does not mean that threads are
actually running right now -- it's a test for whether we have a live
process vs a core dump!)

One simplification we can do that avoids this running vs executing
ambiguity is to replace the "executing" field with an "internal_state"
field, similar to the thread_info::state field, and make that new
internal_state field reuse the same enum thread_state type that is
used by thread_info::state.  Like:

  struct thread_info
  {
  ...
    /* Frontend/public/external/user view of the thread state.  */
    enum thread_state m_state = THREAD_STOPPED;

    /* The thread's internal state.  When the thread is stopped
       internally while handling an internal event, like a software
       single-step breakpoint, the internal state will be
       THREAD_STOPPED, but the external state will still be
       THREAD_RUNNING.  */
    enum thread_state m_internal_state = THREAD_STOPPED;
  };

(Assume we'd add state() and internal_state() getters.)

With that, every check for thr->executing() is replaced with a
'thr->internal_state() == THREAD_RUNNING' check, and the code is
clearer by design.  There is no confusion between "running" vs
"executing" any more, because they now mean the exact same thing.
Instead, we say e.g., 'thread has (user) state "running", and internal
state "stopped"'.  Or simpler, 'thread is running (from the user's
perspective), but internally stopped'.  That is after all what we
would way in comments today already.

That still leaves the 'resumed' flag, though.  That's the least
obvious one.  Turns out we can get rid of it, and make it a new state
tracked by thread_info::internal_state.  That is, we make
internal_state have its own enumeration type (decoupled from
thread_info::state's type), and convert the resumed true/false flag to
a new enumerator of this new enumeration.  Like so:

  enum thread_int_state
  {
    THREAD_INT_STOPPED,
    THREAD_INT_RUNNING,
 +   THREAD_INT_RESUMED_PENDING_STATUS,
    THREAD_INT_EXITED,
  };

That is what this patch does.  So in summary, we go from:

 thread_info::state {THREAD_STOPPED, THREAD_RUNNING, THREAD_EXITED}
 thread_info::executing {false, true}
 thread_info::resumed {false, true}

to:

 thread_info::state {THREAD_STOPPED, THREAD_RUNNING, THREAD_EXITED}
 thread_info::internal_state {THREAD_INT_STOPPED, THREAD_INT_RUNNING,
                              THREAD_INT_RESUMED_PENDING_STATUS,
			      THREAD_INT_EXITED}

The patch adds getters/setters for both (user) state and
internal_state, and adds assertions around state transitions, ensuring
that internal_state doesn't get out of sync with
thread::have_pending_wait_status().  It also adds an assertion to
clear_proceed_status_thread, making sure that we don't try to proceed
a thread that is already running.  Turns out that catches
attach_command calling init_wait_for_inferior too late, after
attaching has already created already-running threads.

The code that adds/removes threads from the proc_target's
resumed_with_pending_wait_status list is all centralized within
thread_info::set_internal_state, when we switch to/from the
resumed-pending-status state.  With the assertions in place, it should
be impossible to end up with a THREAD_INT_RUNNING thread with a
pending status.

The thread.c:set_running, thread.c:set_executing, thread.c:set_resumed
global functions are all gone, replaced with new thread.c:set_state
and thread.c:set_internal_state functions.

Tested on x86_64-linux-gnu, native and gdbserver.

Change-Id: I4f5097d68f4694d44e1ae23fea3e9bce45fb078c
---
 gdb/aarch64-tdep.c           |   2 +-
 gdb/amd-dbgapi-target.c      |   8 +-
 gdb/breakpoint.c             |   9 +-
 gdb/bsd-uthread.c            |   4 +-
 gdb/fork-child.c             |   4 +-
 gdb/frame.c                  |   4 +-
 gdb/gcore.c                  |   4 +-
 gdb/gdbthread.h              | 146 +++++++++--------
 gdb/i386-tdep.c              |   4 +-
 gdb/inf-ptrace.c             |   2 +-
 gdb/infcall.c                |   8 +-
 gdb/infcmd.c                 |  39 ++---
 gdb/inferior.h               |   4 +-
 gdb/inflow.c                 |   2 +-
 gdb/infrun.c                 | 152 +++++++++---------
 gdb/infrun.h                 |   7 +-
 gdb/linux-fork.c             |   9 +-
 gdb/linux-nat.c              |   7 +-
 gdb/linux-thread-db.c        |   4 +-
 gdb/mi/mi-cmd-var.c          |   4 +-
 gdb/mi/mi-interp.c           |   2 +-
 gdb/mi/mi-main.c             |   8 +-
 gdb/process-stratum-target.c |   6 +-
 gdb/python/py-infthread.c    |   6 +-
 gdb/record-btrace.c          |  20 +--
 gdb/record-full.c            |   6 +-
 gdb/regcache.c               |   2 +-
 gdb/remote.c                 |  76 +++++----
 gdb/sol-thread.c             |   4 +-
 gdb/target.c                 |  15 +-
 gdb/thread-iter.h            |   2 +-
 gdb/thread.c                 | 299 ++++++++++++++++++++---------------
 gdb/top.c                    |   2 +-
 33 files changed, 474 insertions(+), 397 deletions(-)

diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
index 8d54e59f332..8e1908452c5 100644
--- a/gdb/aarch64-tdep.c
+++ b/gdb/aarch64-tdep.c
@@ -4265,7 +4265,7 @@ aarch64_remove_non_address_bits (struct gdbarch *gdbarch, CORE_ADDR pointer)
 
       /* If the thread is running, we will not be able to fetch the mask
 	 registers.  */
-      if (thread != nullptr && thread->state != THREAD_RUNNING)
+      if (thread != nullptr && thread->state () != THREAD_RUNNING)
 	{
 	  /* Otherwise, fetch the register cache and the masks.  */
 	  struct regcache *regs
diff --git a/gdb/amd-dbgapi-target.c b/gdb/amd-dbgapi-target.c
index 8e067b66bd8..e68b953888b 100644
--- a/gdb/amd-dbgapi-target.c
+++ b/gdb/amd-dbgapi-target.c
@@ -907,7 +907,7 @@ amd_dbgapi_target::stop (ptid_t ptid)
     /* Use the threads_safe iterator since stop_one_thread may delete the
        thread if it has exited.  */
     for (auto *thread : inf->threads_safe ())
-      if (thread->state != THREAD_EXITED && thread->ptid.matches (ptid)
+      if (thread->state () != THREAD_EXITED && thread->ptid.matches (ptid)
 	  && ptid_is_gpu (thread->ptid))
 	stop_one_thread (thread);
 }
@@ -1130,8 +1130,8 @@ add_gpu_thread (inferior *inf, ptid_t wave_ptid)
   /* Create new GPU threads silently to avoid spamming the terminal
      with thousands of "[New Thread ...]" messages.  */
   thread_info *thread = add_thread_silent (proc_target, wave_ptid);
-  set_running (proc_target, wave_ptid, true);
-  set_executing (proc_target, wave_ptid, true);
+  set_state (proc_target, wave_ptid, THREAD_RUNNING);
+  set_internal_state (proc_target, wave_ptid, THREAD_INT_RUNNING);
   return thread;
 }
 
@@ -1871,7 +1871,7 @@ amd_dbgapi_target::update_thread_list ()
 	 which does not have a corresponding wave_id represents a wave which
 	 is gone at this point and should be deleted.  */
       for (thread_info *tp : inf->threads_safe ())
-	if (ptid_is_gpu (tp->ptid) && tp->state != THREAD_EXITED)
+	if (ptid_is_gpu (tp->ptid) && tp->state () != THREAD_EXITED)
 	  {
 	    auto it = threads.find (tp->ptid.tid ());
 
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index f44ac457b22..847bf059364 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -617,9 +617,9 @@ breakpoints_should_be_inserted_now (void)
 	  return 1;
 
       /* Don't remove breakpoints yet if, even though all threads are
-	 stopped, we still have events to process.  */
+	 stopped, some still have pending events to process.  */
       for (thread_info *tp : all_non_exited_threads ())
-	if (tp->resumed () && tp->has_pending_waitstatus ())
+	if (tp->internal_state () == THREAD_INT_RESUMED_PENDING_STATUS)
 	  return 1;
     }
   return 0;
@@ -2041,7 +2041,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 ()->internal_state () != THREAD_INT_RUNNING)));
 }
 
 /* Set watchpoint B to disp_del_at_next_stop, even including its possible
@@ -4982,7 +4982,8 @@ get_bpstat_thread ()
     return NULL;
 
   thread_info *tp = inferior_thread ();
-  if (tp->state == THREAD_EXITED || tp->executing ())
+  if (tp->internal_state () == THREAD_INT_EXITED
+      || tp->internal_state () == THREAD_INT_RUNNING)
     return NULL;
   return tp;
 }
diff --git a/gdb/bsd-uthread.c b/gdb/bsd-uthread.c
index 341aea98fb7..3b8ee0fa04a 100644
--- a/gdb/bsd-uthread.c
+++ b/gdb/bsd-uthread.c
@@ -417,7 +417,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 = beneath->find_thread (ptid);
-  if (thread == NULL || thread->state == THREAD_EXITED)
+  if (thread == NULL || thread->state () == THREAD_EXITED)
     add_thread (beneath, ptid);
 
   return ptid;
@@ -468,7 +468,7 @@ bsd_uthread_target::update_thread_list ()
       process_stratum_target *proc_target
 	= as_process_stratum_target (this->beneath ());
       thread_info *thread = proc_target->find_thread (ptid);
-      if (thread == nullptr || thread->state == THREAD_EXITED)
+      if (thread == nullptr || thread->state () == THREAD_EXITED)
 	{
 	  /* If INFERIOR_PTID doesn't have a tid member yet, then ptid
 	     is still the initial thread of the process.  Notify GDB
diff --git a/gdb/fork-child.c b/gdb/fork-child.c
index 8abfbda2b78..0913435fb80 100644
--- a/gdb/fork-child.c
+++ b/gdb/fork-child.c
@@ -130,8 +130,8 @@ gdb_startup_inferior (pid_t pid, int num_traps)
 
   ptid_t ptid = startup_inferior (proc_target, pid, num_traps, NULL, NULL);
 
-  /* Mark all threads non-executing.  */
-  set_executing (proc_target, ptid, false);
+  /* Mark all threads internally stopped.  */
+  set_internal_state (proc_target, ptid, THREAD_INT_STOPPED);
 
   return ptid;
 }
diff --git a/gdb/frame.c b/gdb/frame.c
index fe5336f2401..59e72ec37d8 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -1873,11 +1873,11 @@ has_stack_frames ()
 
       thread_info *tp = inferior_thread ();
       /* Don't try to read from a dead thread.  */
-      if (tp->state == THREAD_EXITED)
+      if (tp->internal_state () == THREAD_INT_EXITED)
 	return false;
 
       /* ... or from a spinning thread.  */
-      if (tp->executing ())
+      if (tp->internal_state () == THREAD_INT_RUNNING)
 	return false;
     }
 
diff --git a/gdb/gcore.c b/gdb/gcore.c
index fa15d06796b..b9ed7991efb 100644
--- a/gdb/gcore.c
+++ b/gdb/gcore.c
@@ -846,7 +846,7 @@ thread_info *
 gcore_find_signalled_thread ()
 {
   thread_info *curr_thr = inferior_thread ();
-  if (curr_thr->state != THREAD_EXITED
+  if (curr_thr->state () != THREAD_EXITED
       && curr_thr->stop_signal () != GDB_SIGNAL_0)
     return curr_thr;
 
@@ -855,7 +855,7 @@ gcore_find_signalled_thread ()
       return thr;
 
   /* Default to the current thread, unless it has exited.  */
-  if (curr_thr->state != THREAD_EXITED)
+  if (curr_thr->state () != THREAD_EXITED)
     return curr_thr;
 
   return nullptr;
diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index a8fd967c702..344c808e9cb 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -51,8 +51,8 @@ extern bool debug_threads;
 #define threads_debug_printf(fmt, ...) \
   debug_prefixed_printf_cond (debug_threads, "threads", fmt, ##__VA_ARGS__)
 
-/* Frontend view of the thread state.  Possible extensions: stepping,
-   finishing, until(ling),...
+/* User/frontend view of the thread state.  Possible extensions:
+   stepping, finishing, until(ling),...
 
    NOTE: Since the thread state is not a boolean, most times, you do
    not want to check it with negation.  If you really want to check if
@@ -81,6 +81,34 @@ enum thread_state
   THREAD_EXITED,
 };
 
+/* Internal view of the thread's running state.  When a thread is
+   running from the user's perspective, it will still occasionally
+   stop, due to breakpoint hits, single-stepping, etc.  Often those
+   stops are not meant to be user-visible.  In such situations, the
+   user state will be THREAD_RUNNING, while the internal state
+   transitions between stopped, running, etc.  */
+
+enum thread_int_state
+{
+  /* The thread is stopped.  If the thread has a pending wait status,
+     we should not process it until we try to let the thread run, in
+     which case we switch the thread to
+     THREAD_INT_RESUMED_PENDING_STATUS state.  */
+  THREAD_INT_STOPPED,
+
+  /* The thread is running.  */
+  THREAD_INT_RUNNING,
+
+  /* infrun wants the thread to be resumed, but didn't set it running
+     yet, because the thread has a pending wait status to process.  We
+     shouldn't let the thread really run until that wait status has
+     been processed.  */
+  THREAD_INT_RESUMED_PENDING_STATUS,
+
+  /* The thread is listed, but known to have exited.  */
+  THREAD_INT_EXITED,
+};
+
 /* STEP_OVER_ALL means step over all subroutine calls.
    STEP_OVER_UNDEBUGGABLE means step over calls to undebuggable functions.
    STEP_OVER_NONE means don't step over any subroutine calls.  */
@@ -218,10 +246,10 @@ struct thread_suspend_state
        last stopped, a pending breakpoint waitstatus is discarded.
 
      - If the thread is running, then this field has its value removed by
-       calling stop_pc.reset() (see thread_info::set_executing()).
+       calling stop_pc.reset() (see thread_info::set_internal_state()).
        Attempting to read a std::optional with no value is undefined
        behavior and will trigger an assertion error when _GLIBCXX_DEBUG is
-       defined, which should make error easier to track down.  */
+       defined, which should make errors easier to track down.  */
   std::optional<CORE_ADDR> stop_pc;
 };
 
@@ -263,8 +291,23 @@ class thread_info : public intrusive_list_node<thread_info>,
 
   bool deletable () const;
 
-  /* Mark this thread as running and notify observers.  */
-  void set_running (bool running);
+  /* Get the thread's (user-visible) state.  */
+  thread_state state () const { return m_state; }
+
+  /* Set this thread's (user-visible) state.  If the thread is set
+     running, notify observers.  */
+  void set_state (thread_state state) { set_state (state, false); }
+
+  /* Get the thread's internal state.  */
+  thread_int_state internal_state () const { return m_internal_state; }
+
+  /* Set the thread's internal state from STATE.  If the state
+     switches to THREAD_INT_RUNNING, also clears the thread's stop_pc.
+     The thread may also be added to (when switching to
+     THREAD_INT_RESUMED_PENDING_STATUS), or removed from (when
+     switching from THREAD_INT_RESUMED_PENDING_STATUS), the list of
+     threads with a pending wait status.  */
+  void set_internal_state (thread_int_state state);
 
   ptid_t ptid;			/* "Actual process id";
 				    In fact, this may be overloaded with 
@@ -326,28 +369,6 @@ class thread_info : public intrusive_list_node<thread_info>,
     m_name = std::move (name);
   }
 
-  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/
-     THREAD_STOPPED states are different from EXECUTING.  When the
-     thread is stopped internally while handling an internal event,
-     like a software single-step breakpoint, EXECUTING will be false,
-     but STATE will still be THREAD_RUNNING.  */
-  enum thread_state state = THREAD_STOPPED;
-
   /* State of GDB control of inferior thread execution.
      See `struct thread_control_state'.  */
   thread_control_state control;
@@ -573,20 +594,22 @@ class thread_info : public intrusive_list_node<thread_info>,
   displaced_step_thread_state displaced_step_state;
 
 private:
-  /* True if this thread is resumed from infrun's perspective.
-     Note that a thread can be marked both as not-executing and
-     resumed at the same time.  This happens if we try to resume a
-     thread that has a wait status pending.  We shouldn't let the
-     thread really run until that wait status has been processed, but
-     we should not process that wait status if we didn't try to let
-     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;
+  /* Set this thread's (user-visible) state.  If the thread is set
+     running, notify observers, unless SUPPRESS_NOTIFICATION is true.
+     Returns the thread's previous state.  */
+  thread_state set_state (thread_state state, bool suppress_notification);
+  friend void set_state (process_stratum_target *targ,
+			 ptid_t ptid,
+			 thread_state state);
+  friend void finish_thread_state (process_stratum_target *targ,
+				   ptid_t ptid);
+
+  /* User view of the thread's stopped/running/exited state.  */
+  enum thread_state m_state = THREAD_STOPPED;
+
+  /* The thread's internal state.  See definition of
+     thread_int_state.  */
+  enum thread_int_state m_internal_state = THREAD_INT_STOPPED;
 
   /* State of inferior thread to restore after GDB is done with an inferior
      call.  See `struct thread_suspend_state'.  */
@@ -815,17 +838,15 @@ extern void switch_to_no_thread ();
 /* Switch from one thread to another.  Does not read registers.  */
 extern void switch_to_thread_no_regs (struct thread_info *thread);
 
-/* Marks or clears thread(s) PTID of TARG as resumed.  If PTID is
-   MINUS_ONE_PTID, applies to all threads of TARG.  If
-   ptid_is_pid(PTID) is true, applies to all threads of the process
-   pointed at by {TARG,PTID}.  */
-extern void set_resumed (process_stratum_target *targ,
-			 ptid_t ptid, bool resumed);
+/* Marks thread PTID of TARG with user state STATE.  If PTID is
+   minus_one_ptid, marks all threads of TARG.  */
+extern void set_state (process_stratum_target *targ,
+		       ptid_t ptid, thread_state state);
 
-/* Marks thread PTID of TARG as running, or as stopped.  If PTID is
+/* Marks thread PTID of TARG with internal state STATE.  If PTID is
    minus_one_ptid, marks all threads of TARG.  */
-extern void set_running (process_stratum_target *targ,
-			 ptid_t ptid, bool running);
+extern void set_internal_state (process_stratum_target *targ,
+				ptid_t ptid, thread_int_state state);
 
 /* Marks or clears thread(s) PTID of TARG as having been requested to
    stop.  If PTID is MINUS_ONE_PTID, applies to all threads of TARG.
@@ -835,25 +856,19 @@ extern void set_running (process_stratum_target *targ,
 extern void set_stop_requested (process_stratum_target *targ,
 				ptid_t ptid, bool stop);
 
-/* Marks thread PTID of TARG as executing, or not.  If PTID is
-   minus_one_ptid, marks all threads of TARG.
-
-   Note that this is different from the running state.  See the
-   description of state and executing fields of struct
-   thread_info.  */
-extern void set_executing (process_stratum_target *targ,
-			   ptid_t ptid, bool executing);
-
 /* True if any (known or unknown) thread of TARG is or may be
    executing.  */
 extern bool threads_are_executing (process_stratum_target *targ);
 
-/* Merge the executing property of thread PTID of TARG over to its
-   thread state property (frontend running/stopped view).
+/* Propagate the internal thread state of thread PTID of TARG over to
+   its (user) thread state.
 
-   "not executing" -> "stopped"
-   "executing"     -> "running"
-   "exited"        -> "exited"
+     user    <- internal
+    -------     ------------------------
+    stopped  <- stopped
+    running  <- running
+    running  <- continued-pending-status
+    exited   <- exited
 
    If PTID is minus_one_ptid, go over all threads of TARG.
 
@@ -1074,5 +1089,6 @@ extern void thread_try_catch_cmd (thread_info *thr,
 /* Return a string representation of STATE.  */
 
 extern const char *thread_state_string (enum thread_state state);
+extern const char *thread_int_state_string (enum thread_int_state state);
 
 #endif /* GDB_GDBTHREAD_H */
diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c
index 23788b44e92..a37eb132f47 100644
--- a/gdb/i386-tdep.c
+++ b/gdb/i386-tdep.c
@@ -4811,8 +4811,8 @@ i386_record_vex (struct i386_record_s *ir, uint8_t vex_w, uint8_t vex_r,
   /* Since we are reading pseudo registers, we need to tell GDB that it is
      safe to do so, by saying we aren't _really_ running the inferior right
      now.  */
-  SCOPE_EXIT { inferior_thread ()->set_executing (true); };
-  inferior_thread () -> set_executing (false);
+  SCOPE_EXIT { inferior_thread ()->set_internal_state (THREAD_INT_RUNNING); };
+  inferior_thread ()->set_internal_state (THREAD_INT_STOPPED);
 
   switch (opcode)
     {
diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c
index efa269cbe23..d39f2e5b015 100644
--- a/gdb/inf-ptrace.c
+++ b/gdb/inf-ptrace.c
@@ -175,7 +175,7 @@ inf_ptrace_target::attach (const char *args, int from_tty)
 
   /* Don't consider the thread stopped until we've processed its
      initial SIGSTOP stop.  */
-  set_executing (this, thr->ptid, true);
+  set_internal_state (this, thr->ptid, THREAD_INT_RUNNING);
 
   unpusher.release ();
 }
diff --git a/gdb/infcall.c b/gdb/infcall.c
index 098072dfd2a..697bbbacc5a 100644
--- a/gdb/infcall.c
+++ b/gdb/infcall.c
@@ -797,7 +797,7 @@ run_inferior_call (std::unique_ptr<call_thread_fsm> sm,
 
   struct gdb_exception caught_error;
   ptid_t call_thread_ptid = call_thread->ptid;
-  int was_running = call_thread->state == THREAD_RUNNING;
+  int was_running = call_thread->state () == THREAD_RUNNING;
   *timed_out_p = false;
 
   infcall_debug_printf ("call function at %s in thread %s, was_running = %d",
@@ -928,7 +928,7 @@ run_inferior_call (std::unique_ptr<call_thread_fsm> sm,
      of error out of resume()), then we wouldn't need this.  */
   if (caught_error.reason < 0)
     {
-      if (call_thread->state != THREAD_EXITED)
+      if (call_thread->state () != THREAD_EXITED)
 	breakpoint_auto_delete (call_thread->control.stop_bpstat);
     }
 
@@ -1565,7 +1565,7 @@ call_function_by_hand_dummy (struct value *function,
       infcall_debug_printf ("after inferior call, exception (%d): %s",
 			    e.reason, e.what ());
     infcall_debug_printf ("after inferior call, thread state is: %s",
-			  thread_state_string (call_thread->state));
+			  thread_state_string (call_thread->state ()));
 
     gdb::observers::inferior_call_post.notify (call_thread_ptid, funaddr);
 
@@ -1576,7 +1576,7 @@ call_function_by_hand_dummy (struct value *function,
        threads appear after GDB has reported a stop.  */
     update_thread_list ();
 
-    if (call_thread->state != THREAD_EXITED)
+    if (call_thread->state () != THREAD_EXITED)
       {
 	/* The FSM should still be the same.  */
 	gdb_assert (call_thread->thread_fsm () == sm);
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index e9b58ce5521..6c07e07619c 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -537,12 +537,12 @@ proceed_thread_callback (struct thread_info *thread)
      into a single target `resume_all' request, because some threads
      may be stopped in internal breakpoints/events, or stopped waiting
      for its turn in the displaced stepping queue (that is, they are
-     running && !executing).  The target side has no idea about why
-     the thread is stopped, so a `resume_all' command would resume too
-     much.  If/when GDB gains a way to tell the target `hold this
-     thread stopped until I say otherwise', then we can optimize
-     this.  */
-  if (thread->state != THREAD_STOPPED)
+     running from the user's perspective but internally stopped).  The
+     target side has no idea about why the thread is stopped, so a
+     `resume_all' command would resume too much.  If/when GDB gains a
+     way to tell the target `hold this thread stopped until I say
+     otherwise', then we can optimize this.  */
+  if (thread->state () != THREAD_STOPPED)
     return false;
 
   if (!thread->inf->has_execution ())
@@ -558,7 +558,7 @@ static void
 ensure_valid_thread (void)
 {
   if (inferior_ptid == null_ptid
-      || inferior_thread ()->state == THREAD_EXITED)
+      || inferior_thread ()->state () == THREAD_EXITED)
     error (_("Cannot execute this command without a live selected thread."));
 }
 
@@ -587,7 +587,7 @@ error_is_running (void)
 static void
 ensure_not_running (void)
 {
-  if (inferior_thread ()->state == THREAD_RUNNING)
+  if (inferior_thread ()->state () == THREAD_RUNNING)
     error_is_running ();
 }
 
@@ -945,7 +945,8 @@ prepare_one_step (thread_info *tp, struct step_command_fsm *sm)
 
 	      /* Pretend that we've ran.  */
 	      resume_ptid = user_visible_resume_ptid (1);
-	      set_running (tp->inf->process_target (), resume_ptid, true);
+	      set_state (tp->inf->process_target (), resume_ptid,
+			 THREAD_RUNNING);
 
 	      step_into_inline_frame (tp);
 
@@ -1921,12 +1922,12 @@ info_program_command (const char *args, int from_tty)
 		  print_thread_id (tp),
 		  target_pid_to_str (tp->ptid).c_str ());
 
-      if (tp->state == THREAD_EXITED)
+      if (tp->state () == THREAD_EXITED)
 	{
 	  gdb_printf (_("Selected thread has exited.\n"));
 	  return;
 	}
-      else if (tp->state == THREAD_RUNNING)
+      else if (tp->state () == THREAD_RUNNING)
 	{
 	  gdb_printf (_("Selected thread is running.\n"));
 	  return;
@@ -1948,13 +1949,13 @@ info_program_command (const char *args, int from_tty)
 		  print_thread_id (tp),
 		  target_pid_to_str (tp->ptid).c_str ());
 
-      if (tp->state == THREAD_EXITED)
+      if (tp->state () == THREAD_EXITED)
 	{
 	  gdb_printf (_("Thread has since exited.\n"));
 	  return;
 	}
 
-      if (tp->state == THREAD_RUNNING)
+      if (tp->state () == THREAD_RUNNING)
 	{
 	  gdb_printf (_("Thread is now running.\n"));
 	  return;
@@ -2473,7 +2474,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->internal_state () != THREAD_INT_RUNNING
 	&& !thread->stop_requested
 	&& thread->stop_signal () == GDB_SIGNAL_0)
       {
@@ -2628,6 +2629,10 @@ attach_command (const char *args, int from_tty)
      this function should probably be moved into target_pre_inferior.  */
   target_pre_inferior ();
 
+  /* Set up execution context to know that we should return from
+     wait_for_inferior as soon as the target reports a stop.  */
+  init_wait_for_inferior ();
+
   gdb::unique_xmalloc_ptr<char> stripped = strip_bg_char (args, &async_exec);
   args = stripped.get ();
 
@@ -2670,10 +2675,6 @@ attach_command (const char *args, int from_tty)
        finished.  */
   target_terminal::inferior ();
 
-  /* Set up execution context to know that we should return from
-     wait_for_inferior as soon as the target reports a stop.  */
-  init_wait_for_inferior ();
-
   inferior->needs_setup = true;
 
   if (target_is_non_stop_p ())
@@ -2753,7 +2754,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->internal_state () == THREAD_INT_RUNNING)
     {
       struct inferior *inferior = current_inferior ();
 
diff --git a/gdb/inferior.h b/gdb/inferior.h
index 54f5229b420..301a78f9ebb 100644
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
@@ -201,8 +201,8 @@ extern void child_interrupt (struct target_ops *self);
 /* From fork-child.c */
 
 /* Helper function to call STARTUP_INFERIOR with PID and NUM_TRAPS.
-   This function already calls set_executing.  Return the ptid_t from
-   STARTUP_INFERIOR.  */
+   This function already sets the threads' internal state to
+   THREAD_STOPPED.  Return the ptid_t from STARTUP_INFERIOR.  */
 extern ptid_t gdb_startup_inferior (pid_t pid, int num_traps);
 
 /* From infcmd.c */
diff --git a/gdb/inflow.c b/gdb/inflow.c
index f5ae6cd982f..aef3c8c7081 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->internal_state () == THREAD_INT_RUNNING)
 	{
 	  resumed = thr;
 	  break;
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 9f625a7bd44..20649ace942 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -991,14 +991,14 @@ follow_inferior_reset_breakpoints (void)
   insert_breakpoints ();
 }
 
-/* The child has exited or execed: resume THREAD, a thread of the parent,
-   if it was meant to be executing.  */
+/* The child has exited or execed: resume THREAD, a thread of the
+   parent, if it was meant to be running.  */
 
 static void
 proceed_after_vfork_done (thread_info *thread)
 {
-  if (thread->state == THREAD_RUNNING
-      && !thread->executing ()
+  if (thread->state () == THREAD_RUNNING
+      && thread->internal_state () != THREAD_INT_RUNNING
       && !thread->stop_requested
       && thread->stop_signal () == GDB_SIGNAL_0)
     {
@@ -2227,15 +2227,14 @@ start_step_over (void)
 	}
 
       if (tp->control.trap_expected
-	  || tp->resumed ()
-	  || tp->executing ())
+	  || tp->internal_state () == THREAD_INT_RESUMED_PENDING_STATUS
+	  || tp->internal_state () == THREAD_INT_RUNNING)
 	{
 	  internal_error ("[%s] has inconsistent state: "
-			  "trap_expected=%d, resumed=%d, executing=%d\n",
+			  "trap_expected=%d, internal_state=%s\n",
 			  tp->ptid.to_string ().c_str (),
 			  tp->control.trap_expected,
-			  tp->resumed (),
-			  tp->executing ());
+			  thread_int_state_string (tp->internal_state ()));
 	}
 
       infrun_debug_printf ("resuming [%s] for step-over",
@@ -2259,7 +2258,7 @@ start_step_over (void)
 
       /* If the thread's step over could not be initiated because no buffers
 	 were available, it was re-added to the global step over chain.  */
-      if (tp->resumed  ())
+      if (tp->internal_state () != THREAD_INT_STOPPED)
 	{
 	  infrun_debug_printf ("[%s] was resumed.",
 			       tp->ptid.to_string ().c_str ());
@@ -2659,7 +2658,7 @@ resume_1 (enum gdb_signal sig)
 	 tp->control.currently_stepping);
 
       tp->inf->process_target ()->threads_executing = true;
-      tp->set_resumed (true);
+      tp->set_internal_state (THREAD_INT_RESUMED_PENDING_STATUS);
 
       /* FIXME: What should we do if we are supposed to resume this
 	 thread with a signal?  Maybe we should maintain a queue of
@@ -2784,7 +2783,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;
 	    }
 	}
@@ -2976,7 +2974,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
@@ -3040,6 +3037,7 @@ static void
 clear_proceed_status_thread (struct thread_info *tp)
 {
   infrun_debug_printf ("%s", tp->ptid.to_string ().c_str ());
+  gdb_assert (tp->internal_state () != THREAD_INT_RUNNING);
 
   /* If we're starting a new sequence, then the previous finished
      single-step is no longer relevant.  */
@@ -3051,6 +3049,7 @@ clear_proceed_status_thread (struct thread_info *tp)
 			       "Discarding.",
 			       tp->ptid.to_string ().c_str ());
 
+	  tp->set_internal_state (THREAD_INT_STOPPED);
 	  tp->clear_pending_waitstatus ();
 	  tp->set_stop_reason (TARGET_STOPPED_BY_NO_REASON);
 	}
@@ -3125,7 +3124,8 @@ clear_proceed_status (int step)
       /* In all-stop mode, delete the per-thread status of all threads
 	 we're about to resume, implicitly and explicitly.  */
       for (thread_info *tp : all_non_exited_threads (resume_target, resume_ptid))
-	clear_proceed_status_thread (tp);
+	if (tp->internal_state () != THREAD_INT_RUNNING)
+	  clear_proceed_status_thread (tp);
     }
 
   if (inferior_ptid != null_ptid)
@@ -3485,6 +3485,8 @@ check_multi_target_resumption (process_stratum_target *resume_target)
 static void
 proceed_resume_thread_checked (thread_info *tp)
 {
+  gdb_assert (tp->internal_state () != THREAD_INT_EXITED);
+
   if (!tp->inf->has_execution ())
     {
       infrun_debug_printf ("[%s] target has no execution",
@@ -3492,11 +3494,10 @@ proceed_resume_thread_checked (thread_info *tp)
       return;
     }
 
-  if (tp->resumed ())
+  if (tp->internal_state () != THREAD_INT_STOPPED)
     {
       infrun_debug_printf ("[%s] resumed",
 			   tp->ptid.to_string ().c_str ());
-      gdb_assert (tp->executing () || tp->has_pending_waitstatus ());
       return;
     }
 
@@ -3672,7 +3673,7 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
      inferior function, as in that case we pretend the inferior
      doesn't run at all.  */
   if (!cur_thr->control.in_infcall)
-    set_running (resume_target, resume_ptid, true);
+    set_state (resume_target, resume_ptid, THREAD_RUNNING);
 
   infrun_debug_printf ("addr=%s, signal=%s, resume_ptid=%s",
 		       paddress (gdbarch, addr),
@@ -3873,9 +3874,9 @@ infrun_thread_stop_requested (ptid_t ptid)
      for reporting the stop now.  */
   for (thread_info *tp : all_threads (curr_target, ptid))
     {
-      if (tp->state != THREAD_RUNNING)
+      if (tp->state () != THREAD_RUNNING)
 	continue;
-      if (tp->executing ())
+      if (tp->internal_state () == THREAD_INT_RUNNING)
 	continue;
 
       /* Remove matching threads from the step-over queue, so
@@ -3906,10 +3907,10 @@ infrun_thread_stop_requested (ptid_t ptid)
       if (step_over_info_valid_p ())
 	continue;
 
-      /* Otherwise we can process the (new) pending event now.  Set
-	 it so this pending event is considered by
+      /* Otherwise we can process the (new) pending event now.  Switch
+	 state so this pending event is considered by
 	 do_target_wait.  */
-      tp->set_resumed (true);
+      tp->set_internal_state (THREAD_INT_RESUMED_PENDING_STATUS);
     }
 }
 
@@ -4015,7 +4016,7 @@ random_pending_event_thread (inferior *inf, ptid_t waiton_ptid)
     }
 
   infrun_debug_printf ("Found %s.", thread->ptid.to_string ().c_str ());
-  gdb_assert (thread->resumed ());
+  gdb_assert (thread->internal_state () == THREAD_INT_RESUMED_PENDING_STATUS);
   gdb_assert (thread->has_pending_waitstatus ());
 
   return thread;
@@ -4128,6 +4129,7 @@ do_target_wait_1 (inferior *inf, ptid_t ptid,
 
       tp->set_stop_reason (TARGET_STOPPED_BY_NO_REASON);
       *status = tp->pending_waitstatus ();
+      tp->set_internal_state (THREAD_INT_STOPPED);
       tp->clear_pending_waitstatus ();
 
       /* Wake up the event loop again, until all pending events are
@@ -4326,7 +4328,7 @@ prepare_for_detach (void)
 	{
 	  if (thr->displaced_step_state.in_progress ())
 	    {
-	      if (thr->executing ())
+	      if (thr->internal_state () == THREAD_INT_RUNNING)
 		{
 		  if (!thr->stop_requested)
 		    {
@@ -4334,8 +4336,6 @@ prepare_for_detach (void)
 		      thr->stop_requested = true;
 		    }
 		}
-	      else
-		thr->set_resumed (false);
 	    }
 	}
 
@@ -4474,7 +4474,7 @@ clean_up_just_stopped_threads_fsms (struct execution_control_state *ecs)
 
       for (thread_info *thr : all_threads_safe ())
 	{
-	  if (thr->state == THREAD_EXITED)
+	  if (thr->state () == THREAD_EXITED)
 	    continue;
 
 	  if (thr == ecs->event_thread)
@@ -4810,7 +4810,7 @@ fetch_inferior_event ()
   if (cmd_done
       && exec_done_display_p
       && (inferior_ptid == null_ptid
-	  || inferior_thread ()->state != THREAD_RUNNING))
+	  || inferior_thread ()->state () != THREAD_RUNNING))
     gdb_printf (_("completed.\n"));
 }
 
@@ -5373,14 +5373,14 @@ save_waitstatus (struct thread_info *tp, const target_waitstatus &ws)
     }
 }
 
-/* Mark the non-executing threads accordingly.  In all-stop, all
+/* Mark the internally stopped threads accordingly.  In all-stop, all
    threads of all processes are stopped when we get any event
    reported.  In non-stop mode, only the event thread stops.  */
 
 static void
-mark_non_executing_threads (process_stratum_target *target,
-			    ptid_t event_ptid,
-			    const target_waitstatus &ws)
+mark_internally_stopped_threads (process_stratum_target *target,
+				 ptid_t event_ptid,
+				 const target_waitstatus &ws)
 {
   ptid_t mark_ptid;
 
@@ -5400,18 +5400,15 @@ mark_non_executing_threads (process_stratum_target *target,
 	 target_mourn_inferior, by associating the same
 	 inferior/thread to another fork.  We haven't mourned yet at
 	 this point, but we must mark any threads left in the
-	 process as not-executing so that finish_thread_state marks
-	 them stopped (in the user's perspective) if/when we present
+	 process as internally stopped so that finish_thread_state marks
+	 them stopped in the user's perspective if/when we present
 	 the stop to the user.  */
       mark_ptid = ptid_t (event_ptid.pid ());
     }
   else
     mark_ptid = event_ptid;
 
-  set_executing (target, mark_ptid, false);
-
-  /* Likewise the resumed flag.  */
-  set_resumed (target, mark_ptid, false);
+  set_internal_state (target, mark_ptid, THREAD_INT_STOPPED);
 }
 
 /* Handle one event after stopping threads.  If the eventing thread
@@ -5477,11 +5474,11 @@ handle_one (const wait_one_event &event)
 
       if (t != nullptr)
 	{
-	  /* Set the threads as non-executing to avoid
-	     another stop attempt on them.  */
+	  /* Set the threads as internally stopped to avoid another
+	     stop attempt on them.  */
 	  switch_to_thread_no_regs (t);
-	  mark_non_executing_threads (event.target, event.ptid,
-				      event.ws);
+	  mark_internally_stopped_threads (event.target, event.ptid,
+					   event.ws);
 	  save_waitstatus (t, event.ws);
 	  t->stop_requested = false;
 
@@ -5503,8 +5500,7 @@ handle_one (const wait_one_event &event)
 	t = add_thread (event.target, event.ptid);
 
       t->stop_requested = false;
-      t->set_executing (false);
-      t->set_resumed (false);
+      t->set_internal_state (THREAD_INT_STOPPED);
       t->control.may_range_step = 0;
 
       /* This may be the first time we see the inferior report
@@ -5733,7 +5729,7 @@ stop_all_threads (const char *reason, inferior *inf)
 	      if (!target_is_non_stop_p ())
 		continue;
 
-	      if (t->executing ())
+	      if (t->internal_state () == THREAD_INT_RUNNING)
 		{
 		  /* If already stopping, don't request a stop again.
 		     We just haven't seen the notification yet.  */
@@ -5760,7 +5756,7 @@ stop_all_threads (const char *reason, inferior *inf)
 
 		  /* The thread may be not executing, but still be
 		     resumed with a pending status to process.  */
-		  t->set_resumed (false);
+		  t->set_internal_state (THREAD_INT_STOPPED);
 		}
 	    }
 
@@ -5876,7 +5872,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->internal_state () == THREAD_INT_RUNNING)
 	{
 	  if (thread->inf != curr_inf)
 	    {
@@ -5888,7 +5884,7 @@ handle_no_resumed (struct execution_control_state *ecs)
 	  swap_terminal = false;
 	}
 
-      if (!ignore_event && thread->resumed ())
+      if (!ignore_event && thread->internal_state () != THREAD_INT_STOPPED)
 	{
 	  /* Either there were no unwaited-for children left in the
 	     target at some point, but there are now, or some target
@@ -6160,7 +6156,7 @@ handle_inferior_event (struct execution_control_state *ecs)
 	}
     }
 
-  mark_non_executing_threads (ecs->target, ecs->ptid, ecs->ws);
+  mark_internally_stopped_threads (ecs->target, ecs->ptid, ecs->ws);
 
   switch (ecs->ws.kind ())
     {
@@ -6424,7 +6420,7 @@ handle_inferior_event (struct execution_control_state *ecs)
 	  /* If not resuming the parent, mark it stopped.  */
 	  if (ecs->ws.kind () != TARGET_WAITKIND_THREAD_CLONED
 	      && follow_child && !detach_fork && !non_stop && !sched_multi)
-	    parent->set_running (false);
+	    parent->set_state (THREAD_STOPPED);
 
 	  /* If resuming the child, mark it running.  */
 	  if ((ecs->ws.kind () == TARGET_WAITKIND_THREAD_CLONED
@@ -6432,7 +6428,7 @@ handle_inferior_event (struct execution_control_state *ecs)
 	      || (ecs->ws.kind () != TARGET_WAITKIND_THREAD_CLONED
 		  && (follow_child
 		      || (!detach_fork && (non_stop || sched_multi)))))
-	    child->set_running (true);
+	    child->set_state (THREAD_RUNNING);
 
 	  /* In non-stop mode, also resume the other branch.  */
 	  if ((ecs->ws.kind () == TARGET_WAITKIND_THREAD_CLONED
@@ -6624,18 +6620,17 @@ restart_threads (struct thread_info *event_thread, inferior *inf)
 	  continue;
 	}
 
-      if (!(tp->state == THREAD_RUNNING || tp->control.in_infcall))
+      if (!(tp->state () == THREAD_RUNNING || tp->control.in_infcall))
 	{
 	  infrun_debug_printf ("restart threads: [%s] not meant to be running",
 			       tp->ptid.to_string ().c_str ());
 	  continue;
 	}
 
-      if (tp->resumed ())
+      if (tp->internal_state () != THREAD_INT_STOPPED)
 	{
-	  infrun_debug_printf ("restart threads: [%s] resumed",
+	  infrun_debug_printf ("restart threads: [%s] already resumed",
 			      tp->ptid.to_string ().c_str ());
-	  gdb_assert (tp->executing () || tp->has_pending_waitstatus ());
 	  continue;
 	}
 
@@ -6643,7 +6638,6 @@ restart_threads (struct thread_info *event_thread, inferior *inf)
 	{
 	  infrun_debug_printf ("restart threads: [%s] needs step-over",
 			       tp->ptid.to_string ().c_str ());
-	  gdb_assert (!tp->resumed ());
 	  continue;
 	}
 
@@ -6652,7 +6646,7 @@ restart_threads (struct thread_info *event_thread, inferior *inf)
 	{
 	  infrun_debug_printf ("restart threads: [%s] has pending status",
 			       tp->ptid.to_string ().c_str ());
-	  tp->set_resumed (true);
+	  tp->set_internal_state (THREAD_INT_RESUMED_PENDING_STATUS);
 	  continue;
 	}
 
@@ -6691,7 +6685,7 @@ restart_threads (struct thread_info *event_thread, inferior *inf)
 static bool
 resumed_thread_with_pending_status (struct thread_info *tp)
 {
-  return tp->resumed () && tp->has_pending_waitstatus ();
+  return tp->internal_state () == THREAD_INT_RESUMED_PENDING_STATUS;
 }
 
 /* Called when we get an event that may finish an in-line or
@@ -6780,12 +6774,12 @@ 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
+	  /* The internal state was reset to stopped early, by
+	     handle_inferior_event.  Switch to resumed-pending-status
 	     so this pending event is considered by
 	     do_target_wait.  */
-	  tp->set_resumed (true);
-
-	  gdb_assert (!tp->executing ());
+	  gdb_assert (tp->internal_state () == THREAD_INT_STOPPED);
+	  tp->set_internal_state (THREAD_INT_RESUMED_PENDING_STATUS);
 
 	  regcache = get_thread_regcache (tp);
 	  tp->set_stop_pc (regcache_read_pc (regcache));
@@ -8437,7 +8431,7 @@ restart_stepped_thread (process_stratum_target *resume_target,
 
   for (thread_info *tp : all_threads_safe ())
     {
-      if (tp->state == THREAD_EXITED)
+      if (tp->state () == THREAD_EXITED)
 	continue;
 
       if (tp->has_pending_waitstatus ())
@@ -8461,7 +8455,7 @@ restart_stepped_thread (process_stratum_target *resume_target,
 
   for (thread_info *tp : all_threads_safe ())
     {
-      if (tp->state == THREAD_EXITED)
+      if (tp->state () == THREAD_EXITED)
 	continue;
 
       if (tp->has_pending_waitstatus ())
@@ -8496,26 +8490,27 @@ restart_after_all_stop_detach (process_stratum_target *proc_target)
      current inferior may no longer have a process_stratum target
      pushed, as we just detached.  */
 
-  /* See if we have a THREAD_RUNNING thread that need to be
-     re-resumed.  If we have any thread that is already executing,
-     then we don't need to resume the target -- it is already been
-     resumed.  With the remote target (in all-stop), it's even
-     impossible to issue another resumption if the target is already
-     resumed, until the target reports a stop.  */
+  /* See if we have a thread that is running from the user's
+     perspective that need to be re-resumed.  If we have any thread
+     that is already executing, then we don't need to resume the
+     target -- it is already been resumed.  With the remote target (in
+     all-stop), it's even impossible to issue another resumption if
+     the target is already resumed, until the target reports a
+     stop.  */
   for (thread_info *thr : all_threads (proc_target))
     {
-      if (thr->state != THREAD_RUNNING)
+      if (thr->state () != THREAD_RUNNING)
 	continue;
 
       /* 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->internal_state () == THREAD_INT_RUNNING)
 	return;
 
-      /* If we have a pending event to process, skip resuming the
+      /* If we have a pending status to process, skip resuming the
 	 target and go straight to processing it.  */
-      if (thr->resumed () && thr->has_pending_waitstatus ())
+      if (thr->internal_state () == THREAD_INT_RESUMED_PENDING_STATUS)
 	return;
     }
 
@@ -8528,7 +8523,7 @@ restart_after_all_stop_detach (process_stratum_target *proc_target)
      it.  */
   for (thread_info *thr : all_threads (proc_target))
     {
-      if (thr->state != THREAD_RUNNING)
+      if (thr->state () != THREAD_RUNNING)
 	continue;
 
       execution_control_state ecs (thr);
@@ -8565,7 +8560,7 @@ keep_going_stepped_thread (struct thread_info *tp)
        stepping thread is still alive.  For that reason, we need to
        synchronously query the target now.  */
 
-  if (tp->state == THREAD_EXITED || !target_thread_alive (tp->ptid))
+  if (tp->state () == THREAD_EXITED || !target_thread_alive (tp->ptid))
     {
       infrun_debug_printf ("not resuming previously stepped thread, it has "
 			   "vanished");
@@ -8618,7 +8613,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);
     }
@@ -9027,7 +9021,7 @@ static void
 keep_going_pass_signal (struct execution_control_state *ecs)
 {
   gdb_assert (ecs->event_thread->ptid == inferior_ptid);
-  gdb_assert (!ecs->event_thread->resumed ());
+  gdb_assert (ecs->event_thread->internal_state () == THREAD_INT_STOPPED);
 
   /* Save the pc before execution, to compare with pc after stop.  */
   ecs->event_thread->prev_pc
@@ -9495,7 +9489,7 @@ stop_context::changed () const
     return true;
   if (inf_num != current_inferior ()->num)
     return true;
-  if (thread != nullptr && thread->state != THREAD_STOPPED)
+  if (thread != nullptr && thread->state () != THREAD_STOPPED)
     return true;
   if (get_stop_id () != stop_id)
     return true;
diff --git a/gdb/infrun.h b/gdb/infrun.h
index b9b64aca45a..b09e7c1df8a 100644
--- a/gdb/infrun.h
+++ b/gdb/infrun.h
@@ -66,12 +66,11 @@ infrun_debug_show_threads (const char *title, ThreadRange threads)
 
       infrun_debug_printf ("%s:", title);
       for (thread_info *thread : threads)
-	infrun_debug_printf ("  thread %s, executing = %d, resumed = %d, "
+	infrun_debug_printf ("  thread %s, internal_state = %s, "
 			     "state = %s",
 			     thread->ptid.to_string ().c_str (),
-			     thread->executing (),
-			     thread->resumed (),
-			     thread_state_string (thread->state));
+			     thread_int_state_string (thread->internal_state ()),
+			     thread_state_string (thread->state ()));
     }
 }
 
diff --git a/gdb/linux-fork.c b/gdb/linux-fork.c
index 338ba032a0e..377c68ae6b9 100644
--- a/gdb/linux-fork.c
+++ b/gdb/linux-fork.c
@@ -363,8 +363,7 @@ fork_load_infrun_state (struct fork_info *fp)
 
   inferior_thread ()->set_stop_pc
     (regcache_read_pc (get_thread_regcache (inferior_thread ())));
-  inferior_thread ()->set_executing (false);
-  inferior_thread ()->set_resumed (false);
+  inferior_thread ()->set_internal_state (THREAD_INT_STOPPED);
   nullify_last_target_wait_ptid ();
 
   /* Now restore the file positions of open file descriptors.  */
@@ -726,7 +725,7 @@ delete_checkpoint_command (const char *args, int from_tty)
      ptid.  */
   thread_info *parent = linux_target->find_thread (pptid);
   if ((parent == NULL && find_fork_ptid (pptid).first != nullptr)
-      || (parent != NULL && parent->state == THREAD_STOPPED))
+      || (parent != NULL && parent->state () == THREAD_STOPPED))
     {
       if (inferior_call_waitpid (pptid, ptid.pid ()))
 	warning (_("Unable to wait pid %s"),
@@ -866,7 +865,7 @@ print_checkpoints (struct ui_out *uiout, inferior *req_inf, fork_info *req_fi)
 	  uiout->field_string
 	    ("target-id", target_pid_to_str (proc_ptid (fi.ptid)).c_str ());
 
-	  if (t->state == THREAD_RUNNING && is_current)
+	  if (t->state () == THREAD_RUNNING && is_current)
 	    uiout->text ("(running)");
 	  else
 	    {
@@ -1108,7 +1107,7 @@ restart_command (const char *args, int from_tty)
   /* Don't allow switching from a thread/fork that's running.  */
   inferior *curinf = current_inferior ();
   if (curinf->pid != 0
-      && any_thread_of_inferior (curinf)->state == THREAD_RUNNING)
+      && any_thread_of_inferior (curinf)->state () == THREAD_RUNNING)
     error (_("Cannot execute this command while "
 	     "the selected thread is running."));
 
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index 2f98060506b..4de4cc83cfa 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -1246,8 +1246,8 @@ linux_nat_target::attach (const char *args, int from_tty)
 		       if (lwp->ptid.pid () != lwp->ptid.lwp ())
 			 {
 			   add_thread (linux_target, lwp->ptid);
-			   set_running (linux_target, lwp->ptid, true);
-			   set_executing (linux_target, lwp->ptid, true);
+			   set_state (linux_target, lwp->ptid, THREAD_RUNNING);
+			   set_internal_state (linux_target, lwp->ptid, THREAD_INT_RUNNING);
 			 }
 		       return 0;
 		     });
@@ -1331,7 +1331,8 @@ get_detach_signal (struct lwp_info *lp)
     {
       thread_info *tp = linux_target->find_thread (lp->ptid);
 
-      if (target_is_non_stop_p () && !tp->executing ())
+      if (target_is_non_stop_p ()
+	  && tp->internal_state () != THREAD_INT_RUNNING)
 	{
 	  if (tp->has_pending_waitstatus ())
 	    {
diff --git a/gdb/linux-thread-db.c b/gdb/linux-thread-db.c
index f60116afb2c..7f8f9eeaa53 100644
--- a/gdb/linux-thread-db.c
+++ b/gdb/linux-thread-db.c
@@ -1361,7 +1361,7 @@ record_thread (struct thread_db_info *info,
   /* Add the thread to GDB's thread list.  If we already know about a
      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)
+  if (tp == NULL || tp->state () == THREAD_EXITED)
     tp = add_thread_with_info (info->process_target, ptid,
 			       private_thread_info_up (priv));
   else
@@ -1625,7 +1625,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->internal_state () == THREAD_INT_RUNNING)
 	continue;
 
       /* It's best to avoid td_ta_thr_iter if possible.  That walks
diff --git a/gdb/mi/mi-cmd-var.c b/gdb/mi/mi-cmd-var.c
index 9cbb85722b3..79c8b9979e2 100644
--- a/gdb/mi/mi-cmd-var.c
+++ b/gdb/mi/mi-cmd-var.c
@@ -608,14 +608,14 @@ mi_cmd_var_update_iter (struct varobj *var, bool only_floating,
   if (thread_id == -1)
     {
       thread_stopped = (inferior_ptid == null_ptid
-			|| inferior_thread ()->state == THREAD_STOPPED);
+			|| inferior_thread ()->state () == THREAD_STOPPED);
     }
   else
     {
       thread_info *tp = find_thread_global_id (thread_id);
 
       thread_stopped = (tp == NULL
-			|| tp->state == THREAD_STOPPED);
+			|| tp->state () == THREAD_STOPPED);
     }
 
   if (thread_stopped
diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c
index ae1070eb188..0465d6e9fc0 100644
--- a/gdb/mi/mi-interp.c
+++ b/gdb/mi/mi-interp.c
@@ -868,7 +868,7 @@ mi_interp::on_user_selected_context_changed (user_selected_what selection)
       gdb_printf (this->event_channel, "thread-selected,id=\"%d\"",
 		  tp->global_num);
 
-      if (tp->state != THREAD_RUNNING)
+      if (tp->state () != THREAD_RUNNING)
 	{
 	  if (has_stack_frames ())
 	    print_stack_frame_to_uiout (mi_uiout, get_selected_frame (NULL),
diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c
index cda72ca4f5b..cfb6fcf0772 100644
--- a/gdb/mi/mi-main.c
+++ b/gdb/mi/mi-main.c
@@ -239,7 +239,7 @@ mi_cmd_exec_jump (const char *args, const char *const *argv, int argc)
 static void
 proceed_thread (struct thread_info *thread, int pid)
 {
-  if (thread->state != THREAD_STOPPED)
+  if (thread->state () != THREAD_STOPPED)
     return;
 
   if (pid != 0 && thread->ptid.pid () != pid)
@@ -367,7 +367,7 @@ mi_cmd_exec_interrupt (const char *command, const char *const *argv, int argc)
 
       iterate_over_threads ([&] (struct thread_info *thread)
 	{
-	  if (thread->state != THREAD_RUNNING)
+	  if (thread->state () != THREAD_RUNNING)
 	    return false;
 
 	  if (thread->ptid.pid () != inf->pid)
@@ -508,7 +508,7 @@ mi_cmd_target_detach (const char *command, const char *const *argv, int argc)
 	 target_detach detaches from the parent of inferior_ptid.  */
       tp = iterate_over_threads ([&] (struct thread_info *ti)
 	{
-	  return ti->ptid.pid () == pid && ti->state != THREAD_EXITED;
+	  return ti->ptid.pid () == pid && ti->state () != THREAD_EXITED;
 	});
       if (!tp)
 	error (_("Thread group is empty"));
@@ -2059,7 +2059,7 @@ mi_cmd_execute (struct mi_parse *parse)
       if (tp == NULL)
 	error (_("Invalid thread id: %d"), parse->thread);
 
-      if (tp->state == THREAD_EXITED)
+      if (tp->state () == THREAD_EXITED)
 	error (_("Thread id: %d has terminated"), parse->thread);
 
       if (parse->cmd->preserve_user_selected_context ())
diff --git a/gdb/process-stratum-target.c b/gdb/process-stratum-target.c
index 329589dc34b..039dac4c0fe 100644
--- a/gdb/process-stratum-target.c
+++ b/gdb/process-stratum-target.c
@@ -114,8 +114,9 @@ process_stratum_target::maybe_add_resumed_with_pending_wait_status
 {
   gdb_assert (!thread->resumed_with_pending_wait_status_node.is_linked ());
 
-  if (thread->resumed () && thread->has_pending_waitstatus ())
+  if (thread->internal_state () == THREAD_INT_RESUMED_PENDING_STATUS)
     {
+      gdb_assert (thread->has_pending_waitstatus ());
       infrun_debug_printf ("adding to resumed threads with event list: %s",
 			   thread->ptid.to_string ().c_str ());
       m_resumed_with_pending_wait_status.push_back (*thread);
@@ -128,8 +129,9 @@ void
 process_stratum_target::maybe_remove_resumed_with_pending_wait_status
   (thread_info *thread)
 {
-  if (thread->resumed () && thread->has_pending_waitstatus ())
+  if (thread->internal_state () == THREAD_INT_RESUMED_PENDING_STATUS)
     {
+      gdb_assert (thread->has_pending_waitstatus ());
       infrun_debug_printf ("removing from resumed threads with event list: %s",
 			   thread->ptid.to_string ().c_str ());
       gdb_assert (thread->resumed_with_pending_wait_status_node.is_linked ());
diff --git a/gdb/python/py-infthread.c b/gdb/python/py-infthread.c
index 4f1f8d47e32..0a392616d48 100644
--- a/gdb/python/py-infthread.c
+++ b/gdb/python/py-infthread.c
@@ -261,7 +261,7 @@ thpy_is_stopped (PyObject *self, PyObject *args)
 
   THPY_REQUIRE_VALID (thread_obj);
 
-  if (thread_obj->thread->state == THREAD_STOPPED)
+  if (thread_obj->thread->state () == THREAD_STOPPED)
     Py_RETURN_TRUE;
 
   Py_RETURN_FALSE;
@@ -277,7 +277,7 @@ thpy_is_running (PyObject *self, PyObject *args)
 
   THPY_REQUIRE_VALID (thread_obj);
 
-  if (thread_obj->thread->state == THREAD_RUNNING)
+  if (thread_obj->thread->state () == THREAD_RUNNING)
     Py_RETURN_TRUE;
 
   Py_RETURN_FALSE;
@@ -293,7 +293,7 @@ thpy_is_exited (PyObject *self, PyObject *args)
 
   THPY_REQUIRE_VALID (thread_obj);
 
-  if (thread_obj->thread->state == THREAD_EXITED)
+  if (thread_obj->thread->state () == THREAD_EXITED)
     Py_RETURN_TRUE;
 
   Py_RETURN_FALSE;
diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index 2d71b72ec51..9705d3a251a 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -2042,18 +2042,18 @@ get_thread_current_frame_id (struct thread_info *tp)
 
   process_stratum_target *proc_target = tp->inf->process_target ();
 
-  /* Clear the executing flag to allow changes to the current frame.
-     We are not actually running, yet.  We just started a reverse execution
-     command or a record goto command.
-     For the latter, EXECUTING is false and this has no effect.
-     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.  */
-  bool executing = tp->executing ();
-  set_executing (proc_target, inferior_ptid, false);
+  /* Temporarily set the thread to internally stopped to allow changes
+     to the current frame.  We are not actually running, yet.  We just
+     started a reverse execution command or a record goto command.
+     For the latter, the thread is stopped and this has no effect.
+     For the former, the thread is running and we're in wait, about to
+     move the thread.  Since we need to recompute the stack, we
+     temporarily set the thread to internally stopped.  */
+  thread_int_state prev_int_state = tp->internal_state ();
+  set_internal_state (proc_target, inferior_ptid, THREAD_INT_STOPPED);
   SCOPE_EXIT
     {
-      set_executing (proc_target, inferior_ptid, executing);
+      set_internal_state (proc_target, inferior_ptid, prev_int_state);
     };
   return get_frame_id (get_current_frame ());
 }
diff --git a/gdb/record-full.c b/gdb/record-full.c
index b52fb062d80..cf162f451fc 100644
--- a/gdb/record-full.c
+++ b/gdb/record-full.c
@@ -1270,10 +1270,12 @@ record_full_wait_1 (struct target_ops *ops,
 			{
 			  /* Try to insert the software single step breakpoint.
 			     If insert success, set step to 0.  */
-			  set_executing (proc_target, inferior_ptid, false);
+			  set_internal_state (proc_target, inferior_ptid,
+					      THREAD_INT_STOPPED);
 			  SCOPE_EXIT
 			    {
-			      set_executing (proc_target, inferior_ptid, true);
+			      set_internal_state (proc_target, inferior_ptid,
+						  THREAD_INT_RUNNING);
 			    };
 
 			  reinit_frame_cache ();
diff --git a/gdb/regcache.c b/gdb/regcache.c
index e3d435f90d5..cd6e65f9dc9 100644
--- a/gdb/regcache.c
+++ b/gdb/regcache.c
@@ -429,7 +429,7 @@ get_thread_regcache (process_stratum_target *target, ptid_t ptid)
 struct regcache *
 get_thread_regcache (thread_info *thread)
 {
-  gdb_assert (thread->state != THREAD_EXITED);
+  gdb_assert (thread->state () != THREAD_EXITED);
 
   return get_thread_regcache (thread->inf->process_target (),
 			      thread->ptid);
diff --git a/gdb/remote.c b/gdb/remote.c
index 1c49cdf0fc0..413425ab8e7 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -1220,12 +1220,15 @@ class remote_target : public process_stratum_target
   ptid_t select_thread_for_ambiguous_stop_reply
     (const struct target_waitstatus &status);
 
-  void remote_notice_new_inferior (ptid_t currthread, bool executing);
+  void remote_notice_new_inferior (ptid_t currthread,
+				   thread_int_state internal_state);
 
   void print_one_stopped_thread (thread_info *thread);
   void process_initial_stop_replies (int from_tty);
 
-  thread_info *remote_add_thread (ptid_t ptid, bool running, bool executing,
+  thread_info *remote_add_thread (ptid_t ptid,
+				  thread_state state,
+				  thread_int_state internal_state,
 				  bool silent_p);
 
   void btrace_sync_conf (const btrace_config *conf);
@@ -2924,13 +2927,16 @@ static remote_thread_info *get_remote_thread_info (thread_info *thread);
 static remote_thread_info *get_remote_thread_info (remote_target *target,
 						   ptid_t ptid);
 
-/* Add thread PTID to GDB's thread list.  Tag it as executing/running
-   according to EXECUTING and RUNNING respectively.  If SILENT_P (or the
-   remote_state::starting_up flag) is true then the new thread is added
-   silently, otherwise the new thread will be announced to the user.  */
+/* Add thread PTID to GDB's thread list.  Tag its user and internal
+   states according to STATE and INTERNAL_STATE respectively.  If
+   SILENT_P (or the remote_state::starting_up flag) is true then the
+   new thread is added silently, otherwise the new thread will be
+   announced to the user.  */
 
 thread_info *
-remote_target::remote_add_thread (ptid_t ptid, bool running, bool executing,
+remote_target::remote_add_thread (ptid_t ptid,
+				  thread_state state,
+				  thread_int_state internal_state,
 				  bool silent_p)
 {
   struct remote_state *rs = get_remote_state ();
@@ -2947,10 +2953,10 @@ remote_target::remote_add_thread (ptid_t ptid, bool running, bool executing,
   else
     thread = add_thread (this, ptid);
 
-  if (executing)
+  if (internal_state == THREAD_INT_RUNNING)
     get_remote_thread_info (thread)->set_resumed ();
-  set_executing (this, ptid, executing);
-  set_running (this, ptid, running);
+  set_internal_state (this, ptid, internal_state);
+  set_state (this, ptid, state);
 
   return thread;
 }
@@ -2959,26 +2965,29 @@ remote_target::remote_add_thread (ptid_t ptid, bool running, bool executing,
    It may be the first time we hear about such thread, so take the
    opportunity to add it to GDB's thread list.  In case this is the
    first time we're noticing its corresponding inferior, add it to
-   GDB's inferior list as well.  EXECUTING indicates whether the
-   thread is (internally) executing or stopped.  */
+   GDB's inferior list as well.  INTERNAL_STATE indicates whether the
+   thread is internally running or stopped.  */
 
 void
-remote_target::remote_notice_new_inferior (ptid_t currthread, bool executing)
+remote_target::remote_notice_new_inferior (ptid_t currthread,
+					   thread_int_state internal_state)
 {
   /* In non-stop mode, we assume new found threads are (externally)
      running until proven otherwise with a stop reply.  In all-stop,
      we can only get here if all threads are stopped.  */
-  bool running = target_is_non_stop_p ();
+  thread_state state = (target_is_non_stop_p ()
+			? THREAD_RUNNING
+			: THREAD_STOPPED);
 
   /* If this is a new thread, add it to GDB's thread list.
      If we leave it up to WFI to do this, bad things will happen.  */
 
   thread_info *tp = this->find_thread (currthread);
-  if (tp != NULL && tp->state == THREAD_EXITED)
+  if (tp != NULL && tp->state () == THREAD_EXITED)
     {
       /* We're seeing an event on a thread id we knew had exited.
 	 This has to be a new thread reusing the old id.  Add it.  */
-      remote_add_thread (currthread, running, executing, false);
+      remote_add_thread (currthread, state, internal_state, false);
       return;
     }
 
@@ -3000,7 +3009,7 @@ remote_target::remote_notice_new_inferior (ptid_t currthread, bool executing)
 	  else
 	    {
 	      thread_info *thr
-		= remote_add_thread (currthread, running, executing, false);
+		= remote_add_thread (currthread, state, internal_state, false);
 	      switch_to_thread (thr);
 	    }
 	  return;
@@ -3031,7 +3040,7 @@ remote_target::remote_notice_new_inferior (ptid_t currthread, bool executing)
 
       /* This is really a new thread.  Add it.  */
       thread_info *new_thr
-	= remote_add_thread (currthread, running, executing, false);
+	= remote_add_thread (currthread, state, internal_state, false);
 
       /* If we found a new inferior, let the common code do whatever
 	 it needs to with it (e.g., read shared libraries, insert
@@ -3042,7 +3051,7 @@ remote_target::remote_notice_new_inferior (ptid_t currthread, bool executing)
 	  struct remote_state *rs = get_remote_state ();
 
 	  if (!rs->starting_up)
-	    notice_new_inferior (new_thr, executing, 0);
+	    notice_new_inferior (new_thr, internal_state, 0);
 	}
     }
 }
@@ -4363,12 +4372,14 @@ remote_target::update_thread_list ()
 	  if (item.ptid != null_ptid)
 	    {
 	      /* In non-stop mode, we assume new found threads are
-		 executing until proven otherwise with a stop reply.
-		 In all-stop, we can only get here if all threads are
+		 running until proven otherwise with a stop reply.  In
+		 all-stop, we can only get here if all threads are
 		 stopped.  */
-	      bool executing = target_is_non_stop_p ();
+	      thread_int_state internal_state = (target_is_non_stop_p ()
+						 ? THREAD_INT_RUNNING
+						 : THREAD_INT_STOPPED);
 
-	      remote_notice_new_inferior (item.ptid, executing);
+	      remote_notice_new_inferior (item.ptid, internal_state);
 
 	      thread_info *tp = this->find_thread (item.ptid);
 	      remote_thread_info *info = get_remote_thread_info (tp);
@@ -4982,8 +4993,8 @@ remote_target::process_initial_stop_replies (int from_tty)
 	  || ws.sig () != GDB_SIGNAL_0)
 	evthread->set_pending_waitstatus (ws);
 
-      set_executing (this, event_ptid, false);
-      set_running (this, event_ptid, false);
+      set_internal_state (this, event_ptid, THREAD_INT_STOPPED);
+      set_state (this, event_ptid, THREAD_STOPPED);
       get_remote_thread_info (evthread)->set_not_resumed ();
     }
 
@@ -4996,7 +5007,7 @@ remote_target::process_initial_stop_replies (int from_tty)
       if (non_stop)
 	{
 	  thread_info *thread = any_live_thread_of_inferior (inf);
-	  notice_new_inferior (thread, thread->state == THREAD_RUNNING,
+	  notice_new_inferior (thread, thread->state () == THREAD_RUNNING,
 			       from_tty);
 	}
     }
@@ -5038,8 +5049,8 @@ remote_target::process_initial_stop_replies (int from_tty)
 	first = thread;
 
       if (!non_stop)
-	thread->set_running (false);
-      else if (thread->state != THREAD_STOPPED)
+	thread->set_state (THREAD_STOPPED);
+      else if (thread->state () != THREAD_STOPPED)
 	continue;
 
       if (selected == nullptr && thread->has_pending_waitstatus ())
@@ -6585,7 +6596,7 @@ remote_target::follow_fork (inferior *child_inf, ptid_t child_ptid,
 void
 remote_target::follow_clone (ptid_t child_ptid)
 {
-  remote_add_thread (child_ptid, false, false, false);
+  remote_add_thread (child_ptid, THREAD_STOPPED, THREAD_INT_STOPPED, false);
 }
 
 /* Target follow-exec function for remote targets.  Save EXECD_PATHNAME
@@ -6693,7 +6704,8 @@ extended_remote_target::attach (const char *args, int from_tty)
 
       /* Add the main thread to the thread list.  We add the thread
 	 silently in this case (the final true parameter).  */
-      thread_info *thr = remote_add_thread (curr_ptid, true, true, true);
+      thread_info *thr = remote_add_thread (curr_ptid, THREAD_RUNNING,
+					    THREAD_INT_RUNNING, true);
 
       switch_to_thread (thr);
     }
@@ -8571,7 +8583,7 @@ remote_target::process_stop_reply (stop_reply_up stop_reply,
       && status->kind () != TARGET_WAITKIND_SIGNALLED
       && status->kind () != TARGET_WAITKIND_NO_RESUMED)
     {
-      remote_notice_new_inferior (ptid, false);
+      remote_notice_new_inferior (ptid, THREAD_INT_STOPPED);
 
       /* Expedited registers.  */
       if (!stop_reply->regcache.empty ())
@@ -8677,7 +8689,7 @@ static ptid_t
 first_remote_resumed_thread (remote_target *target)
 {
   for (thread_info *tp : all_non_exited_threads (target, minus_one_ptid))
-    if (tp->resumed ())
+    if (tp->internal_state () != THREAD_INT_STOPPED)
       return tp->ptid;
   return null_ptid;
 }
diff --git a/gdb/sol-thread.c b/gdb/sol-thread.c
index ae1e5c07457..3c7f0d3d353 100644
--- a/gdb/sol-thread.c
+++ b/gdb/sol-thread.c
@@ -451,7 +451,7 @@ sol_thread_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
       if (rtnval.tid_p ())
 	{
 	  thread_info *thr = current_inferior ()->find_thread (rtnval);
-	  if (thr == NULL || thr->state == THREAD_EXITED)
+	  if (thr == NULL || thr->state () == THREAD_EXITED)
 	    {
 	      process_stratum_target *proc_target
 		= current_inferior ()->process_target ();
@@ -997,7 +997,7 @@ sol_update_thread_list_callback (const td_thrhandle_t *th, void *ignored)
 
   ptid_t ptid = ptid_t (current_inferior ()->pid, 0, ti.ti_tid);
   thread_info *thr = current_inferior ()->find_thread (ptid);
-  if (thr == NULL || thr->state == THREAD_EXITED)
+  if (thr == NULL || thr->state () == THREAD_EXITED)
     {
       process_stratum_target *proc_target
 	= current_inferior ()->process_target ();
diff --git a/gdb/target.c b/gdb/target.c
index 522bed8e939..c55c0878c6b 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -2653,10 +2653,10 @@ target_resume (ptid_t scope_ptid, int step, enum gdb_signal signal)
   current_inferior ()->top_target ()->resume (scope_ptid, step, signal);
 
   registers_changed_ptid (curr_target, scope_ptid);
-  /* We only set the internal executing state here.  The user/frontend
-     running state is set at a higher level.  This also clears the
-     thread's stop_pc as side effect.  */
-  set_executing (curr_target, scope_ptid, true);
+  /* We only set the internal state here.  The user/frontend state is
+     set at a higher level.  This also clears the thread's stop_pc as
+     side effect.  */
+  set_internal_state (curr_target, scope_ptid, THREAD_INT_RUNNING);
   clear_inline_frame_state (curr_target, scope_ptid);
 
   if (target_can_async_p ())
@@ -3805,9 +3805,10 @@ target_pass_ctrlc (void)
 
       for (thread_info *thr : inf->non_exited_threads ())
 	{
-	  /* A thread can be THREAD_STOPPED and executing, while
-	     running an infcall.  */
-	  if (thr->state == THREAD_RUNNING || thr->executing ())
+	  /* A thread can be externally THREAD_STOPPED and internally
+	     THREAD_INT_RUNNING, while running an infcall.  */
+	  if (thr->state () == THREAD_RUNNING
+	      || thr->internal_state () == THREAD_INT_RUNNING)
 	    {
 	      /* We can get here quite deep in target layers.  Avoid
 		 switching thread context or anything that would
diff --git a/gdb/thread-iter.h b/gdb/thread-iter.h
index abd7daff1f8..4463aaf37a6 100644
--- a/gdb/thread-iter.h
+++ b/gdb/thread-iter.h
@@ -151,7 +151,7 @@ struct non_exited_thread_filter
 {
   bool operator() (struct thread_info *thr) const
   {
-    return thr->state != THREAD_EXITED;
+    return thr->state () != THREAD_EXITED;
   }
 };
 
diff --git a/gdb/thread.c b/gdb/thread.c
index 0228027fb92..da45c263c92 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -223,23 +223,13 @@ set_thread_exited (thread_info *tp, std::optional<ULONGEST> exit_code,
   if (thread_is_in_step_over_chain (tp))
     global_thread_step_over_chain_remove (tp);
 
-  if (tp->state != THREAD_EXITED)
+  if (tp->state () != THREAD_EXITED)
     {
-      process_stratum_target *proc_target = tp->inf->process_target ();
-
-      /* Some targets unpush themselves from the inferior's target stack before
-	 clearing the inferior's thread list (which marks all threads as exited,
-	 and therefore leads to this function).  In this case, the inferior's
-	 process target will be nullptr when we arrive here.
-
-	 See also the comment in inferior::unpush_target.  */
-      if (proc_target != nullptr)
-	proc_target->maybe_remove_resumed_with_pending_wait_status (tp);
-
       notify_thread_exited (tp, exit_code, silent);
 
       /* Tag it as exited.  */
-      tp->state = THREAD_EXITED;
+      tp->set_state (THREAD_EXITED);
+      tp->set_internal_state (THREAD_INT_EXITED);
 
       /* Clear breakpoints, etc. associated with this thread.  */
       clear_thread_inferior_resources (tp);
@@ -373,34 +363,50 @@ thread_info::deletable () const
 /* See gdbthread.h.  */
 
 void
-thread_info::set_executing (bool executing)
-{
-  m_executing = executing;
-  if (executing)
-    this->clear_stop_pc ();
-}
-
-/* See gdbthread.h.  */
-
-void
-thread_info::set_resumed (bool resumed)
+thread_info::set_internal_state (thread_int_state state)
 {
-  if (resumed == m_resumed)
+  if (m_internal_state == state)
     return;
 
-  process_stratum_target *proc_target = this->inf->process_target ();
-
-  /* If we transition from resumed to not resumed, we might need to remove
-     the thread from the resumed threads with pending statuses list.  */
-  if (!resumed)
-    proc_target->maybe_remove_resumed_with_pending_wait_status (this);
+  if (state == THREAD_INT_RUNNING)
+    this->clear_stop_pc ();
 
-  m_resumed = resumed;
+  if (state == THREAD_INT_RESUMED_PENDING_STATUS)
+    gdb_assert (this->has_pending_waitstatus ());
+  else if (state == THREAD_INT_RUNNING)
+    gdb_assert (!this->has_pending_waitstatus ());
 
-  /* If we transition from not resumed to resumed, we might need to add
+  /* If we transition from resumed-pending-status to another state, we
+     might need to remove the thread from the resumed threads with
+     pending statuses list.  Conversely, if we transition to
+     resumed-pending-status from another state, we might need to add
      the thread to the resumed threads with pending statuses list.  */
-  if (resumed)
-    proc_target->maybe_add_resumed_with_pending_wait_status (this);
+  if (state == THREAD_INT_RESUMED_PENDING_STATUS
+      || m_internal_state == THREAD_INT_RESUMED_PENDING_STATUS)
+    {
+      process_stratum_target *proc_target = this->inf->process_target ();
+
+      /* We need the proc_target NULL checks below, because some
+	 targets unpush themselves from the inferior's target stack
+	 before clearing the inferior's thread list (which marks all
+	 threads as exited, and therefore leads to this function).  In
+	 this case, the inferior's process target will be nullptr when
+	 we arrive here.  See also the comment in
+	 inferior::unpush_target.  */
+
+      if (state != THREAD_INT_RESUMED_PENDING_STATUS && proc_target != nullptr)
+	proc_target->maybe_remove_resumed_with_pending_wait_status (this);
+
+      /* Note maybe_remove_resumed_with_pending_wait_status internally
+	 reads this state.  Thus it must be updated after the call
+	 above, and before the call below.  */
+      m_internal_state = state;
+
+      if (state == THREAD_INT_RESUMED_PENDING_STATUS && proc_target != nullptr)
+	proc_target->maybe_add_resumed_with_pending_wait_status (this);
+    }
+  else
+    m_internal_state = state;
 }
 
 /* See gdbthread.h.  */
@@ -409,12 +415,13 @@ void
 thread_info::set_pending_waitstatus (const target_waitstatus &ws)
 {
   gdb_assert (!this->has_pending_waitstatus ());
+  /* Doesn't make sense to set a pending status on an exited or
+     running thread.  */
+  gdb_assert (this->internal_state () == THREAD_INT_STOPPED
+	      || this->internal_state () == THREAD_INT_RESUMED_PENDING_STATUS);
 
   m_suspend.waitstatus = ws;
   m_suspend.waitstatus_pending_p = 1;
-
-  process_stratum_target *proc_target = this->inf->process_target ();
-  proc_target->maybe_add_resumed_with_pending_wait_status (this);
 }
 
 /* See gdbthread.h.  */
@@ -424,9 +431,6 @@ thread_info::clear_pending_waitstatus ()
 {
   gdb_assert (this->has_pending_waitstatus ());
 
-  process_stratum_target *proc_target = this->inf->process_target ();
-  proc_target->maybe_remove_resumed_with_pending_wait_status (this);
-
   m_suspend.waitstatus_pending_p = 0;
 }
 
@@ -435,8 +439,8 @@ thread_info::clear_pending_waitstatus ()
 void
 thread_info::set_thread_options (gdb_thread_options thread_options)
 {
-  gdb_assert (this->state != THREAD_EXITED);
-  gdb_assert (!this->executing ());
+  gdb_assert (this->state () != THREAD_EXITED);
+  gdb_assert (this->internal_state () == THREAD_INT_STOPPED);
 
   if (m_thread_options == thread_options)
     return;
@@ -682,30 +686,30 @@ any_thread_of_inferior (inferior *inf)
 thread_info *
 any_live_thread_of_inferior (inferior *inf)
 {
-  struct thread_info *curr_tp = NULL;
-  struct thread_info *tp_executing = NULL;
+  thread_info *curr_tp = NULL;
+  thread_info *tp_running = NULL;
 
   gdb_assert (inf != NULL && inf->pid != 0);
 
-  /* Prefer the current thread if it's not executing.  */
+  /* Prefer the current thread if it's stopped.  */
   if (inferior_ptid != null_ptid && current_inferior () == inf)
     {
-      /* If the current thread is dead, forget it.  If it's not
-	 executing, use it.  Otherwise, still choose it (below), but
-	 only if no other non-executing thread is found.  */
+      /* If the current thread is dead, forget it.  If it's stopped,
+	 use it.  Otherwise, still choose it (below), but only if no
+	 other running thread is found.  */
       curr_tp = inferior_thread ();
-      if (curr_tp->state == THREAD_EXITED)
+      if (curr_tp->internal_state () == THREAD_INT_EXITED)
 	curr_tp = NULL;
-      else if (!curr_tp->executing ())
+      else if (curr_tp->internal_state () != THREAD_INT_RUNNING)
 	return curr_tp;
     }
 
   for (thread_info *tp : inf->non_exited_threads ())
     {
-      if (!tp->executing ())
+      if (tp->internal_state () != THREAD_INT_RUNNING)
 	return tp;
 
-      tp_executing = tp;
+      tp_running = tp;
     }
 
   /* If both the current thread and all live threads are executing,
@@ -713,15 +717,15 @@ any_live_thread_of_inferior (inferior *inf)
   if (curr_tp != NULL)
     return curr_tp;
 
-  /* Otherwise, just return an executing thread, if any.  */
-  return tp_executing;
+  /* Otherwise, just return a running thread, if any.  */
+  return tp_running;
 }
 
 /* Return true if TP is an active thread.  */
 static bool
 thread_alive (thread_info *tp)
 {
-  if (tp->state == THREAD_EXITED)
+  if (tp->state () == THREAD_EXITED)
     return false;
 
   /* Ensure we're looking at the right target stack.  */
@@ -773,7 +777,7 @@ void
 delete_exited_threads (void)
 {
   for (thread_info *tp : all_threads_safe ())
-    if (tp->state == THREAD_EXITED)
+    if (tp->state () == THREAD_EXITED)
       delete_thread (tp);
 }
 
@@ -852,43 +856,6 @@ thread_change_ptid (process_stratum_target *targ,
   gdb::observers::thread_ptid_changed.notify (targ, old_ptid, new_ptid);
 }
 
-/* See gdbthread.h.  */
-
-void
-set_resumed (process_stratum_target *targ, ptid_t ptid, bool resumed)
-{
-  for (thread_info *tp : all_non_exited_threads (targ, ptid))
-    tp->set_resumed (resumed);
-}
-
-/* Helper for set_running, that marks one thread either running or
-   stopped.  */
-
-static bool
-set_running_thread (struct thread_info *tp, bool running)
-{
-  bool started = false;
-
-  if (running && tp->state == THREAD_STOPPED)
-    started = true;
-  tp->state = running ? THREAD_RUNNING : THREAD_STOPPED;
-
-  threads_debug_printf ("thread: %s, running? %d%s",
-			tp->ptid.to_string ().c_str (), running,
-			(started ? " (started)" : ""));
-
-  if (!running)
-    {
-      /* If the thread is now marked stopped, remove it from
-	 the step-over queue, so that we don't try to resume
-	 it until the user wants it to.  */
-      if (thread_is_in_step_over_chain (tp))
-	global_thread_step_over_chain_remove (tp);
-    }
-
-  return started;
-}
-
 /* Notify interpreters and observers that the target was resumed.  */
 
 static void
@@ -905,41 +872,73 @@ notify_target_resumed (ptid_t ptid)
 
 /* See gdbthread.h.  */
 
-void
-thread_info::set_running (bool running)
+thread_state
+thread_info::set_state (thread_state state,
+			bool suppress_notification)
 {
-  if (set_running_thread (this, running))
-    notify_target_resumed (this->ptid);
+  thread_state prev_state = m_state;
+
+  if (prev_state == state)
+    return prev_state;
+
+  threads_debug_printf ("thread: %s, %s -> %s",
+			this->ptid.to_string ().c_str (),
+			thread_state_string (m_state),
+			thread_state_string (state));
+
+  m_state = state;
+
+  switch (m_state)
+    {
+    case THREAD_EXITED:
+      break;
+
+    case THREAD_STOPPED:
+      /* If the thread is now marked stopped, remove it from
+	 the step-over queue, so that we don't try to resume
+	 it until the user wants it to.  */
+      if (thread_is_in_step_over_chain (this))
+	global_thread_step_over_chain_remove (this);
+      break;
+
+    case THREAD_RUNNING:
+      if (!suppress_notification)
+	notify_target_resumed (this->ptid);
+      break;
+    }
+
+  return prev_state;
 }
 
 void
-set_running (process_stratum_target *targ, ptid_t ptid, bool running)
+set_state (process_stratum_target *targ, ptid_t ptid, thread_state state)
 {
   /* We try not to notify the observer if no thread has actually
-     changed the running state -- merely to reduce the number of
+     changed its public state -- merely to reduce the number of
      messages to the MI frontend.  A frontend is supposed to handle
      multiple *running notifications just fine.  */
-  bool any_started = false;
+  bool any_changed = false;
 
   for (thread_info *tp : all_non_exited_threads (targ, ptid))
-    if (set_running_thread (tp, running))
-      any_started = true;
+    if (tp->set_state (state, true) != state)
+      any_changed = true;
 
-  if (any_started)
+  if (any_changed && state == THREAD_RUNNING)
     notify_target_resumed (ptid);
 }
 
 void
-set_executing (process_stratum_target *targ, ptid_t ptid, bool executing)
+set_internal_state (process_stratum_target *targ, ptid_t ptid,
+		    thread_int_state state)
 {
   for (thread_info *tp : all_non_exited_threads (targ, ptid))
-    tp->set_executing (executing);
+    tp->set_internal_state (state);
 
   /* It only takes one running thread to spawn more threads.  */
-  if (executing)
+  if (state == THREAD_INT_RUNNING)
     targ->threads_executing = true;
   /* Only clear the flag if the caller is telling us everything is
-     stopped.  */
+     stopped or dead.  */
   else if (minus_one_ptid == ptid)
     targ->threads_executing = false;
 }
@@ -964,14 +963,41 @@ set_stop_requested (process_stratum_target *targ, ptid_t ptid, bool stop)
     gdb::observers::thread_stop_requested.notify (ptid);
 }
 
+/* Map INT_STATE to a user state.  */
+
+static thread_state
+state_from_int_state (thread_int_state int_state)
+{
+  switch (int_state)
+    {
+    case THREAD_INT_RUNNING:
+    case THREAD_INT_RESUMED_PENDING_STATUS:
+      return THREAD_RUNNING;
+    case THREAD_INT_STOPPED:
+      return THREAD_STOPPED;
+    case THREAD_INT_EXITED:
+      return THREAD_EXITED;
+    }
+
+  gdb_assert_not_reached ("unknown thread_int_state: %d", int_state);
+}
+
+/* See gdbthread.h.  Note this is a friend of thread_info so that it
+   can access the thread_info::set_state overload that lets us
+   suppress the target_resumed notification.  */
+
 void
 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 ()))
-      any_started = true;
+    {
+      thread_state new_state = state_from_int_state (tp->internal_state ());
+      thread_state prev_state = tp->set_state (new_state, true);
+      if (prev_state != new_state && new_state == THREAD_RUNNING)
+	any_started = true;
+    }
 
   if (any_started)
     notify_target_resumed (ptid);
@@ -989,7 +1015,7 @@ validate_registers_access (void)
   thread_info *tp = inferior_thread ();
 
   /* Don't try to read from a dead thread.  */
-  if (tp->state == THREAD_EXITED)
+  if (tp->state () == THREAD_EXITED)
     error (_("The current thread has terminated"));
 
   /* ... or from a spinning thread.  FIXME: This isn't actually fully
@@ -997,7 +1023,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->internal_state () == THREAD_INT_RUNNING)
     {
       /* If we are replaying with the record-full subsystem, even though
 	 the thread is executing, it is always safe to read from it since
@@ -1017,11 +1043,11 @@ can_access_registers_thread (thread_info *thread)
     return false;
 
   /* Don't try to read from a dead thread.  */
-  if (thread->state == THREAD_EXITED)
+  if (thread->state () == THREAD_EXITED)
     return false;
 
   /* ... or from a spinning thread.  FIXME: see validate_registers_access.  */
-  if (thread->executing ())
+  if (thread->internal_state () == THREAD_INT_RUNNING)
     {
       /* See validate_registers_access.  */
       if (!record_full_is_replaying ())
@@ -1105,14 +1131,14 @@ should_print_thread (const char *requested_threads,
       return false;
     }
 
-  if (thr->state == THREAD_EXITED)
+  if (thr->state () == THREAD_EXITED)
     return false;
 
-  bool is_stopped = (thr->state == THREAD_STOPPED);
+  bool is_stopped = (thr->state () == THREAD_STOPPED);
   if (opts.show_stopped_threads && is_stopped)
     return true;
 
-  bool is_running = (thr->state == THREAD_RUNNING);
+  bool is_running = (thr->state () == THREAD_RUNNING);
   if (opts.show_running_threads && is_running)
     return true;
 
@@ -1203,7 +1229,7 @@ do_print_thread (ui_out *uiout, const char *requested_threads,
       uiout->field_string ("target-id", thread_target_id_str (tp));
     }
 
-  if (tp->state == THREAD_RUNNING)
+  if (tp->state () == THREAD_RUNNING)
     uiout->text ("(running)\n");
   else
     {
@@ -1219,7 +1245,7 @@ do_print_thread (ui_out *uiout, const char *requested_threads,
     {
       const char *state = "stopped";
 
-      if (tp->state == THREAD_RUNNING)
+      if (tp->state () == THREAD_RUNNING)
 	state = "running";
       uiout->field_string ("state", state);
     }
@@ -1330,7 +1356,7 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads,
     for (inferior *inf : all_inferiors ())
       for (thread_info *tp : inf->threads ())
 	{
-	  if (tp == current_thread && tp->state == THREAD_EXITED)
+	  if (tp == current_thread && tp->state () == THREAD_EXITED)
 	    current_exited = true;
 
 	  print_thread (uiout, requested_threads, opts, global_ids, pid,
@@ -1495,7 +1521,7 @@ scoped_restore_current_thread::restore ()
      changed, so we have to recheck it here.  */
   if (inferior_ptid != null_ptid
       && m_was_stopped
-      && m_thread->state == THREAD_STOPPED
+      && m_thread->state () == THREAD_STOPPED
       && target_has_registers ()
       && target_has_stack ()
       && target_has_memory ())
@@ -1518,7 +1544,7 @@ scoped_restore_current_thread::scoped_restore_current_thread ()
     {
       m_thread = thread_info_ref::new_reference (inferior_thread ());
 
-      m_was_stopped = m_thread->state == THREAD_STOPPED;
+      m_was_stopped = m_thread->state () == THREAD_STOPPED;
       save_selected_frame (&m_selected_frame_id, &m_selected_frame_level);
     }
 }
@@ -1964,7 +1990,7 @@ thread_command (const char *tidstr, int from_tty)
 	{
 	  struct thread_info *tp = inferior_thread ();
 
-	  if (tp->state == THREAD_EXITED)
+	  if (tp->state () == THREAD_EXITED)
 	    gdb_printf (_("[Current thread is %s (%s) (exited)]\n"),
 			print_thread_id (tp),
 			target_pid_to_str (inferior_ptid).c_str ());
@@ -2122,7 +2148,7 @@ print_selected_thread_frame (struct ui_out *uiout,
 	}
     }
 
-  if (tp->state == THREAD_RUNNING)
+  if (tp->state () == THREAD_RUNNING)
     {
       if (selection & USER_SELECTED_THREAD)
 	uiout->text ("(running)\n");
@@ -2167,7 +2193,7 @@ update_threads_executing (void)
 
       for (thread_info *tp : inf->non_exited_threads ())
 	{
-	  if (tp->executing ())
+	  if (tp->internal_state () == THREAD_INT_RUNNING)
 	    {
 	      targ->threads_executing = true;
 	      return;
@@ -2221,6 +2247,29 @@ thread_state_string (enum thread_state state)
   gdb_assert_not_reached ("unknown thread state");
 }
 
+/* See gdbthread.h.  */
+
+const char *
+thread_int_state_string (thread_int_state state)
+{
+  switch (state)
+    {
+    case THREAD_INT_STOPPED:
+      return "INT_STOPPED";
+
+    case THREAD_INT_RUNNING:
+      return "INT_RUNNING";
+
+    case THREAD_INT_RESUMED_PENDING_STATUS:
+      return "INT_RESUMED_PENDING_STATUS";
+
+    case THREAD_INT_EXITED:
+      return "INT_EXITED";
+    }
+
+  gdb_assert_not_reached ("unknown thread internal state");
+}
+
 /* Return a new value for the selected thread's id.  Return a value of
    0 if no thread is selected.  If GLOBAL is true, return the thread's
    global number.  Otherwise return the per-inferior number.  */
diff --git a/gdb/top.c b/gdb/top.c
index 6adef467b90..8b35d0467b6 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -586,7 +586,7 @@ execute_command (const char *p, int from_tty)
      we just finished executing did not resume the inferior's execution.
      If it did resume the inferior, we will do that check after
      the inferior stopped.  */
-  if (has_stack_frames () && inferior_thread ()->state != THREAD_RUNNING)
+  if (has_stack_frames () && inferior_thread ()->state () != THREAD_RUNNING)
     check_frame_language_change ();
 
   cleanup_if_error.release ();
-- 
2.49.0


  parent reply	other threads:[~2025-05-19 13:28 UTC|newest]

Thread overview: 97+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-05-19 13:22 [PATCH v2 00/47] Windows non-stop mode Pedro Alves
2025-05-19 13:22 ` [PATCH v2 01/47] Make default_gdb_exit resilient to failed closes Pedro Alves
2025-05-19 13:56   ` Andrew Burgess
2025-06-06 13:56     ` Pedro Alves
2025-05-19 13:22 ` [PATCH v2 02/47] Add test for continuing with some threads running Pedro Alves
2025-05-21 19:36   ` Kevin Buettner
2026-04-02 13:07     ` Pedro Alves
2025-05-19 13:22 ` [PATCH v2 03/47] infrun: Remove unnecessary currently_stepping call Pedro Alves
2025-05-21 19:44   ` Kevin Buettner
2026-04-02 13:17     ` Pedro Alves
2025-05-19 13:22 ` [PATCH v2 04/47] infrun: Split currently_stepping, fix sw watchpoints issue Pedro Alves
2026-04-02 13:33   ` Pedro Alves
2025-05-19 13:22 ` Pedro Alves [this message]
2026-04-06 18:01   ` [PATCH v2 05/47] thread_info::executing+resumed -> thread_info::internal_state Pedro Alves
2025-05-19 13:22 ` [PATCH v2 06/47] Windows gdb: Dead code in windows_nat_target::do_initial_windows_stuff Pedro Alves
2025-05-19 13:22 ` [PATCH v2 07/47] Windows gdb: Eliminate global current_process.dr[8] global Pedro Alves
2025-05-28 19:09   ` Tom Tromey
2026-04-06 19:44   ` Pedro Alves
2025-05-19 13:22 ` [PATCH v2 08/47] Windows gdb+gdbserver: New find_thread, replaces thread_rec(DONT_INVALIDATE_CONTEXT) Pedro Alves
2025-05-19 13:22 ` [PATCH v2 09/47] Windows gdb: handle_output_debug_string return type Pedro Alves
2025-05-19 13:22 ` [PATCH v2 10/47] Windows gdb: Eliminate reload_context Pedro Alves
2025-05-19 13:22 ` [PATCH v2 11/47] Windows gdb+gdbserver: Eliminate thread_rec(INVALIDATE_CONTEXT) calls Pedro Alves
2025-05-19 13:22 ` [PATCH v2 12/47] Windows gdb+gdbserver: Eliminate DONT_SUSPEND Pedro Alves
2025-05-19 13:22 ` [PATCH v2 13/47] Windows gdb+gdbserver: Eliminate windows_process_info::thread_rec Pedro Alves
2025-05-19 13:22 ` [PATCH v2 14/47] Windows gdb: Simplify windows_nat_target::wait Pedro Alves
2025-05-28 19:16   ` Tom Tromey
2025-05-19 13:22 ` [PATCH v2 15/47] Windows gdb+gdbserver: Move suspending thread to when returning event Pedro Alves
2025-05-28 19:17   ` Tom Tromey
2025-05-19 13:22 ` [PATCH v2 16/47] Windows gdb: Introduce continue_last_debug_event_main_thread Pedro Alves
2025-05-28 19:18   ` Tom Tromey
2025-05-19 13:22 ` [PATCH v2 17/47] Windows gdb: Introduce windows_continue_flags Pedro Alves
2025-05-19 13:22 ` [PATCH v2 18/47] Windows gdb: Factor code out of windows_nat_target::windows_continue Pedro Alves
2025-05-19 13:22 ` [PATCH v2 19/47] Windows gdb: Pending stop and current_event Pedro Alves
2025-05-19 13:22 ` [PATCH v2 20/47] Windows gdb+gdbserver: Elim desired_stop_thread_id / rework pending_stops Pedro Alves
2025-05-30 20:41   ` Tom Tromey
2025-05-19 13:22 ` [PATCH v2 21/47] Windows gdb+gdbserver: Introduce get_last_debug_event_ptid Pedro Alves
2025-05-28 19:21   ` Tom Tromey
2025-05-19 13:22 ` [PATCH v2 22/47] Windows gdb: Can't pass signal to thread other than last stopped thread Pedro Alves
2025-05-28 19:22   ` Tom Tromey
2025-05-19 13:22 ` [PATCH v2 23/47] Windows gdbserver: Fix scheduler-locking Pedro Alves
2025-05-30 20:37   ` Tom Tromey
2025-05-19 13:22 ` [PATCH v2 24/47] Windows gdb: Enable "set scheduler-locking on" Pedro Alves
2025-05-19 13:22 ` [PATCH v2 25/47] Windows gdbserver: Eliminate soft-interrupt mechanism Pedro Alves
2025-05-19 13:22 ` [PATCH v2 26/47] Windows gdb+gdbserver: Make current_event per-thread state Pedro Alves
2025-05-28 19:30   ` Tom Tromey
2025-05-19 13:22 ` [PATCH v2 27/47] Windows gdb+gdbserver: Make last_sig " Pedro Alves
2025-05-28 19:31   ` Tom Tromey
2025-05-19 13:22 ` [PATCH v2 28/47] Windows gdb+gdbserver: Make siginfo_er " Pedro Alves
2025-05-28 19:33   ` Tom Tromey
2025-05-19 13:22 ` [PATCH v2 29/47] Add backpointer from windows_thread_info to windows_process_info Pedro Alves
2025-05-19 13:22 ` [PATCH v2 30/47] Windows gdb+gdbserver: Share $_siginfo reading code Pedro Alves
2025-05-19 13:22 ` [PATCH v2 31/47] Windows gdb+gdbserver: Eliminate struct pending_stop Pedro Alves
2025-05-28 19:36   ` Tom Tromey
2025-05-19 13:22 ` [PATCH v2 32/47] Windows gdb: Change serial_event management Pedro Alves
2025-05-28 19:37   ` Tom Tromey
2025-05-19 13:22 ` [PATCH v2 33/47] Windows gdb: cygwin_set_dr => windows_set_dr, etc Pedro Alves
2025-05-19 13:22 ` [PATCH v2 34/47] Windows gdb: Avoid writing debug registers if watchpoint hit pending Pedro Alves
2025-05-30 20:43   ` Tom Tromey
2025-05-19 13:22 ` [PATCH v2 35/47] Windows gdb+gdbserver: Check whether DBG_REPLY_LATER is available Pedro Alves
2025-05-19 13:22 ` [PATCH v2 36/47] linux-nat: Factor out get_detach_signal code to common code Pedro Alves
2025-05-28 19:44   ` Tom Tromey
2025-05-19 13:22 ` [PATCH v2 37/47] Windows GDB: make windows_thread_info be private thread_info data Pedro Alves
2025-05-28 19:52   ` Tom Tromey
2025-05-19 13:22 ` [PATCH v2 38/47] Introduce windows_nat::event_code_to_string Pedro Alves
2025-05-28 19:53   ` Tom Tromey
2025-05-19 13:23 ` [PATCH v2 39/47] Windows gdb: Add non-stop support Pedro Alves
2025-06-05 16:21   ` Tom Tromey
2025-05-19 13:23 ` [PATCH v2 40/47] Windows gdb: Eliminate invalidate_context Pedro Alves
2025-05-28 19:54   ` Tom Tromey
2025-05-19 13:23 ` [PATCH v2 41/47] Windows gdb: Watchpoints while running (internal vs external stops) Pedro Alves
2025-05-30 20:50   ` Tom Tromey
2025-05-19 13:23 ` [PATCH v2 42/47] gdb_test_multiple: Anchor prompt match if -lbl Pedro Alves
2025-05-21 15:19   ` Tom de Vries
2025-05-27 22:41     ` Pedro Alves
2025-05-27 23:20       ` Pedro Alves
2025-05-28 11:59         ` [PATCH v2] of " Pedro Alves
2025-06-05 16:37           ` Pedro Alves
2025-06-05 17:20             ` [PATCH v3] " Pedro Alves
2025-06-06  9:58               ` Tom de Vries
2025-06-06 13:53                 ` Pedro Alves
2025-05-19 13:23 ` [PATCH v2 43/47] Windows gdb: extra thread info => show exiting Pedro Alves
2025-05-28 19:58   ` Tom Tromey
2025-05-19 13:23 ` [PATCH v2 44/47] Add gdb.threads/leader-exit-schedlock.exp Pedro Alves
2025-05-29 16:09   ` Tom Tromey
2025-05-19 13:23 ` [PATCH v2 45/47] infrun: with AS+NS, prefer process exit over thread exit Pedro Alves
2025-05-19 13:23 ` [PATCH v2 46/47] Windows gdb: Always non-stop (default to "maint set target-non-stop on") Pedro Alves
2025-05-29 16:02   ` Tom Tromey
2025-05-19 13:23 ` [PATCH v2 47/47] Mention Windows scheduler-locking and non-stop support in NEWS Pedro Alves
2025-05-19 14:07   ` Eli Zaretskii
2025-06-05 17:57 ` [PATCH v2 00/47] Windows non-stop mode Tom Tromey
2025-06-11 22:06   ` [PATCH] Improve attach on Windows (was: Re: [PATCH v2 00/47] Windows non-stop mode) Pedro Alves
2026-04-02 12:21     ` [PATCH] Improve attach on Windows Pedro Alves
2026-04-02 18:52       ` Tom Tromey
2025-06-11 23:51   ` [PATCH v2 00/47] Windows non-stop mode Pedro Alves
2025-06-12 19:23     ` Tom Tromey
2025-06-13 10:34       ` Pedro Alves
2025-06-13 14:23         ` Tom Tromey

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250519132308.3553663-6-pedro@palves.net \
    --to=pedro@palves.net \
    --cc=gdb-patches@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox