From 455fa5ccc6ad7a5a6227166f74474124d614e8ea Mon Sep 17 00:00:00 2001 From: Jim Ingham Date: Thu, 1 Nov 2012 01:15:33 +0000 Subject: [PATCH] There seems to be some odd corner case where we shut down the ProcessGDBRemote, but we haven't managed to shut down the async thread. That causes the ProcessGDBRemote::AsyncThread to crash when it wakes up. So I changed StartAsyncThread and StopAsyncThread to be callable multiple times (only the first one does anything) so that we can just shut it down unequivocally in the ProcessGDBRemote destructor. llvm-svn: 167197 --- .../Process/gdb-remote/ProcessGDBRemote.cpp | 63 +++++++++++++++++----- .../Plugins/Process/gdb-remote/ProcessGDBRemote.h | 9 ++++ 2 files changed, 60 insertions(+), 12 deletions(-) diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 7f38cb6b..1bfbb7a 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -188,6 +188,8 @@ ProcessGDBRemote::ProcessGDBRemote(Target& target, Listener &listener) : m_register_info (), m_async_broadcaster (NULL, "lldb.process.gdb-remote.async-broadcaster"), m_async_thread (LLDB_INVALID_HOST_THREAD), + m_async_thread_state(eAsyncThreadNotStarted), + m_async_thread_state_mutex(Mutex::eMutexTypeRecursive), m_thread_ids (), m_continue_c_tids (), m_continue_C_tids (), @@ -220,6 +222,12 @@ ProcessGDBRemote::~ProcessGDBRemote() // destruct this class, then Process::~Process() might have problems // trying to fully destroy the broadcaster. Finalize(); + + // The general Finalize is going to try to destroy the process and that SHOULD + // shut down the async thread. However, if we don't kill it it will get stranded and + // its connection will go away so when it wakes up it will crash. So kill it for sure here. + StopAsyncThread(); + KillDebugserverProcess(); } //---------------------------------------------------------------------- @@ -2713,11 +2721,32 @@ ProcessGDBRemote::StartAsyncThread () if (log) log->Printf ("ProcessGDBRemote::%s ()", __FUNCTION__); - - // Create a thread that watches our internal state and controls which - // events make it to clients (into the DCProcess event queue). - m_async_thread = Host::ThreadCreate ("", ProcessGDBRemote::AsyncThread, this, NULL); - return IS_VALID_LLDB_HOST_THREAD(m_async_thread); + + Mutex::Locker start_locker(m_async_thread_state_mutex); + if (m_async_thread_state == eAsyncThreadNotStarted) + { + // Create a thread that watches our internal state and controls which + // events make it to clients (into the DCProcess event queue). + m_async_thread = Host::ThreadCreate ("", ProcessGDBRemote::AsyncThread, this, NULL); + if (IS_VALID_LLDB_HOST_THREAD(m_async_thread)) + { + m_async_thread_state = eAsyncThreadRunning; + return true; + } + else + return false; + } + else + { + // Somebody tried to start the async thread while it was either being started or stopped. If the former, and + // it started up successfully, then say all's well. Otherwise it is an error, since we aren't going to restart it. + if (log) + log->Printf ("ProcessGDBRemote::%s () - Called when Async thread was in state: %d.", __FUNCTION__, m_async_thread_state); + if (m_async_thread_state == eAsyncThreadRunning) + return true; + else + return false; + } } void @@ -2728,15 +2757,25 @@ ProcessGDBRemote::StopAsyncThread () if (log) log->Printf ("ProcessGDBRemote::%s ()", __FUNCTION__); - m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncThreadShouldExit); - - // This will shut down the async thread. - m_gdb_comm.Disconnect(); // Disconnect from the debug server. + Mutex::Locker start_locker(m_async_thread_state_mutex); + if (m_async_thread_state == eAsyncThreadRunning) + { + m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncThreadShouldExit); + + // This will shut down the async thread. + m_gdb_comm.Disconnect(); // Disconnect from the debug server. - // Stop the stdio thread - if (IS_VALID_LLDB_HOST_THREAD(m_async_thread)) + // Stop the stdio thread + if (IS_VALID_LLDB_HOST_THREAD(m_async_thread)) + { + Host::ThreadJoin (m_async_thread, NULL, NULL); + } + m_async_thread_state = eAsyncThreadDone; + } + else { - Host::ThreadJoin (m_async_thread, NULL, NULL); + if (log) + log->Printf ("ProcessGDBRemote::%s () - Called when Async thread was in state: %d.", __FUNCTION__, m_async_thread_state); } } diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 5c642d44..4cf2a4f 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -307,6 +307,13 @@ protected: eBroadcastBitAsyncThreadDidExit = (1 << 2) }; + typedef enum AsyncThreadState + { + eAsyncThreadNotStarted, + eAsyncThreadRunning, + eAsyncThreadDone + } AsyncThreadState; + lldb_private::Flags m_flags; // Process specific flags (see eFlags enums) GDBRemoteCommunicationClient m_gdb_comm; lldb::pid_t m_debugserver_pid; @@ -315,6 +322,8 @@ protected: GDBRemoteDynamicRegisterInfo m_register_info; lldb_private::Broadcaster m_async_broadcaster; lldb::thread_t m_async_thread; + AsyncThreadState m_async_thread_state; + lldb_private::Mutex m_async_thread_state_mutex; typedef std::vector tid_collection; typedef std::vector< std::pair > tid_sig_collection; typedef std::map MMapMap; -- 2.7.4