[Lldb-commits] [lldb] r222178 - Move the thread logic around to fit better into LLDB's process model.

Zachary Turner zturner at google.com
Mon Nov 17 13:31:30 PST 2014


Author: zturner
Date: Mon Nov 17 15:31:30 2014
New Revision: 222178

URL: http://llvm.org/viewvc/llvm-project?rev=222178&view=rev
Log:
Move the thread logic around to fit better into LLDB's process model.

Previously we were directly updating the thread list and stopping
and restarting the process every time threads were created.  With
this patch, we queue up thread launches and thread exits, resolve
these all internally, and only update the threads when we get an
UpdateThreadList call.  We now only update the private state on
an actual stop (i.e. breakpoint).

Modified:
    lldb/trunk/source/Plugins/Process/Windows/DebuggerThread.cpp
    lldb/trunk/source/Plugins/Process/Windows/ForwardDecl.h
    lldb/trunk/source/Plugins/Process/Windows/ProcessWindows.cpp

Modified: lldb/trunk/source/Plugins/Process/Windows/DebuggerThread.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Windows/DebuggerThread.cpp?rev=222178&r1=222177&r2=222178&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Windows/DebuggerThread.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Windows/DebuggerThread.cpp Mon Nov 17 15:31:30 2014
@@ -117,11 +117,11 @@ DebuggerThread::DebugLoop()
             {
                 ExceptionResult status = HandleExceptionEvent(dbe.u.Exception, dbe.dwThreadId);
                 m_exception.SetValue(status, eBroadcastNever);
-                m_exception.WaitForValueNotEqualTo(ExceptionResult::WillHandle, status);
+                m_exception.WaitForValueNotEqualTo(ExceptionResult::BreakInDebugger, status);
 
-                if (status == ExceptionResult::Handled)
+                if (status == ExceptionResult::MaskException)
                     continue_status = DBG_CONTINUE;
-                else if (status == ExceptionResult::NotHandled)
+                else if (status == ExceptionResult::SendToApplication)
                     continue_status = DBG_EXCEPTION_NOT_HANDLED;
                 break;
             }

Modified: lldb/trunk/source/Plugins/Process/Windows/ForwardDecl.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Windows/ForwardDecl.h?rev=222178&r1=222177&r2=222178&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Windows/ForwardDecl.h (original)
+++ lldb/trunk/source/Plugins/Process/Windows/ForwardDecl.h Mon Nov 17 15:31:30 2014
@@ -18,11 +18,11 @@ class ProcessWindows;
 // the exception.
 enum class ExceptionResult
 {
-    Handled,    // The delegate handled the exception.  Continue.
-    NotHandled, // The delegate did not handle the exception.  Keep
-                // searching.
-    WillHandle  // The delegate will handle the exception.  Do not
-                // process further debug events until it finishes.
+    BreakInDebugger,  // Break in the debugger and give the user a chance to interact with
+                      // the program before continuing.
+    MaskException,    // Eat the exception and don't let the application know it occurred.
+    SendToApplication // Send the exception to the application to be handled as if there were
+                      // no debugger attached.
 };
 
 namespace lldb_private

Modified: lldb/trunk/source/Plugins/Process/Windows/ProcessWindows.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Windows/ProcessWindows.cpp?rev=222178&r1=222177&r2=222178&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Windows/ProcessWindows.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Windows/ProcessWindows.cpp Mon Nov 17 15:31:30 2014
@@ -11,6 +11,7 @@
 #include "lldb/Host/windows/windows.h"
 
 // C++ Includes
+#include <list>
 #include <vector>
 
 // Other libraries and framework includes
@@ -23,6 +24,7 @@
 #include "lldb/Host/HostNativeThreadBase.h"
 #include "lldb/Host/MonitoringProcessLauncher.h"
 #include "lldb/Host/ThreadLauncher.h"
+#include "lldb/Host/windows/HostThreadWindows.h"
 #include "lldb/Host/windows/ProcessLauncherWindows.h"
 #include "lldb/Symbol/ObjectFile.h"
 #include "lldb/Target/DynamicLoader.h"
