[Lldb-commits] [lldb] r227909 - Get initial thread state coordinator integration working.

Chaoren Lin chaorenl at google.com
Mon Feb 2 17:50:42 PST 2015


Author: chaoren
Date: Mon Feb  2 19:50:42 2015
New Revision: 227909

URL: http://llvm.org/viewvc/llvm-project?rev=227909&view=rev
Log:
Get initial thread state coordinator integration working.

* Fixed bug in run loop where run loop return enum was being treated
  erroneously like an int, causing the TSC event loop to terminate
  prematurely.

* Added an explicit scope in NativeProcessLinux::Resume() for the
  threads lock lifetime.  (This was likely unnecessary but is
  more explicit.)

* Fixed a bug in ThreadStateCoordinator where resume execution was
  not updating the internal state about the thread assumed to be
  running now.  I'll add a test and upstream this in a moment.

* Added a verbose logging mechanism to event processing within
  ThreadStateCoordinator.  It is currently enabled when the
  'log enable lldb thread' is true upon inferior launch/attach.

Modified:
    lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp
    lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h
    lldb/trunk/source/Plugins/Process/Linux/ThreadStateCoordinator.cpp
    lldb/trunk/source/Plugins/Process/Linux/ThreadStateCoordinator.h

Modified: lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp?rev=227909&r1=227908&r2=227909&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp Mon Feb  2 19:50:42 2015
@@ -66,6 +66,7 @@
 #include "Plugins/Process/Utility/LinuxSignals.h"
 #include "NativeThreadLinux.h"
 #include "ProcFileReader.h"
+#include "ThreadStateCoordinator.h"
 #include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
 
 #ifdef __ANDROID__
@@ -149,6 +150,26 @@ namespace
         return signals;
     }
 
