[Lldb-commits] [lldb] r237945 - Fix race condition when detaching/killing an inferior.
Zachary Turner
zturner at google.com
Thu May 21 12:56:27 PDT 2015
Author: zturner
Date: Thu May 21 14:56:26 2015
New Revision: 237945
URL: http://llvm.org/viewvc/llvm-project?rev=237945&view=rev
Log:
Fix race condition when detaching/killing an inferior.
Modified:
lldb/trunk/source/Plugins/Process/Windows/DebuggerThread.cpp
lldb/trunk/source/Plugins/Process/Windows/DebuggerThread.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=237945&r1=237944&r2=237945&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Windows/DebuggerThread.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Windows/DebuggerThread.cpp Thu May 21 14:56:26 2015
@@ -62,11 +62,14 @@ struct DebugAttachContext
DebuggerThread::DebuggerThread(DebugDelegateSP debug_delegate)
: m_debug_delegate(debug_delegate)
, m_image_file(nullptr)
+ , m_debugging_ended_event(nullptr)
{
+ m_debugging_ended_event = ::CreateEvent(nullptr, TRUE, FALSE, nullptr);
}
DebuggerThread::~DebuggerThread()
{
+ ::CloseHandle(m_debugging_ended_event);
}
Error
@@ -150,6 +153,7 @@ DebuggerThread::DebuggerThreadLaunchRout
else
m_debug_delegate->OnDebuggerError(error, 0);
+ SetEvent(m_debugging_ended_event);
return 0;
}
@@ -203,10 +207,9 @@ DebuggerThread::StopDebugging(bool termi
"StopDebugging called TerminateProcess(0x%p, 0) (inferior=%I64u), success='%s'",
handle, pid, (terminate_suceeded ? "true" : "false"));
-
- // If we're stuck waiting for an exception to continue, continue it now. But only
- // AFTER setting the termination event, to make sure that we don't race and enter
- // another wait for another debug event.
+ // If we're stuck waiting for an exception to continue (e.g. the user is at a breakpoint
+ // messing around in the debugger), continue it now. But only AFTER calling TerminateProcess
+ // to make sure that the very next call to WaitForDebugEvent is an exit process event.
if (m_active_exception.get())
{
WINLOG_IFANY(WINDOWS_LOG_PROCESS|WINDOWS_LOG_EXCEPTION,
@@ -215,23 +218,19 @@ DebuggerThread::StopDebugging(bool termi
ContinueAsyncException(ExceptionResult::MaskException);
}
- // Don't return until the process has exited.
- if (terminate_suceeded)
- {
- WINLOG_IFALL(WINDOWS_LOG_PROCESS,
- "StopDebugging waiting for termination of process %u to complete.", pid);
+ WINLOG_IFALL(WINDOWS_LOG_PROCESS, "StopDebugging waiting for detach from process %u to complete.", pid);
- DWORD wait_result = ::WaitForSingleObject(handle, 5000);
- if (wait_result != WAIT_OBJECT_0)
- terminate_suceeded = false;
-
- WINLOG_IFALL(WINDOWS_LOG_PROCESS,
- "StopDebugging WaitForSingleObject(0x%p, 5000) returned %u",
- handle, wait_result);
- }
-
- if (!terminate_suceeded)
+ DWORD wait_result = WaitForSingleObject(m_debugging_ended_event, 5000);
+ if (wait_result != WAIT_OBJECT_0)
+ {
error.SetError(GetLastError(), eErrorTypeWin32);
+ WINERR_IFALL(WINDOWS_LOG_PROCESS, "StopDebugging WaitForSingleObject(0x%p, 5000) returned %u",
+ m_debugging_ended_event, wait_result);
+ }
+ else
+ {
+ WINLOG_IFALL(WINDOWS_LOG_PROCESS, "StopDebugging detach from process %u completed successfully.", pid);
+ }
}
else
{
@@ -343,6 +342,8 @@ DebuggerThread::DebugLoop()
}
}
FreeProcessHandles();
+
+ WINLOG_IFALL(WINDOWS_LOG_EVENT, "WaitForDebugEvent loop completed, exiting.");
}
ExceptionResult
Modified: lldb/trunk/source/Plugins/Process/Windows/DebuggerThread.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Windows/DebuggerThread.h?rev=237945&r1=237944&r2=237945&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Windows/DebuggerThread.h (original)
+++ lldb/trunk/source/Plugins/Process/Windows/DebuggerThread.h Thu May 21 14:56:26 2015
@@ -81,6 +81,9 @@ class DebuggerThread : public std::enabl
// is finished processing and the debug loop can be
// continued.
+ HANDLE m_debugging_ended_event; // An event which gets signalled by the debugger thread when it
+ // exits the debugger loop and is detached from the inferior.
+
static lldb::thread_result_t DebuggerThreadLaunchRoutine(void *data);
lldb::thread_result_t DebuggerThreadLaunchRoutine(const ProcessLaunchInfo &launch_info);
static lldb::thread_result_t DebuggerThreadAttachRoutine(void *data);
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=237945&r1=237944&r2=237945&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Windows/ProcessWindows.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Windows/ProcessWindows.cpp Thu May 21 14:56:26 2015
@@ -424,30 +424,43 @@ ProcessWindows::DoDetach(bool keep_stopp
Error
ProcessWindows::DoDestroy()
{
- llvm::sys::ScopedLock lock(m_mutex);
-
- Error error;
- StateType private_state = GetPrivateState();
- if (!m_session_data)
+ DebuggerThreadSP debugger_thread;
+ StateType private_state;
{
- WINWARN_IFALL(WINDOWS_LOG_PROCESS, "DoDestroy called while state = %u, but there is no active session.",
- private_state);
- return error;
+ // Acquire this lock inside an inner scope, only long enough to get the DebuggerThread.
+ // StopDebugging() will trigger a call back into ProcessWindows which will acquire the lock
+ // again, so we need to not deadlock.
+ llvm::sys::ScopedLock lock(m_mutex);
+
+ private_state = GetPrivateState();
+
+ if (!m_session_data)
+ {
+ WINWARN_IFALL(WINDOWS_LOG_PROCESS, "DoDestroy called while state = %u, but there is no active session.",
+ private_state);
+ return Error();
+ }
+
+ debugger_thread = m_session_data->m_debugger;
}
- DebuggerThread &debugger = *m_session_data->m_debugger;
+ Error error;
if (private_state != eStateExited && private_state != eStateDetached)
{
- WINLOG_IFALL(WINDOWS_LOG_PROCESS, "DoDestroy called for process 0x%I64u while state = %u. Shutting down...",
- debugger.GetProcess().GetNativeProcess().GetSystemHandle(), private_state);
- error = debugger.StopDebugging(true);
+ WINLOG_IFALL(WINDOWS_LOG_PROCESS, "DoDestroy called for process %I64u while state = %u. Shutting down...",
+ debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle(), private_state);
+ error = debugger_thread->StopDebugging(true);
+
+ // By the time StopDebugging returns, there is no more debugger thread, so we can be assured that no other
+ // thread
+ // will race for the session data. So it's safe to reset it without holding a lock.
m_session_data.reset();
}
else
{
WINERR_IFALL(WINDOWS_LOG_PROCESS,
"DoDestroy called for process %I64u while state = %u, but cannot destroy in this state.",
- debugger.GetProcess().GetNativeProcess().GetSystemHandle(), private_state);
+ debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle(), private_state);
}
return error;
More information about the lldb-commits
mailing list