@@ -40,6 +42,7 @@ using namespace lldb_private;
 
 namespace lldb_private
 {
+
 // We store a pointer to this class in the ProcessWindows, so that we don't expose Windows
 // OS specific types and implementation details from a public header file.
 class ProcessWindowsData
@@ -61,6 +64,8 @@ class ProcessWindowsData
     lldb_private::DebuggerThreadSP m_debugger;
     HANDLE m_initial_stop_event;
     bool m_initial_stop_received;
+    std::map<lldb::tid_t, HostThread> m_new_threads;
+    std::map<lldb::tid_t, HostThread> m_exited_threads;
 };
 }
 //------------------------------------------------------------------------------
@@ -120,8 +125,33 @@ ProcessWindows::GetPluginDescriptionStat
 bool
 ProcessWindows::UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_thread_list)
 {
-    new_thread_list = old_thread_list;
-    return new_thread_list.GetSize(false) > 0;
+    // Add all the threads that were previously running and for which we did not detect a thread
+    // exited event.
+    int new_size = 0;
+    for (ThreadSP old_thread : old_thread_list.Threads())
+    {
+        lldb::tid_t old_thread_id = old_thread->GetID();
+        auto exited_thread_iter = m_session_data->m_exited_threads.find(old_thread_id);
+        if (exited_thread_iter == m_session_data->m_exited_threads.end())
+        {
+            new_thread_list.AddThread(old_thread);
+            ++new_size;
+        }
+    }
+
+    // Also add all the threads that are new since the last time we broke into the debugger.
+    for (auto iter = m_session_data->m_new_threads.begin(); iter != m_session_data->m_new_threads.end(); ++iter)
+    {
+        ThreadSP thread(new TargetThreadWindows(*this, iter->second));
+        thread->SetID(iter->first);
+        new_thread_list.AddThread(thread);
+        ++new_size;
+    }
+
+    m_session_data->m_new_threads.clear();
+    m_session_data->m_exited_threads.clear();
+
+    return new_size > 0;
 }
 
 Error
