diff options
author | Greg Clayton <gclayton@apple.com> | 2014-12-01 22:41:27 +0000 |
---|---|---|
committer | Greg Clayton <gclayton@apple.com> | 2014-12-01 22:41:27 +0000 |
commit | afa91e339ba053828e352fe1509c8d415d91a591 (patch) | |
tree | 95858d680d65864fd9f0b340c188ab49f7cb2f4f /lldb/source/Core/Debugger.cpp | |
parent | d90ac932d9d314e5fcf70951a2bc5f6c4bbdc26d (diff) | |
download | bcm5719-llvm-afa91e339ba053828e352fe1509c8d415d91a591.tar.gz bcm5719-llvm-afa91e339ba053828e352fe1509c8d415d91a591.zip |
lldb can deadlock when launched with an non-existing executable:
% lldb /bin/nonono
(lldb) target create "/bin/nonono"
error: unable to find executable for '/usr/bin/nonono'
<deadlock>
The problem was the initial commands 'target create "/bin/nonono"' were put into a pipe and the command interpreter was being run with:
void
CommandInterpreter::RunCommandInterpreter(bool auto_handle_events,
bool spawn_thread,
CommandInterpreterRunOptions &options)
{
// Always re-create the command intepreter when we run it in case
// any file handles have changed.
bool force_create = true;
m_debugger.PushIOHandler(GetIOHandler(force_create, &options));
m_stopped_for_crash = false;
if (auto_handle_events)
m_debugger.StartEventHandlerThread();
if (spawn_thread)
{
m_debugger.StartIOHandlerThread();
}
else
{
m_debugger.ExecuteIOHanders();
if (auto_handle_events)
m_debugger.StopEventHandlerThread();
}
}
If "auto_handle_events" was set to true and "spawn_thread" was false, we would execute:
m_debugger.StartEventHandlerThread();
m_debugger.ExecuteIOHanders();
m_debugger.StopEventHandlerThread();
The problem was there was no synchonization in Debugger::StartEventHandlerThread() to ensure the event handler was listening to events and the the call to "m_debugger.StopEventHandlerThread()" would do:
void
Debugger::StopEventHandlerThread()
{
if (m_event_handler_thread.IsJoinable())
{
GetCommandInterpreter().BroadcastEvent(CommandInterpreter::eBroadcastBitQuitCommandReceived);
m_event_handler_thread.Join(nullptr);
}
}
The problem was that the event thread might not be listening for the CommandInterpreter::eBroadcastBitQuitCommandReceived event yet.
The solution is to make sure the Debugger::DefaultEventHandler() is listening to events before we return from Debugger::StartEventHandlerThread(). Once we have this synchonization we remove the race condition.
This fixes radar:
<rdar://problem/19041192>
llvm-svn: 223083
Diffstat (limited to 'lldb/source/Core/Debugger.cpp')
-rw-r--r-- | lldb/source/Core/Debugger.cpp | 36 |
1 files changed, 26 insertions, 10 deletions
diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index 98fb64cd14e..6cb844f2928 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -661,7 +661,10 @@ Debugger::Debugger(lldb::LogOutputCallback log_callback, void *baton) : m_command_interpreter_ap(new CommandInterpreter(*this, eScriptLanguageDefault, false)), m_input_reader_stack(), m_instance_name(), - m_loaded_plugins() + m_loaded_plugins(), + m_event_handler_thread (), + m_io_handler_thread (), + m_sync_broadcaster (NULL, "lldb.debugger.sync") { char instance_cstr[256]; snprintf(instance_cstr, sizeof(instance_cstr), "debugger_%d", (int)GetID()); @@ -3250,17 +3253,14 @@ Debugger::DefaultEventHandler() CommandInterpreter::eBroadcastBitQuitCommandReceived | CommandInterpreter::eBroadcastBitAsynchronousOutputData | CommandInterpreter::eBroadcastBitAsynchronousErrorData ); - + + // Let the thread that spawned us know that we have started up and + // that we are now listening to all required events so no events get missed + m_sync_broadcaster.BroadcastEvent(eBroadcastBitEventThreadIsListening); + bool done = false; while (!done) { -// Mutex::Locker locker; -// if (locker.TryLock(m_input_reader_stack.GetMutex())) -// { -// if (m_input_reader_stack.IsEmpty()) -// break; -// } -// EventSP event_sp; if (listener.WaitForEvent(NULL, event_sp)) { @@ -3344,9 +3344,25 @@ Debugger::StartEventHandlerThread() { if (!m_event_handler_thread.IsJoinable()) { + // We must synchronize with the DefaultEventHandler() thread to ensure + // it is up and running and listening to events before we return from + // this function. We do this by listening to events for the + // eBroadcastBitEventThreadIsListening from the m_sync_broadcaster + Listener listener("lldb.debugger.event-handler"); + listener.StartListeningForEvents(&m_sync_broadcaster, eBroadcastBitEventThreadIsListening); + // Use larger 8MB stack for this thread - m_event_handler_thread = ThreadLauncher::LaunchThread("lldb.debugger.event-handler", EventHandlerThread, this, NULL, + m_event_handler_thread = ThreadLauncher::LaunchThread("lldb.debugger.event-handler", EventHandlerThread, + this, + NULL, g_debugger_event_thread_stack_bytes); + + // Make sure DefaultEventHandler() is running and listening to events before we return + // from this function. We are only listening for events of type + // eBroadcastBitEventThreadIsListening so we don't need to check the event, we just need + // to wait an infinite amount of time for it (NULL timeout as the first parameter) + lldb::EventSP event_sp; + listener.WaitForEvent(NULL, event_sp); } return m_event_handler_thread.IsJoinable(); } |