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.
<rdar://problem/12602981> llvm-svn: 167197
This commit is contained in:
parent
4e45abf0ae
commit
455fa5ccc6
|
@ -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 ("<lldb.process.gdb-remote.async>", 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 ("<lldb.process.gdb-remote.async>", 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.
|
||||
|
||||
// Stop the stdio thread
|
||||
if (IS_VALID_LLDB_HOST_THREAD(m_async_thread))
|
||||
Mutex::Locker start_locker(m_async_thread_state_mutex);
|
||||
if (m_async_thread_state == eAsyncThreadRunning)
|
||||
{
|
||||
Host::ThreadJoin (m_async_thread, NULL, NULL);
|
||||
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))
|
||||
{
|
||||
Host::ThreadJoin (m_async_thread, NULL, NULL);
|
||||
}
|
||||
m_async_thread_state = eAsyncThreadDone;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (log)
|
||||
log->Printf ("ProcessGDBRemote::%s () - Called when Async thread was in state: %d.", __FUNCTION__, m_async_thread_state);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<lldb::tid_t> tid_collection;
|
||||
typedef std::vector< std::pair<lldb::tid_t,int> > tid_sig_collection;
|
||||
typedef std::map<lldb::addr_t, lldb::addr_t> MMapMap;
|
||||
|
|
Loading…
Reference in New Issue