Don't let the ThreadPlanSingleStepTimeout interrupt an already stopped process (#227898)

When the ThreadPlanSingleThreadTimeout timeout fires, first check
whether the process is stopped before sending the interrupt.

This is a simpler way to address the problem that was identified in:

https://github.com/llvm/llvm-project/pull/224272

The problem solved there is that if the stop processing is still going
on when the timer fires, we send the interrupt request event which gets
enqueued and then handled after the stop event processing has restarted
the inferior to continue the thread plan work.

That patch involved trying to figure out, when you receive the event,
whether it was stale or not. It was harder to reason about - and not all
the way right, though that probably could be fixed.

But when you get a stop event, we first set the private state to stopped
and then start the handling. So if instead we check whether the process
is stopped when the timer fires, and don't send the interrupt if it is,
we fix the same problem in a much more obviously correct way.

This addresses the flakiness of the test:

TestSingleThreadStepTimeout.py

GitOrigin-RevId: e0d351f24d0afe03a077d19b358363142e876ea7
diff --git a/include/lldb/Target/Process.h b/include/lldb/Target/Process.h
index 08defc5..226c580 100644
--- a/include/lldb/Target/Process.h
+++ b/include/lldb/Target/Process.h
@@ -375,6 +375,7 @@
   friend class Target;
   friend class ThreadList;
   friend class MemoryCache;
+  friend class ThreadPlanSingleThreadTimeout;
 
 public:
   /// Broadcaster event bits definitions.
diff --git a/source/Target/Process.cpp b/source/Target/Process.cpp
index 0be2d92..c1343fa 100644
--- a/source/Target/Process.cpp
+++ b/source/Target/Process.cpp
@@ -4279,6 +4279,16 @@
   const StateType new_state =
       Process::ProcessEventData::GetStateFromEvent(event_sp.get());
 
+#ifdef LLDB_SIMULATE_SLOW_STOPS
+  // Simulate a slow machine that takes a long time to process an internal
+  // stop, so that ThreadPlanSingleThreadTimeout's 10ms timer fires while we
+  // are still in here.  This is helpful for diagnosing problems in
+  // the thread plans - particular the interaction with the
+  // ThreadPlanSingleThreadTimeout.
+  if (StateIsStoppedState(new_state, /*must_exist=*/true))
+    std::this_thread::sleep_for(std::chrono::milliseconds(10));
+#endif
+  
   // First check to see if anybody wants a shot at this event:
   if (m_next_event_action_up) {
     NextEventAction::EventActionResult action_result =
diff --git a/source/Target/ThreadPlanSingleThreadTimeout.cpp b/source/Target/ThreadPlanSingleThreadTimeout.cpp
index 71be813..39c9a79 100644
--- a/source/Target/ThreadPlanSingleThreadTimeout.cpp
+++ b/source/Target/ThreadPlanSingleThreadTimeout.cpp
@@ -246,12 +246,18 @@
 
 void ThreadPlanSingleThreadTimeout::HandleTimeout() {
   Log *log = GetLog(LLDBLog::Step);
-  LLDB_LOGF(
-      log,
-      "ThreadPlanSingleThreadTimeout::HandleTimeout() send async interrupt.");
-  m_state = State::AsyncInterrupt;
-
   // Private state thread will only send async interrupt
   // in running state so no need to check state here.
-  m_process.SendAsyncInterrupt(&GetThread());
+  if (m_process.GetPrivateState() == eStateRunning) {
+    LLDB_LOGF(
+        log,
+        "ThreadPlanSingleThreadTimeout::HandleTimeout() send async interrupt.");
+      m_process.SendAsyncInterrupt(&GetThread());
+
+    m_state = State::AsyncInterrupt;
+  } else {
+    LLDB_LOGF(log, "ThreadPlanSingleThreadTimeout::HandleTimeout() process "
+                   "already stopped - didn't send interrupt");
+  }
+
 }