lldb can deadlock when launched with an non-existing executable:
authorGreg Clayton <gclayton@apple.com>
Mon, 1 Dec 2014 22:41:27 +0000 (22:41 +0000)
committerGreg Clayton <gclayton@apple.com>
Mon, 1 Dec 2014 22:41:27 +0000 (22:41 +0000)
commitafa91e339ba053828e352fe1509c8d415d91a591
tree95858d680d65864fd9f0b340c188ab49f7cb2f4f
parentd90ac932d9d314e5fcf70951a2bc5f6c4bbdc26d
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
lldb/include/lldb/Core/Debugger.h
lldb/source/Core/Debugger.cpp