+    ThreadStateCoordinator::LogFunction
+    GetThreadLoggerFunction ()
+    {
+        return [](const char *format, va_list args)
+        {
+            Log *const log = GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD);
+            if (log)
+                log->VAPrintf (format, args);
+        };
+    }
+
+    void
+    CoordinatorErrorHandler (const std::string &error_message)
+    {
+        Log *const log = GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD);
+        if (log)
+            log->Printf ("NativePlatformLinux::%s ThreadStateCoordinator error received: %s", __FUNCTION__, error_message.c_str ());
+        assert (false && "ThreadStateCoordinator error reported");
+    }
+
     Error
     ResolveProcessArchitecture (lldb::pid_t pid, Platform &platform, ArchSpec &arch)
     {
@@ -1322,19 +1343,17 @@ NativeProcessLinux::AttachToProcess (
 NativeProcessLinux::NativeProcessLinux () :
     NativeProcessProtocol (LLDB_INVALID_PROCESS_ID),
     m_arch (),
+    m_operation_thread (),
+    m_monitor_thread (),
     m_operation (nullptr),
     m_operation_mutex (),
     m_operation_pending (),
     m_operation_done (),
-    m_wait_for_stop_tids (),
-    m_wait_for_stop_tids_mutex (),
-    m_wait_for_group_stop_tids (),
-    m_group_stop_signal_tid (LLDB_INVALID_THREAD_ID),
-    m_group_stop_signal (LLDB_INVALID_SIGNAL_NUMBER),
-    m_wait_for_group_stop_tids_mutex (),
     m_supports_mem_region (eLazyBoolCalculate),
     m_mem_region_cache (),
-    m_mem_region_cache_mutex ()
+    m_mem_region_cache_mutex (),
+    m_coordinator_up (new ThreadStateCoordinator (GetThreadLoggerFunction ())),
+    m_coordinator_thread ()
 {
 }
 
@@ -1365,7 +1384,7 @@ NativeProcessLinux::LaunchInferior (
     if (module)
         m_arch = module->GetArchitecture ();
 
-    SetState(eStateLaunching);
+    SetState (eStateLaunching);
 
     std::unique_ptr<LaunchArgs> args(
         new LaunchArgs(
@@ -1373,11 +1392,15 @@ NativeProcessLinux::LaunchInferior (
             stdin_path, stdout_path, stderr_path,
             working_dir, launch_info));
 
-    sem_init(&m_operation_pending, 0, 0);
-    sem_init(&m_operation_done, 0, 0);
+    sem_init (&m_operation_pending, 0, 0);
+    sem_init (&m_operation_done, 0, 0);
 
-    StartLaunchOpThread(args.get(), error);
-    if (!error.Success())
+    StartLaunchOpThread (args.get(), error);
+    if (!error.Success ())
+        return;
+
+    error = StartCoordinatorThread ();
+    if (!error.Success ())
         return;
 
 WAIT_AGAIN:
@@ -1397,6 +1420,7 @@ WAIT_AGAIN:
     if (!args->m_error.Success())
     {
         StopOpThread();
+        StopCoordinatorThread ();
         error = args->m_error;
         return;
     }
@@ -1465,6 +1489,10 @@ NativeProcessLinux::AttachToInferior (ll
     if (!error.Success ())
         return;
 
+    error = StartCoordinatorThread ();
+    if (!error.Success ())
+        return;
+
 WAIT_AGAIN:
     // Wait for the operation thread to initialize.
     if (sem_wait (&args->m_semaphore))
@@ -1482,6 +1510,7 @@ WAIT_AGAIN:
     if (!args->m_error.Success ())
     {
         StopOpThread ();
+        StopCoordinatorThread ();
         error = args->m_error;
         return;
     }
@@ -1758,12 +1787,13 @@ NativeProcessLinux::Launch(LaunchArgs *a
     if (log)
         log->Printf ("NativeProcessLinux::%s() adding pid = %" PRIu64, __FUNCTION__, pid);
 
-    thread_sp = monitor->AddThread (static_cast<lldb::tid_t> (pid));
+    thread_sp = monitor->AddThread (pid);
     assert (thread_sp && "AddThread() returned a nullptr thread");
+    monitor->NotifyThreadCreateStopped (pid);
     reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetStoppedBySignal (SIGSTOP);
-    monitor->SetCurrentThreadID (thread_sp->GetID ());
 
     // Let our process instance know the thread has stopped.
+    monitor->SetCurrentThreadID (thread_sp->GetID ());
     monitor->SetState (StateType::eStateStopped);
 
     if (log)
@@ -1800,11 +1830,11 @@ NativeProcessLinux::AttachOpThread(void
 
     if (!Attach(args)) {
         sem_post(&args->m_semaphore);
-        return NULL;
+        return nullptr;
     }
 
     ServeOperation(args);
-    return NULL;
+    return nullptr;
 }
 
 bool
@@ -1886,6 +1916,9 @@ NativeProcessLinux::Attach(AttachArgs *a
                 // Create the thread, mark it as stopped.
                 NativeThreadProtocolSP thread_sp (monitor->AddThread (static_cast<lldb::tid_t> (tid)));
                 assert (thread_sp && "AddThread() returned a nullptr");
+
+                // This will notify this is a new thread and tell the system it is stopped.
+                monitor->NotifyThreadCreateStopped (tid);
                 reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetStoppedBySignal (SIGSTOP);
                 monitor->SetCurrentThreadID (thread_sp->GetID ());
             }
@@ -1996,12 +2029,15 @@ NativeProcessLinux::MonitorCallback(void
         // This is a thread that exited.  Ensure we're not tracking it anymore.
         const bool thread_found = process->StopTrackingThread (pid);
 
+        // Make sure the thread state coordinator knows about this.
+        process->NotifyThreadDeath (pid);
+
         if (is_main_thread)
         {
             // We only set the exit status and notify the delegate if we haven't already set the process
             // state to an exited state.  We normally should have received a SIGTRAP | (PTRACE_EVENT_EXIT << 8)
             // for the main thread.
-            const bool already_notified = (process->GetState() == StateType::eStateExited) | (process->GetState () == StateType::eStateCrashed);
+            const bool already_notified = (process->GetState() == StateType::eStateExited) || (process->GetState () == StateType::eStateCrashed);
             if (!already_notified)
             {
                 if (log)
@@ -2036,11 +2072,24 @@ NativeProcessLinux::MonitorCallback(void
     siginfo_t info;
     int ptrace_err = 0;
 
-    if (!process->GetSignalInfo (pid, &info, ptrace_err))
+    if (process->GetSignalInfo (pid, &info, ptrace_err))
+    {
+        // We have retrieved the signal info.  Dispatch appropriately.
+        if (info.si_signo == SIGTRAP)
+            process->MonitorSIGTRAP(&info, pid);
+        else
+            process->MonitorSignal(&info, pid, exited);
+
+        stop_monitoring = false;
+    }
+    else
     {
         if (ptrace_err == EINVAL)
         {
-            process->OnGroupStop (pid);
+            // This is a group stop reception for this tid.
+            if (log)
+                log->Printf ("NativeThreadLinux::%s received a group stop for pid %" PRIu64 " tid %" PRIu64, __FUNCTION__, process->GetID (), pid);
+            process->NotifyThreadStop (pid);
         }
         else
         {
@@ -2056,6 +2105,9 @@ NativeProcessLinux::MonitorCallback(void
             // Stop tracking the metadata for the thread since it's entirely off the system now.
             const bool thread_found = process->StopTrackingThread (pid);
 
+            // Make sure the thread state coordinator knows about this.
+            process->NotifyThreadDeath (pid);
+
             if (log)
                 log->Printf ("NativeProcessLinux::%s GetSignalInfo failed: %s, tid = %" PRIu64 ", signal = %d, status = %d (%s, %s, %s)",
                              __FUNCTION__, strerror(ptrace_err), pid, signal, status, ptrace_err == ESRCH ? "thread/process killed" : "unknown reason", is_main_thread ? "is main thread" : "is not main thread", thread_found ? "thread metadata removed" : "thread metadata not found");
@@ -2075,16 +2127,6 @@ NativeProcessLinux::MonitorCallback(void
             }
         }
     }
-    else
-    {
-        // We have retrieved the signal info.  Dispatch appropriately.
-        if (info.si_signo == SIGTRAP)
-            process->MonitorSIGTRAP(&info, pid);
-        else
-            process->MonitorSignal(&info, pid, exited);
-
-        stop_monitoring = false;
-    }
 
     return stop_monitoring;
 }
@@ -2117,53 +2159,73 @@ NativeProcessLinux::MonitorSIGTRAP(const
     {
         lldb::tid_t tid = LLDB_INVALID_THREAD_ID;
 
-        unsigned long event_message = 0;
-        if (GetEventMessage(pid, &event_message))
-            tid = static_cast<lldb::tid_t> (event_message);
-
-        if (log)
-            log->Printf ("NativeProcessLinux::%s() pid %" PRIu64 " received thread creation event for tid %" PRIu64, __FUNCTION__, pid, tid);
-
-        // If we don't track the thread yet: create it, mark as stopped.
-        // If we do track it, this is the wait we needed.  Now resume the new thread.
-        // In all cases, resume the current (i.e. main process) thread.
-        bool created_now = false;
-        thread_sp = GetOrCreateThread (tid, created_now);
-        assert (thread_sp.get() && "failed to get or create the tracking data for newly created inferior thread");
+        // The main thread is stopped here.
+        if (thread_sp)
+            reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetStoppedBySignal (SIGTRAP);
+        NotifyThreadStop (pid);
 
-        // If the thread was already tracked, it means the created thread already received its SI_USER notification of creation.
-        if (!created_now)
+        unsigned long event_message = 0;
+        if (GetEventMessage (pid, &event_message))
         {
-            // FIXME loops like we want to stop all theads here.
-            // StopAllThreads
+            tid = static_cast<lldb::tid_t> (event_message);
+            if (log)
+                log->Printf ("NativeProcessLinux::%s() pid %" PRIu64 " received thread creation event for tid %" PRIu64, __FUNCTION__, pid, tid);
 
-            // We can now resume the newly created thread since it is fully created.
-            reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetRunning ();
-            Resume (tid, LLDB_INVALID_SIGNAL_NUMBER);
+            // If we don't track the thread yet: create it, mark as stopped.
+            // If we do track it, this is the wait we needed.  Now resume the new thread.
+            // In all cases, resume the current (i.e. main process) thread.
+            bool created_now = false;
+            NativeThreadProtocolSP new_thread_sp = GetOrCreateThread (tid, created_now);
+            assert (new_thread_sp.get() && "failed to get or create the tracking data for newly created inferior thread");
+
+            // If the thread was already tracked, it means the created thread already received its SI_USER notification of creation.
+            if (!created_now)
+            {
+                // We can now resume the newly created thread since it is fully created.
+                NotifyThreadCreateStopped (tid);
+                m_coordinator_up->RequestThreadResume (tid,
+                                                       [=](lldb::tid_t tid_to_resume)
+                                                       {
+                                                           reinterpret_cast<NativeThreadLinux*> (new_thread_sp.get ())->SetRunning ();
+                                                           Resume (tid_to_resume, LLDB_INVALID_SIGNAL_NUMBER);
+                                                       },
+                                                       CoordinatorErrorHandler);
+            }
+            else
+            {
+                // Mark the thread as currently launching.  Need to wait for SIGTRAP clone on the main thread before
+                // this thread is ready to go.
+                reinterpret_cast<NativeThreadLinux*> (new_thread_sp.get ())->SetLaunching ();
+            }
         }
         else
         {
-            // Mark the thread as currently launching.  Need to wait for SIGTRAP clone on the main thread before
-            // this thread is ready to go.
-            reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetLaunching ();
+            if (log)
+                log->Printf ("NativeProcessLinux::%s() pid %" PRIu64 " received thread creation event but GetEventMessage failed so we don't know the new tid", __FUNCTION__, pid);
         }
 
         // In all cases, we can resume the main thread here.
-        Resume (pid, LLDB_INVALID_SIGNAL_NUMBER);
+        m_coordinator_up->RequestThreadResume (pid,
+                                               [=](lldb::tid_t tid_to_resume)
+                                               {
+                                                   reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetRunning ();
+                                                   Resume (tid_to_resume, LLDB_INVALID_SIGNAL_NUMBER);
+                                               },
+                                               CoordinatorErrorHandler);
+
         break;
     }
 
     case (SIGTRAP | (PTRACE_EVENT_EXEC << 8)):
     {
         NativeThreadProtocolSP main_thread_sp;
-
         if (log)
             log->Printf ("NativeProcessLinux::%s() received exec event, code = %d", __FUNCTION__, info->si_code ^ SIGTRAP);
 
-        // Remove all but the main thread here.
-        // FIXME check if we really need to do this - how does ptrace behave under exec when multiple threads were present
-        // before the exec?  If we get all the detach signals right, we don't need to do this.  However, it makes it clearer
-        // what we should really be tracking.
+        // The thread state coordinator needs to reset due to the exec.
+        m_coordinator_up->ResetForExec ();
+
+        // Remove all but the main thread here.  Linux fork creates a new process which only copies the main thread.  Mutexes are in undefined state.
         {
             Mutex::Locker locker (m_threads_mutex);
 
@@ -2181,6 +2243,7 @@ NativeProcessLinux::MonitorSIGTRAP(const
                 }
                 else
                 {
+                    // Tell thread coordinator this thread is dead.
                     if (log)
                         log->Printf ("NativeProcessLinux::%s discarding non-main-thread tid %" PRIu64 " due to exec", __FUNCTION__, thread_sp->GetID ());
                 }
@@ -2202,11 +2265,19 @@ NativeProcessLinux::MonitorSIGTRAP(const
             }
         }
 
+        // Tell coordinator about about the "new" (since exec) stopped main thread.
+        const lldb::tid_t main_thread_tid = GetID ();
+        NotifyThreadCreateStopped (main_thread_tid);
+
+        // NOTE: ideally these next statements would execute at the same time as the coordinator thread create was executed.
+        // Consider a handler that can execute when that happens.
         // Let our delegate know we have just exec'd.
         NotifyDidExec ();
 
         // If we have a main thread, indicate we are stopped.
         assert (main_thread_sp && "exec called during ptraced process but no main thread metadata tracked");
+
+        // Let the process know we're stopped.
         SetState (StateType::eStateStopped);
 
         break;
@@ -2215,6 +2286,10 @@ NativeProcessLinux::MonitorSIGTRAP(const
     case (SIGTRAP | (PTRACE_EVENT_EXIT << 8)):
     {
         // The inferior process or one of its threads is about to exit.
+
+        // This thread is currently stopped.  It's not actually dead yet, just about to be.
+        NotifyThreadStop (pid);
+
         unsigned long data = 0;
         if (!GetEventMessage(pid, &data))
             data = -1;
@@ -2228,22 +2303,30 @@ NativeProcessLinux::MonitorSIGTRAP(const
                     is_main_thread ? "is main thread" : "not main thread");
         }
 
-        // Set the thread to exited.
-        if (thread_sp)
-            reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetExited ();
-        else
-        {
-            if (log)
-                log->Printf ("NativeProcessLinux::%s() pid %" PRIu64 " failed to retrieve thread for tid %" PRIu64", cannot set thread state", __FUNCTION__, GetID (), pid);
-        }
-
+        // We'll set the thread to exited later...
+//        if (thread_sp)
+//            reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetExited ();
+//        else
+//        {
+//            if (log)
+//                log->Printf ("NativeProcessLinux::%s() pid %" PRIu64 " failed to retrieve thread for tid %" PRIu64", cannot set thread state", __FUNCTION__, GetID (), pid);
+//        }
+
+        // FIXME: review if this is the spot, or the follow up, which tells us the real exit code.
+        // If it's this one, we need to track it or set it here.  Setting it here is not really in the
+        // right time flow though unless we skip the follow up.
         if (is_main_thread)
         {
             SetExitStatus (convert_pid_status_to_exit_type (data), convert_pid_status_to_return_code (data), nullptr, true);
         }
 
-        // Resume the thread so it completely exits.
-        Resume (pid, LLDB_INVALID_SIGNAL_NUMBER);
+        m_coordinator_up->RequestThreadResume (pid,
+                                               [=](lldb::tid_t tid_to_resume)
+                                               {
+                                                   reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetRunning ();
+                                                   Resume (tid_to_resume, LLDB_INVALID_SIGNAL_NUMBER);
+                                               },
+                                               CoordinatorErrorHandler);
 
         break;
     }
@@ -2254,10 +2337,12 @@ NativeProcessLinux::MonitorSIGTRAP(const
         if (log)
             log->Printf ("NativeProcessLinux::%s() received trace event, pid = %" PRIu64 " (single stepping)", __FUNCTION__, pid);
 
+        // This thread is currently stopped.
+        NotifyThreadStop (pid);
+
         if (thread_sp)
         {
             reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetStoppedBySignal (SIGTRAP);
-            SetCurrentThreadID (thread_sp->GetID ());
         }
         else
         {
@@ -2265,8 +2350,14 @@ NativeProcessLinux::MonitorSIGTRAP(const
                 log->Printf ("NativeProcessLinux::%s() pid %" PRIu64 " tid %" PRIu64 " single stepping received trace but thread not found", __FUNCTION__, GetID (), pid);
         }
 
-        // Tell the process we have a stop (from single stepping).
-        SetState (StateType::eStateStopped, true);
+        // We need to tell all other running threads before we notify the delegate about this stop.
+        CallAfterRunningThreadsStop (pid,
+                                     [=](lldb::tid_t deferred_notification_tid)
+                                     {
+                                         SetCurrentThreadID (deferred_notification_tid);
+                                         // Tell the process we have a stop (from single stepping).
+                                         SetState (StateType::eStateStopped, true);
+                                     });
         break;
 
     case SI_KERNEL:
@@ -2274,6 +2365,9 @@ NativeProcessLinux::MonitorSIGTRAP(const
         if (log)
             log->Printf ("NativeProcessLinux::%s() received breakpoint event, pid = %" PRIu64, __FUNCTION__, pid);
 
+        // This thread is currently stopped.
+        NotifyThreadStop (pid);
+
         // Mark the thread as stopped at breakpoint.
         if (thread_sp)
         {
@@ -2292,15 +2386,23 @@ NativeProcessLinux::MonitorSIGTRAP(const
         }
 
 
-        // Tell the process we have a stop from this thread.
-        SetCurrentThreadID (pid);
-        SetState (StateType::eStateStopped, true);
+        // We need to tell all other running threads before we notify the delegate about this stop.
+        CallAfterRunningThreadsStop (pid,
+                                     [=](lldb::tid_t deferred_notification_tid)
+                                     {
+                                         SetCurrentThreadID (deferred_notification_tid);
+                                         // Tell the process we have a stop (from software breakpoint).
+                                         SetState (StateType::eStateStopped, true);
+                                     });
         break;
 
     case TRAP_HWBKPT:
         if (log)
             log->Printf ("NativeProcessLinux::%s() received watchpoint event, pid = %" PRIu64, __FUNCTION__, pid);
 
+        // This thread is currently stopped.
+        NotifyThreadStop (pid);
+
         // Mark the thread as stopped at watchpoint.
         // The address is at (lldb::addr_t)info->si_addr if we need it.
         if (thread_sp)
@@ -2311,17 +2413,35 @@ NativeProcessLinux::MonitorSIGTRAP(const
                 log->Printf ("NativeProcessLinux::%s() pid %" PRIu64 " tid %" PRIu64 ": warning, cannot process hardware breakpoint since no thread metadata", __FUNCTION__, GetID (), pid);
         }
 
-        // Tell the process we have a stop from this thread.
-        SetCurrentThreadID (pid);
-        SetState (StateType::eStateStopped, true);
+        // We need to tell all other running threads before we notify the delegate about this stop.
+        CallAfterRunningThreadsStop (pid,
+                                     [=](lldb::tid_t deferred_notification_tid)
+                                     {
+                                         SetCurrentThreadID (deferred_notification_tid);
+                                         // Tell the process we have a stop (from hardware breakpoint).
+                                         SetState (StateType::eStateStopped, true);
+                                     });
         break;
 
     case SIGTRAP:
     case (SIGTRAP | 0x80):
         if (log)
-            log->Printf ("NativeProcessLinux::%s() received system call stop event, pid %" PRIu64 "tid %" PRIu64, __FUNCTION__, GetID (), pid);
+            log->Printf ("NativeProcessLinux::%s() received unknown SIGTRAP system call stop event, pid %" PRIu64 "tid %" PRIu64 ", resuming", __FUNCTION__, GetID (), pid);
+
+        // This thread is currently stopped.
+        NotifyThreadStop (pid);
+        if (thread_sp)
+            reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetStoppedBySignal (SIGTRAP);
+
+            
         // Ignore these signals until we know more about them.
-        Resume(pid, 0);
+        m_coordinator_up->RequestThreadResume (pid,
+                                               [=](lldb::tid_t tid_to_resume)
+                                               {
+                                                   reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetRunning ();
+                                                   Resume (tid_to_resume, LLDB_INVALID_SIGNAL_NUMBER);
+                                               },
+                                               CoordinatorErrorHandler);
         break;
 
     default:
@@ -2393,9 +2513,15 @@ NativeProcessLinux::MonitorSignal(const
         // If the thread was already tracked, it means the main thread already received its SIGTRAP for the create.
         if (!created_now)
         {
-            // We can now resume this thread up since it is fully created.
-            reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetRunning ();
-            Resume (thread_sp->GetID (), LLDB_INVALID_SIGNAL_NUMBER);
+            // We can now resume the newly created thread since it is fully created.
+            NotifyThreadCreateStopped (pid);
+            m_coordinator_up->RequestThreadResume (pid,
+                                                   [=](lldb::tid_t tid_to_resume)
+                                                   {
+                                                       reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetRunning ();
+                                                       Resume (tid_to_resume, LLDB_INVALID_SIGNAL_NUMBER);
+                                                   },
+                                                   CoordinatorErrorHandler);
         }
         else
         {
@@ -2414,35 +2540,18 @@ NativeProcessLinux::MonitorSignal(const
         // This is a tgkill()-based stop.
         if (thread_sp)
         {
+            if (log)
+                log->Printf ("NativeProcessLinux::%s() pid %" PRIu64 " tid %" PRIu64 ", thread stopped",
+                             __FUNCTION__,
+                             GetID (),
+                             pid);
+
             // An inferior thread just stopped.  Mark it as such.
             reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetStoppedBySignal (signo);
             SetCurrentThreadID (thread_sp->GetID ());
 
-            // Remove this tid from the wait-for-stop set.
-            Mutex::Locker locker (m_wait_for_stop_tids_mutex);
-
-            auto removed_count = m_wait_for_stop_tids.erase (thread_sp->GetID ());
-            if (removed_count < 1)
-            {
-                log->Printf ("NativeProcessLinux::%s() pid = %" PRIu64 " tid %" PRIu64 ": tgkill()-stopped thread not in m_wait_for_stop_tids",
-                             __FUNCTION__, GetID (), thread_sp->GetID ());
-
-            }
-
-            // If this is the last thread in the m_wait_for_stop_tids, we need to notify
-            // the delegate that a stop has occurred now that every thread that was supposed
-            // to stop has stopped.
-            if (m_wait_for_stop_tids.empty ())
-            {
-                if (log)
-                {
-                    log->Printf ("NativeProcessLinux::%s() pid %" PRIu64 " tid %" PRIu64 ", setting process state to stopped now that all tids marked for stop have completed",
-                                 __FUNCTION__,
-                                 GetID (),
-                                 pid);
-                }
-                SetState (StateType::eStateStopped, true);
-            }
+            // Tell the thread state coordinator about the stop.
+            NotifyThreadStop (thread_sp->GetID ());
         }
 
         // Done handling.
@@ -2455,70 +2564,51 @@ NativeProcessLinux::MonitorSignal(const
     switch (signo)
     {
     case SIGSEGV:
-        {
-            lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr);
-
-            // FIXME figure out how to propagate this properly.  Seems like it
-            // should go in ThreadStopInfo.
-            // We can get more details on the exact nature of the crash here.
-            // ProcessMessage::CrashReason reason = GetCrashReasonForSIGSEGV(info);
-            if (!exited)
-            {
-                // This is just a pre-signal-delivery notification of the incoming signal.
-                // Send a stop to the debugger.
-                if (thread_sp)
-                {
-                    reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetStoppedBySignal (signo);
-                    SetCurrentThreadID (thread_sp->GetID ());
-                }
-                SetState (StateType::eStateStopped, true);
-            }
-            else
-            {
-                if (thread_sp)
-                {
-                    // FIXME figure out what type this is.
-                    const uint64_t exception_type = static_cast<uint64_t> (SIGSEGV);
-                    reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetCrashedWithException (exception_type, fault_addr);
-                }
-                SetState (StateType::eStateCrashed, true);
-            }
-        }
-        break;
-
     case SIGABRT:
     case SIGILL:
     case SIGFPE:
     case SIGBUS:
         {
-            // Break these out into separate cases once I have more data for each type of signal.
-            lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr);
+            // This thread is stopped.
+            NotifyThreadStop (pid);
+
+            // lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr);
+
+            // This is just a pre-signal-delivery notification of the incoming signal.
+            if (thread_sp)
+                reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetStoppedBySignal (signo);
+
+            // We can get more details on the exact nature of the crash here.
+            // ProcessMessage::CrashReason reason = GetCrashReasonForSIGSEGV(info);
             if (!exited)
             {
-                // This is just a pre-signal-delivery notification of the incoming signal.
-                // Send a stop to the debugger.
-                if (thread_sp)
-                {
-                    reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetStoppedBySignal (signo);
-                    SetCurrentThreadID (thread_sp->GetID ());
-                }
-                SetState (StateType::eStateStopped, true);
+                // Send a stop to the debugger after we get all other threads to stop.
+                CallAfterRunningThreadsStop (pid,
+                                             [=] (lldb::tid_t signaling_tid)
+                                             {
+                                                 SetCurrentThreadID (signaling_tid);
+                                                 SetState (StateType::eStateStopped, true);
+                                             });
             }
             else
             {
-                if (thread_sp)
-                {
-                    // FIXME figure out how to report exit by signal correctly.
-                    const uint64_t exception_type = static_cast<uint64_t> (SIGABRT);
-                    reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetCrashedWithException (exception_type, fault_addr);
-                }
-                SetState (StateType::eStateCrashed, true);
+                // FIXME the process might die right after this - might not ever get stops on any other threads.
+                // Send a stop to the debugger after we get all other threads to stop.
+                CallAfterRunningThreadsStop (pid,
+                                             [=] (lldb::tid_t signaling_tid)
+                                             {
+                                                 SetCurrentThreadID (signaling_tid);
+                                                 SetState (StateType::eStateCrashed, true);
+                                             });
             }
         }
         break;
 
     case SIGSTOP:
         {
+            // This thread is stopped.
+            NotifyThreadStop (pid);
+
             if (log)
             {
                 if (is_from_llgs)
@@ -2527,167 +2617,50 @@ NativeProcessLinux::MonitorSignal(const
                     log->Printf ("NativeProcessLinux::%s pid = %" PRIu64 " tid %" PRIu64 " received SIGSTOP from outside of debugger", __FUNCTION__, GetID (), pid);
             }
 
-            // Save group stop tids to wait for.
-            SetGroupStopTids (pid, SIGSTOP);
-            // Fall through to deliver signal to thread.
-            // This will trigger a group stop sequence, after which we'll notify the process that everything stopped.
+            // Resume this thread to get the group-stop mechanism to fire off the true group stops.
+            // This thread will get stopped again as part of the group-stop completion.
+            m_coordinator_up->RequestThreadResume (pid,
+                                                   [=](lldb::tid_t tid_to_resume)
+                                                   {
+                                                       reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetRunning ();
+                                                       // Pass this signal number on to the inferior to handle.
+                                                       Resume (tid_to_resume, signo);
+                                                   },
+                                                   CoordinatorErrorHandler);
+
+            // And now we want to signal that we received a SIGSTOP on this thread
+            // as soon as all running threads stop (i.e. the group stop sequence completes).
+            CallAfterRunningThreadsStop (pid,
+                                         [=] (lldb::tid_t signaling_tid)
+                                         {
+                                             SetCurrentThreadID (signaling_tid);
+                                             SetState (StateType::eStateStopped, true);
+                                         });
+            break;
         }
 
     default:
         {
+            // This thread is stopped.
+            NotifyThreadStop (pid);
+
             if (log)
                 log->Printf ("NativeProcessLinux::%s pid = %" PRIu64 " tid %" PRIu64 " resuming thread with signal %s (%d)", __FUNCTION__, GetID (), pid, GetUnixSignals().GetSignalAsCString (signo), signo);
 
             // Pass the signal on to the inferior.
-            const bool resume_success = Resume (pid, signo);
-
-            if (log)
-                log->Printf ("NativeProcessLinux::%s pid = %" PRIu64 " tid %" PRIu64 " resume %s", __FUNCTION__, GetID (), pid, resume_success ? "SUCCESS" : "FAILURE");
-
+            m_coordinator_up->RequestThreadResume (pid,
+                                                   [=](lldb::tid_t tid_to_resume)
+                                                   {
+                                                       reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetRunning ();
+                                                       // Pass this signal number on to the inferior to handle.
+                                                       Resume (tid_to_resume, signo);
+                                                   },
+                                                   CoordinatorErrorHandler);
         }
         break;
     }
 }
 
-void
-NativeProcessLinux::SetGroupStopTids (lldb::tid_t signaled_thread_tid, int signo)
-{
-    Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
-
-    // Lock 1 - thread lock.
-    {
-        Mutex::Locker locker (m_threads_mutex);
-        // Lock 2 - group stop tids
-        {
-            Mutex::Locker locker (m_wait_for_group_stop_tids_mutex);
-            if (log)
-                log->Printf ("NativeProcessLinux::%s pid = %" PRIu64 " tid %" PRIu64 " loading up known threads in set%s",
-                             __FUNCTION__,
-                             GetID (),
-                             signaled_thread_tid,
-                             m_wait_for_group_stop_tids.empty () ? " (currently empty)"
-                                : "(group_stop_tids not empty?!?)");
-
-            // Add all known threads not already stopped into the wait for group-stop tids.
-            for (auto thread_sp : m_threads)
-            {
-                int unused_signo = LLDB_INVALID_SIGNAL_NUMBER;
-                if (thread_sp && !((NativeThreadLinux*)thread_sp.get())->IsStopped (&unused_signo))
-                {
-                    // Wait on this thread for a group stop before we notify the delegate about the process state change.
-                    m_wait_for_group_stop_tids.insert (thread_sp->GetID ());
-                }
-            }
-
-            m_group_stop_signal_tid = signaled_thread_tid;
-            m_group_stop_signal = signo;
-        }
-    }
-}
-
-void
-NativeProcessLinux::OnGroupStop (lldb::tid_t tid)
-{
-    Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
-    bool should_tell_delegate = false;
-
-    // Lock 1 - thread lock.
-    {
-        Mutex::Locker locker (m_threads_mutex);
-        // Lock 2 - group stop tids
-        {
-            Mutex::Locker locker (m_wait_for_group_stop_tids_mutex);
-
-            // Remove this thread from the set.
-            auto remove_result = m_wait_for_group_stop_tids.erase (tid);
-            if (log)
-                log->Printf ("NativeProcessLinux::%s pid = %" PRIu64 " tid %" PRIu64 " tried to remove tid from group-stop set: %s",
-                             __FUNCTION__,
-                             GetID (),
-                             tid,
-                             remove_result > 0 ? "SUCCESS" : "FAILURE");
-
-            // Grab the thread metadata for this thread.
-            NativeThreadProtocolSP thread_sp = GetThreadByIDUnlocked (tid);
-            if (thread_sp)
-            {
-                NativeThreadLinux *const linux_thread = static_cast<NativeThreadLinux*> (thread_sp.get ());
-                if (thread_sp->GetID () == m_group_stop_signal_tid)
-                {
-                    linux_thread->SetStoppedBySignal (m_group_stop_signal);
-                    if (log)
-                        log->Printf ("NativeProcessLinux::%s pid = %" PRIu64 " tid %" PRIu64 " set group stop tid to state 'stopped by signal %d'",
-                                     __FUNCTION__,
-                                     GetID (),
-                                     tid,
-                                     m_group_stop_signal);
-                }
-                else
-                {
-                    int stopping_signal = LLDB_INVALID_SIGNAL_NUMBER;
-                    if (linux_thread->IsStopped (&stopping_signal))
-                    {
-                        if (log)
-                            log->Printf ("NativeProcessLinux::%s pid = %" PRIu64 " tid %" PRIu64 " thread is already stopped with signal %d, not clearing",
-                                         __FUNCTION__,
-                                         GetID (),
-                                         tid,
-                                         stopping_signal);
-
-                    }
-                    else
-                    {
-                        linux_thread->SetStoppedBySignal (0);
-                        if (log)
-                            log->Printf ("NativeProcessLinux::%s pid = %" PRIu64 " tid %" PRIu64 " set stopped by signal with signal 0 (i.e. debugger-initiated stop)",
-                                         __FUNCTION__,
-                                         GetID (),
-                                         tid);
-
-                    }
-                }
-            }
-            else
-            {
-                if (log)
-                    log->Printf ("NativeProcessLinux::%s pid = %" PRIu64 " tid %" PRIu64 " WARNING failed to find thread metadata for tid",
-                                 __FUNCTION__,
-                                 GetID (),
-                                 tid);
-
-            }
-
-            // If there are no more threads we're waiting on for group stop, signal the process.
-            if (m_wait_for_group_stop_tids.empty ())
-            {
-                if (log)
-                    log->Printf ("NativeProcessLinux::%s pid = %" PRIu64 " tid %" PRIu64 " done waiting for group stop, will notify delegate of process state change",
-                                 __FUNCTION__,
-                                 GetID (),
-                                 tid);
-
-                SetCurrentThreadID (m_group_stop_signal_tid);
-
-                // Tell the delegate about the stop event, after we release our mutexes.
-                should_tell_delegate = true;
-            }
-        }
-    }
-
-    // If we're ready to broadcast the process event change, do it now that we're no longer
-    // holding any locks.  Note this does introduce a potential race, we should think about
-    // adding a notification queue.
-    if (should_tell_delegate)
-    {
-        if (log)
-            log->Printf ("NativeProcessLinux::%s pid = %" PRIu64 " tid %" PRIu64 " done waiting for group stop, notifying delegate of process state change",
-                         __FUNCTION__,
-                         GetID (),
-                         tid);
-        SetState (StateType::eStateStopped, true);
-    }
-}
-
 Error
 NativeProcessLinux::Resume (const ResumeActionList &resume_actions)
 {
@@ -2697,119 +2670,87 @@ NativeProcessLinux::Resume (const Resume
     if (log)
         log->Printf ("NativeProcessLinux::%s called: pid %" PRIu64, __FUNCTION__, GetID ());
 
-    int run_thread_count = 0;
-    int stop_thread_count = 0;
-    int step_thread_count = 0;
+    int stop_thread_id = LLDB_INVALID_THREAD_ID;
 
     std::vector<NativeThreadProtocolSP> new_stop_threads;
 
-    Mutex::Locker locker (m_threads_mutex);
-    for (auto thread_sp : m_threads)
+    // Scope for threads mutex.
     {
-        assert (thread_sp && "thread list should not contain NULL threads");
-        NativeThreadLinux *const linux_thread_p = reinterpret_cast<NativeThreadLinux*> (thread_sp.get ());
-
-        const ResumeAction *const action = resume_actions.GetActionForThread (thread_sp->GetID (), true);
-        assert (action && "NULL ResumeAction returned for thread during Resume ()");
-
-        if (log)
+        Mutex::Locker locker (m_threads_mutex);
+        for (auto thread_sp : m_threads)
         {
-            log->Printf ("NativeProcessLinux::%s processing resume action state %s for pid %" PRIu64 " tid %" PRIu64, 
-                    __FUNCTION__, StateAsCString (action->state), GetID (), thread_sp->GetID ());
-        }
+            assert (thread_sp && "thread list should not contain NULL threads");
+            NativeThreadLinux *const linux_thread_p = reinterpret_cast<NativeThreadLinux*> (thread_sp.get ());
 
-        switch (action->state)
-        {
-        case eStateRunning:
-            // Run the thread, possibly feeding it the signal.
-            linux_thread_p->SetRunning ();
-            if (action->signal > 0)
-            {
-                // Resume the thread and deliver the given signal,
-                // then mark as delivered.
-                Resume (thread_sp->GetID (), action->signal);
-                resume_actions.SetSignalHandledForThread (thread_sp->GetID ());
-            }
-            else
+            const ResumeAction *const action = resume_actions.GetActionForThread (thread_sp->GetID (), true);
+            assert (action && "NULL ResumeAction returned for thread during Resume ()");
+
+            if (log)
             {
-                // Just resume the thread with no signal.
-                Resume (thread_sp->GetID (), LLDB_INVALID_SIGNAL_NUMBER);
+                log->Printf ("NativeProcessLinux::%s processing resume action state %s for pid %" PRIu64 " tid %" PRIu64, 
+                        __FUNCTION__, StateAsCString (action->state), GetID (), thread_sp->GetID ());
             }
-            ++run_thread_count;
-            break;
 
-        case eStateStepping:
-            // Note: if we have multiple threads, we may need to stop
-            // the other threads first, then step this one.
-            linux_thread_p->SetStepping ();
-            if (SingleStep (thread_sp->GetID (), 0))
+            switch (action->state)
             {
-                if (log)
-                    log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " tid %" PRIu64 " single step succeeded",
-                                 __FUNCTION__, GetID (), thread_sp->GetID ());
-            }
-            else
+            case eStateRunning:
             {
-                if (log)
-                    log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " tid %" PRIu64 " single step failed",
-                                 __FUNCTION__, GetID (), thread_sp->GetID ());
+                // Run the thread, possibly feeding it the signal.
+                const int signo = action->signal;
+                m_coordinator_up->RequestThreadResume (thread_sp->GetID (),
+                                                       [=](lldb::tid_t tid_to_resume)
+                                                       {
+                                                           reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetRunning ();
+                                                           // Pass this signal number on to the inferior to handle.
+                                                           Resume (tid_to_resume, (signo > 0) ? signo : LLDB_INVALID_SIGNAL_NUMBER);
+                                                       },
+                                                       CoordinatorErrorHandler);
+                break;
             }
-            ++step_thread_count;
-            break;
 
-        case eStateSuspended:
-        case eStateStopped:
-            if (!StateIsStoppedState (linux_thread_p->GetState (), false))
-                new_stop_threads.push_back (thread_sp);
-            else
-            {
-                if (log)
-                    log->Printf ("NativeProcessLinux::%s no need to stop pid %" PRIu64 " tid %" PRIu64 ", thread state already %s",
-                                 __FUNCTION__, GetID (), thread_sp->GetID (), StateAsCString (linux_thread_p->GetState ()));
-            }
+            case eStateStepping:
+                linux_thread_p->SetStepping ();
+                if (SingleStep (thread_sp->GetID (), 0))
+                {
+                    if (log)
+                        log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " tid %" PRIu64 " single step succeeded",
+                                     __FUNCTION__, GetID (), thread_sp->GetID ());
+                }
+                else
+                {
+                    if (log)
+                        log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " tid %" PRIu64 " single step failed",
+                                     __FUNCTION__, GetID (), thread_sp->GetID ());
+                }
+                break;
 
-            ++stop_thread_count;
-            break;
+            case eStateSuspended:
+            case eStateStopped:
+                // if we haven't chosen a stop thread id yet, use this one.
+                if (stop_thread_id == LLDB_INVALID_THREAD_ID)
+                    stop_thread_id = thread_sp->GetID ();
+                break;
 
-        default:
-            return Error ("NativeProcessLinux::%s (): unexpected state %s specified for pid %" PRIu64 ", tid %" PRIu64,
-                    __FUNCTION__, StateAsCString (action->state), GetID (), thread_sp->GetID ());
+            default:
+                return Error ("NativeProcessLinux::%s (): unexpected state %s specified for pid %" PRIu64 ", tid %" PRIu64,
+                        __FUNCTION__, StateAsCString (action->state), GetID (), thread_sp->GetID ());
+            }
         }
     }
 
-    // If any thread was set to run, notify the process state as running.
-    if (run_thread_count > 0)
-        SetState (StateType::eStateRunning, true);
+    // We don't need to tell the delegate when we're running, so don't do that here.
 
-    // Now do a tgkill SIGSTOP on each thread we want to stop.
-    if (!new_stop_threads.empty ())
+    // If we had any thread stopping, then do a deferred notification of the chosen stop thread id and signal
+    // after all other running threads have stopped.
+    if (stop_thread_id != LLDB_INVALID_THREAD_ID)
     {
-        // Lock the m_wait_for_stop_tids set so we can fill it with every thread we expect to have stopped.
-        Mutex::Locker stop_thread_id_locker (m_wait_for_stop_tids_mutex);
-        for (auto thread_sp : new_stop_threads)
-        {
-            // Send a stop signal to the thread.
-            const int result = tgkill (GetID (), thread_sp->GetID (), SIGSTOP);
-            if (result != 0)
-            {
-                // tgkill failed.
-                if (log)
-                    log->Printf ("NativeProcessLinux::%s error: tgkill SIGSTOP for pid %" PRIu64 " tid %" PRIu64 "failed, retval %d",
-                                 __FUNCTION__, GetID (), thread_sp->GetID (), result);
-            }
-            else
-            {
-                // tgkill succeeded.  Don't mark the thread state, though.  Let the signal
-                // handling mark it.
-                if (log)
-                    log->Printf ("NativeProcessLinux::%s tgkill SIGSTOP for pid %" PRIu64 " tid %" PRIu64 " succeeded",
-                                 __FUNCTION__, GetID (), thread_sp->GetID ());
-
-                // Add it to the set of threads we expect to signal a stop.
-                // We won't tell the delegate about it until this list drains to empty.
-                m_wait_for_stop_tids.insert (thread_sp->GetID ());
-            }
-        }
+        CallAfterRunningThreadsStop (stop_thread_id,
+                                     [=](lldb::tid_t deferred_notification_tid)
+                                     {
+                                         SetCurrentThreadID (deferred_notification_tid);
+                                         // Tell the process we have a stop.
+                                         SetState (StateType::eStateStopped, true);
+                                     });
     }
 
     return error;
@@ -2820,11 +2761,6 @@ NativeProcessLinux::Halt ()
 {
     Error error;
 
-    // FIXME check if we're already stopped
-    const bool is_stopped = false;
-    if (is_stopped)
-        return error;
-
     if (kill (GetID (), SIGSTOP) != 0)
         error.SetErrorToErrno ();
 
@@ -3635,6 +3571,7 @@ NativeProcessLinux::StopMonitor()
 {
     StopMonitoringChildProcess();
     StopOpThread();
+    StopCoordinatorThread ();
     sem_destroy(&m_operation_pending);
     sem_destroy(&m_operation_done);
 
@@ -3655,6 +3592,69 @@ NativeProcessLinux::StopOpThread()
     m_operation_thread.Join(nullptr);
 }
 
+Error
+NativeProcessLinux::StartCoordinatorThread ()
+{
+    Error error;
+    static const char *g_thread_name = "lldb.process.linux.ts_coordinator";
+    Log *const log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+
+    // Skip if thread is already running
+    if (m_coordinator_thread.IsJoinable())
+    {
+        error.SetErrorString ("ThreadStateCoordinator's run loop is already running");
+        if (log)
+            log->Printf ("NativeProcessLinux::%s %s", __FUNCTION__, error.AsCString ());
+        return error;
+    }
+
+    // Enable verbose logging if lldb thread logging is enabled.
+    m_coordinator_up->LogEnableEventProcessing (log != nullptr);
+
+    if (log)
+        log->Printf ("NativeProcessLinux::%s launching ThreadStateCoordinator thread for pid %" PRIu64, __FUNCTION__, GetID ());
+    m_coordinator_thread = ThreadLauncher::LaunchThread(g_thread_name, CoordinatorThread, this, &error);
+    return error;
+}
+
+void *
+NativeProcessLinux::CoordinatorThread (void *arg)
+{
+    Log *const log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+
+    NativeProcessLinux *const process = static_cast<NativeProcessLinux*> (arg);
+    assert (process && "null process passed to CoordinatorThread");
+    if (!process)
+    {
+        if (log)
+            log->Printf ("NativeProcessLinux::%s null process, exiting ThreadStateCoordinator processing loop", __FUNCTION__);
+        return nullptr;
+    }
+
+    // Run the thread state coordinator loop until it is done.  This call uses
+    // efficient waiting for an event to be ready.
+    while (process->m_coordinator_up->ProcessNextEvent () == ThreadStateCoordinator::eventLoopResultContinue)
+    {
+    }
+
+    if (log)
+        log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " exiting ThreadStateCoordinator processing loop due to coordinator indicating completion", __FUNCTION__, process->GetID ());
+
+    return nullptr;
+}
+
+void
+NativeProcessLinux::StopCoordinatorThread()
+{
+    Log *const log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+    if (log)
+        log->Printf ("NativeProcessLinux::%s requesting ThreadStateCoordinator stop for pid %" PRIu64, __FUNCTION__, GetID ());
+
+    // Tell the coordinator we're done.  This will cause the coordinator
+    // run loop thread to exit when the processing queue hits this message.
+    m_coordinator_up->StopCoordinator ();
+}
+
 bool
 NativeProcessLinux::HasThreadNoLock (lldb::tid_t thread_id)
 {
@@ -3869,3 +3869,37 @@ NativeProcessLinux::FixupBreakpointPCAsN
 
     return error;
 }
+
+void
+NativeProcessLinux::NotifyThreadCreateStopped (lldb::tid_t tid)
+{
+    const bool is_stopped = true;
+    m_coordinator_up->NotifyThreadCreate (tid, is_stopped, CoordinatorErrorHandler);
+}
+
+void
+NativeProcessLinux::NotifyThreadDeath (lldb::tid_t tid)
+{
+    m_coordinator_up->NotifyThreadDeath (tid, CoordinatorErrorHandler);
+}
+
+void
+NativeProcessLinux::NotifyThreadStop (lldb::tid_t tid)
+{
+    m_coordinator_up->NotifyThreadStop (tid, CoordinatorErrorHandler);
+}
+
+void
+NativeProcessLinux::CallAfterRunningThreadsStop (lldb::tid_t tid,
+                                                 const std::function<void (lldb::tid_t tid)> &call_after_function)
+{
+    const lldb::pid_t pid = GetID ();
+    m_coordinator_up->CallAfterRunningThreadsStop (pid,
+                                                   [=](lldb::tid_t request_stop_tid)
+                                                   {
+                                                       tgkill (pid, request_stop_tid, SIGSTOP);
+                                                   },
+                                                   call_after_function,
+                                                   CoordinatorErrorHandler);
+
+}

Modified: lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h?rev=227909&r1=227908&r2=227909&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h (original)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h Mon Feb  2 19:50:42 2015
@@ -31,6 +31,7 @@ namespace lldb_private
 {
     class Error;
     class Module;
+    class ThreadStateCoordinator;
     class Scalar;
 
     /// @class NativeProcessLinux
@@ -183,21 +184,12 @@ namespace lldb_private
         sem_t m_operation_pending;
         sem_t m_operation_done;
 
-        // Set of tids we're waiting to stop before we notify the delegate of
-        // the stopped state.  We only notify the delegate after all threads
-        // ordered to stop have signaled their stop.
-        std::unordered_set<lldb::tid_t> m_wait_for_stop_tids;
-        lldb_private::Mutex m_wait_for_stop_tids_mutex;
-
-        std::unordered_set<lldb::tid_t> m_wait_for_group_stop_tids;
-        lldb::tid_t m_group_stop_signal_tid;
-        int m_group_stop_signal;
-        lldb_private::Mutex m_wait_for_group_stop_tids_mutex;
-
         lldb_private::LazyBool m_supports_mem_region;
         std::vector<MemoryRegionInfo> m_mem_region_cache;
         lldb_private::Mutex m_mem_region_cache_mutex;
 
+        std::unique_ptr<ThreadStateCoordinator> m_coordinator_up;
+        HostThread m_coordinator_thread;
 
         struct OperationArgs
         {
@@ -334,6 +326,15 @@ namespace lldb_private
         void
         StopOpThread();
 
+        Error
+        StartCoordinatorThread ();
+
+        static void*
+        CoordinatorThread (void *arg);
+
+        void
+        StopCoordinatorThread ();
+
         /// Stops monitoring the child process thread.
         void
         StopMonitor();
@@ -380,16 +381,22 @@ namespace lldb_private
         bool
         SingleStep(lldb::tid_t tid, uint32_t signo);
 
-        /// Safely mark all existing threads as waiting for group stop.
-        /// When the final group stop comes in from the set of group stop threads,
-        /// we'll mark the current thread as signaled_thread_tid and set its stop
-        /// reason as the given signo.  All other threads from group stop notification
-        /// will have thread stop reason marked as signaled with no signo.
+        // ThreadStateCoordinator helper methods.
+        void
+        NotifyThreadCreateStopped (lldb::tid_t tid);
+
+        void
+        NotifyThreadCreateRunning (lldb::tid_t tid);
+
+        void
+        NotifyThreadDeath (lldb::tid_t tid);
+
         void
-        SetGroupStopTids (lldb::tid_t signaled_thread_tid, int signo);
+        NotifyThreadStop (lldb::tid_t tid);
 
         void
-        OnGroupStop (lldb::tid_t tid);
+        CallAfterRunningThreadsStop (lldb::tid_t tid,
+                                     const std::function<void (lldb::tid_t tid)> &call_after_function);
 
         lldb_private::Error
         Detach(lldb::tid_t tid);

Modified: lldb/trunk/source/Plugins/Process/Linux/ThreadStateCoordinator.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/ThreadStateCoordinator.cpp?rev=227909&r1=227908&r2=227909&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/ThreadStateCoordinator.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Linux/ThreadStateCoordinator.cpp Mon Feb  2 19:50:42 2015
@@ -35,6 +35,9 @@ public:
     {
     }
 
+    virtual std::string
+    GetDescription () = 0;
+
     // Return false if the coordinator should terminate running.
     virtual EventLoopResult
     ProcessEvent (ThreadStateCoordinator &coordinator) = 0;
@@ -55,6 +58,12 @@ public:
     {
         return eventLoopResultStop;
     }
+
+    std::string
+    GetDescription () override
+    {
+        return "EventStopCoordinator";
+    }
 };
 
 //===----------------------------------------------------------------------===//
@@ -190,6 +199,14 @@ public:
             m_request_thread_stop_function (tid);
     }
 
+    std::string
+    GetDescription () override
+    {
+        std::ostringstream description;
+        description << "EventCallAfterThreadsStop (triggering_tid=" << m_triggering_tid << ", request_stop_on_all_unstopped_threads=" << m_request_stop_on_all_unstopped_threads << ")";
+        return description.str ();
+    }
+
 private:
 
     void
@@ -291,6 +308,12 @@ public:
         coordinator.ResetNow ();
         return eventLoopResultContinue;
     }
+
+    std::string
+    GetDescription () override
+    {
+        return "EventReset";
+    }
 };
 
 //===----------------------------------------------------------------------===//
@@ -313,6 +336,14 @@ public:
         return eventLoopResultContinue;
     }
 
+    std::string
+    GetDescription () override
+    {
+        std::ostringstream description;
+        description << "EventThreadStopped (tid=" << m_tid << ")";
+        return description.str ();
+    }
+
 private:
 
     const lldb::tid_t m_tid;
@@ -341,6 +372,14 @@ public:
         return eventLoopResultContinue;
     }
 
+    std::string
+    GetDescription () override
+    {
+        std::ostringstream description;
+        description << "EventThreadCreate (tid=" << m_tid << ", " << (m_is_stopped ? "stopped" : "running") << ")";
+        return description.str ();
+    }
+
 private:
 
     const lldb::tid_t m_tid;
@@ -368,6 +407,14 @@ public:
         return eventLoopResultContinue;
     }
 
+    std::string
+    GetDescription () override
+    {
+        std::ostringstream description;
+        description << "EventThreadDeath (tid=" << m_tid << ")";
+        return description.str ();
+    }
+
 private:
 
     const lldb::tid_t m_tid;
@@ -450,6 +497,14 @@ public:
         return eventLoopResultContinue;
     }
 
+    std::string
+    GetDescription () override
+    {
+        std::ostringstream description;
+        description << "EventRequestResume (tid=" << m_tid << ")";
+        return description.str ();
+    }
+
 private:
 
     const lldb::tid_t m_tid;
@@ -464,7 +519,8 @@ ThreadStateCoordinator::ThreadStateCoord
     m_event_queue (),
     m_queue_condition (),
     m_queue_mutex (),
-    m_tid_stop_map ()
+    m_tid_stop_map (),
+    m_log_event_processing (false)
 {
 }
 
@@ -711,7 +767,39 @@ ThreadStateCoordinator::StopCoordinator
 ThreadStateCoordinator::EventLoopResult
 ThreadStateCoordinator::ProcessNextEvent ()
 {
-    return DequeueEventWithWait()->ProcessEvent (*this);
+    // Dequeue the next event, synchronous.
+    if (m_log_event_processing)
+        Log ("ThreadStateCoordinator::%s about to dequeue next event in blocking mode", __FUNCTION__);
+
+    EventBaseSP event_sp = DequeueEventWithWait();
+    assert (event_sp && "event should never be null");
+    if (!event_sp)
+    {
+        Log ("ThreadStateCoordinator::%s error: event_sp was null, signaling exit of event loop.", __FUNCTION__);
+        return eventLoopResultStop;
+    }
+
+    if (m_log_event_processing)
+    {
+        Log ("ThreadStateCoordinator::%s about to process event: %s", __FUNCTION__, event_sp->GetDescription ().c_str ());
+    }
+
+    // Process the event.
+    const EventLoopResult result = event_sp->ProcessEvent (*this);
+
+    if (m_log_event_processing)
+    {
+        Log ("ThreadStateCoordinator::%s event processing returned value %s", __FUNCTION__,
+             result == eventLoopResultContinue ? "eventLoopResultContinue" : "eventLoopResultStop");
+    }
+
+    return result;
+}
+
+void
+ThreadStateCoordinator::LogEnableEventProcessing (bool enabled)
+{
+    m_log_event_processing = enabled;
 }
 
 ThreadStateCoordinator::EventCallAfterThreadsStop *

Modified: lldb/trunk/source/Plugins/Process/Linux/ThreadStateCoordinator.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/ThreadStateCoordinator.h?rev=227909&r1=227908&r2=227909&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/ThreadStateCoordinator.h (original)
+++ lldb/trunk/source/Plugins/Process/Linux/ThreadStateCoordinator.h Mon Feb  2 19:50:42 2015
@@ -115,6 +115,10 @@ namespace lldb_private
         EventLoopResult
         ProcessNextEvent ();
 
+        // Enable/disable verbose logging of event processing.
+        void
+        LogEnableEventProcessing (bool enabled);
+
     private:
 
         // Typedefs.
@@ -179,6 +183,8 @@ namespace lldb_private
 
         // Maps known TIDs to stop (true) or not-stopped (false) state.
         TIDBoolMap m_tid_stop_map;
+
+        bool m_log_event_processing;
     };
 }
 





More information about the lldb-commits mailing list