@@ -148,6 +178,7 @@ ProcessWindows::DoLaunch(Module *exe_mod
     HostProcess process;
     if (result.Success())
     {
+        // Block this function until we receive the initial stop from the process.
         if (::WaitForSingleObject(m_session_data->m_initial_stop_event, INFINITE) == WAIT_OBJECT_0)
             process = debugger->GetProcess();
         else
@@ -158,7 +189,7 @@ ProcessWindows::DoLaunch(Module *exe_mod
         return result;
 
     // We've hit the initial stop.  The private state should already be set to stopped as a result
-    // of encountering the breakpoint exception.
+    // of encountering the breakpoint exception in ProcessWindows::OnDebugException.
     launch_info.SetProcessID(process.GetProcessId());
     SetID(process.GetProcessId());
 
@@ -173,9 +204,10 @@ ProcessWindows::DoResume()
     {
         if (m_session_data->m_active_exception)
         {
-            // Resume the process and continue processing debug events.
+            // Resume the process and continue processing debug events.  Mask the exception so that
+            // from the process's view, there is no indication that anything happened.
             m_session_data->m_active_exception.reset();
-            m_session_data->m_debugger->ContinueAsyncException(ExceptionResult::Handled);
+            m_session_data->m_debugger->ContinueAsyncException(ExceptionResult::MaskException);
         }
 
         SetPrivateState(eStateRunning);
@@ -212,6 +244,7 @@ ProcessWindows::DoDestroy()
     Error error;
     if (GetPrivateState() != eStateExited && GetPrivateState() != eStateDetached && m_session_data)
     {
+        // Ends the debugging session and terminates the inferior process.
         DebugActiveProcessStop(m_session_data->m_debugger->GetProcess().GetProcessId());
         SetPrivateState(eStateExited);
     }
@@ -325,25 +358,27 @@ ProcessWindows::OnExitProcess(uint32_t e
 void
 ProcessWindows::OnDebuggerConnected(lldb::addr_t image_base)
 {
+    // Either we successfully attached to an existing process, or we successfully launched a new
+    // process under the debugger.
     ModuleSP module = GetTarget().GetExecutableModule();
     bool load_addr_changed;
     module->SetLoadAddress(GetTarget(), image_base, false, load_addr_changed);
 
     DebuggerThreadSP debugger = m_session_data->m_debugger;
-    ThreadSP main_thread(new TargetThreadWindows(*this, debugger->GetMainThread()));
-    m_thread_list.AddThread(main_thread);
+    const HostThreadWindows &wmain_thread = static_cast<const HostThreadWindows &>(debugger->GetMainThread().GetNativeThread());
+    m_session_data->m_new_threads[wmain_thread.GetThreadId()] = debugger->GetMainThread();
 }
 
 ExceptionResult
 ProcessWindows::OnDebugException(bool first_chance, const ExceptionRecord &record)
 {
-    ExceptionResult result = ExceptionResult::NotHandled;
+    ExceptionResult result = ExceptionResult::SendToApplication;
     m_session_data->m_active_exception.reset(new ExceptionRecord(record));
     switch (record.GetExceptionCode())
     {
         case EXCEPTION_BREAKPOINT:
             // Handle breakpoints at the first chance.
-            result = ExceptionResult::WillHandle;
+            result = ExceptionResult::BreakInDebugger;
 
             if (!m_session_data->m_initial_stop_received)
             {
@@ -354,9 +389,9 @@ ProcessWindows::OnDebugException(bool fi
         default:
             // For non-breakpoints, give the application a chance to handle the exception first.
             if (first_chance)
-                result = ExceptionResult::NotHandled;
+                result = ExceptionResult::SendToApplication;
             else
-                result = ExceptionResult::WillHandle;
+                result = ExceptionResult::BreakInDebugger;
     }
 
     if (!first_chance)
@@ -364,10 +399,10 @@ ProcessWindows::OnDebugException(bool fi
         // Any second chance exception is an application crash by definition.
         SetPrivateState(eStateCrashed);
     }
-    else if (result == ExceptionResult::WillHandle)
+    else if (result == ExceptionResult::BreakInDebugger)
     {
         // For first chance exceptions that we can handle, the process is stopped so the user
-        // can inspect / manipulate the state of the process in the debugger.
+        // can interact with the debugger.
         SetPrivateState(eStateStopped);
     }
     else
@@ -380,14 +415,23 @@ ProcessWindows::OnDebugException(bool fi
 }
 
 void
-ProcessWindows::OnCreateThread(const HostThread &thread)
+ProcessWindows::OnCreateThread(const HostThread &new_thread)
 {
-    SuspendThread(thread.GetNativeThread().GetSystemHandle());
+    const HostThreadWindows &wnew_thread = static_cast<const HostThreadWindows &>(new_thread.GetNativeThread());
+    m_session_data->m_new_threads[wnew_thread.GetThreadId()] = new_thread;
 }
 
 void
-ProcessWindows::OnExitThread(const HostThread &thread)
+ProcessWindows::OnExitThread(const HostThread &exited_thread)
 {
+    // A thread may have started and exited before the debugger stopped allowing a refresh.
+    // Just remove it from the new threads list in that case.
+    const HostThreadWindows &wexited_thread = static_cast<const HostThreadWindows &>(exited_thread.GetNativeThread());
+    auto iter = m_session_data->m_new_threads.find(wexited_thread.GetThreadId());
+    if (iter != m_session_data->m_new_threads.end())
+        m_session_data->m_new_threads.erase(iter);
+    else
+        m_session_data->m_exited_threads[wexited_thread.GetThreadId()] = exited_thread;
 }
 
 void
@@ -418,8 +462,9 @@ ProcessWindows::OnDebuggerError(const Er
 {
     if (!m_session_data->m_initial_stop_received)
     {
-        // If we haven't actually launched the process yet, this was an error
-        // launching the process.  Set the internal error and signal.
+        // If we haven't actually launched the process yet, this was an error launching the
+        // process.  Set the internal error and signal the initial stop event so that the DoLaunch
+        // method wakes up and returns a failure.
         m_session_data->m_launch_error = error;
         ::SetEvent(m_session_data->m_initial_stop_event);
         return;





More information about the lldb-commits mailing list