Remove quit hook in CMIDriver::DoMainLoop (MI)

Summary:
This patch removes quit hook and fixes 1 bug:
# Fix "quit" hook in CMIDriver::DoMainLoop (MI)
# Fix bug when the handler thread exits without any notification (MI)
# Fix a race condition in CMICmnLLDBDebugger::MonitorSBListenerEvents (MI)

Test Plan: ./dotest.py -v --executable $BUILDDIR/bin/lldb tools/lldb-mi/

Reviewers: abidh

Reviewed By: abidh

Subscribers: lldb-commits, abidh

Differential Revision: http://reviews.llvm.org/D9275

llvm-svn: 236702
This commit is contained in:
Ilia K 2015-05-07 06:45:42 +00:00
parent 43f7439cf5
commit 8913012ee9
3 changed files with 51 additions and 16 deletions

View File

@ -221,6 +221,28 @@ CMICmnLLDBDebugger::GetDriver(void) const
return *m_pClientDriver;
}
//++ ------------------------------------------------------------------------------------
// Details: Wait until all events have been handled.
// This function works in pair with CMICmnLLDBDebugger::MonitorSBListenerEvents
// that handles events from queue. When all events were handled and queue is
// empty the MonitorSBListenerEvents notifies this function that it's ready to
// go on. To synchronize them the m_mutexEventQueue and
// m_conditionEventQueueEmpty are used.
// Type: Method.
// Args: None.
// Return: None.
// Throws: None.
//--
void
CMICmnLLDBDebugger::WaitForHandleEvent(void)
{
std::unique_lock<std::mutex> lock(m_mutexEventQueue);
lldb::SBEvent event;
if (ThreadIsActive() && m_lldbListener.PeekAtNextEvent(event))
m_conditionEventQueueEmpty.wait(lock);
}
//++ ------------------------------------------------------------------------------------
// Details: Initialize the LLDB Debugger object.
// Type: Method.
@ -642,39 +664,48 @@ CMICmnLLDBDebugger::MonitorSBListenerEvents(bool &vrbIsAlive)
{
vrbIsAlive = true;
// Lock the mutex of event queue
// Note that it should be locked while we are in CMICmnLLDBDebugger::MonitorSBListenerEvents to
// avoid a race condition with CMICmnLLDBDebugger::WaitForHandleEvent
std::unique_lock<std::mutex> lock(m_mutexEventQueue);
lldb::SBEvent event;
const bool bGotEvent = m_lldbListener.GetNextEvent(event);
if (!bGotEvent || !event.IsValid())
if (!bGotEvent)
{
// Notify that we are finished and unlock the mutex of event queue before sleeping
m_conditionEventQueueEmpty.notify_one();
lock.unlock();
// Wait a bit to reduce CPU load
const std::chrono::milliseconds time(1);
std::this_thread::sleep_for(time);
return MIstatus::success;
}
if (!event.GetBroadcaster().IsValid())
return MIstatus::success;
assert(event.IsValid());
assert(event.GetBroadcaster().IsValid());
// Debugging
m_pLog->WriteLog(CMIUtilString::Format("##### An event occurred: %s", event.GetBroadcasterClass()));
bool bHandledEvent = false;
bool bOk = false;
{
// Lock Mutex before handling events so that we don't disturb a running cmd
CMIUtilThreadLock lock(CMICmnLLDBDebugSessionInfo::Instance().GetSessionMutex());
bOk = CMICmnLLDBDebuggerHandleEvents::Instance().HandleEvent(event, bHandledEvent);
}
if (!bHandledEvent)
{
const CMIUtilString msg(CMIUtilString::Format(MIRSRC(IDS_LLDBDEBUGGER_WRN_UNKNOWN_EVENT), event.GetBroadcasterClass()));
m_pLog->WriteLog(msg);
}
if (!bOk)
{
m_pLog->WriteLog(CMICmnLLDBDebuggerHandleEvents::Instance().GetErrorDescription());
}
return bOk;
if (!bOk)
m_pLog->WriteLog(CMICmnLLDBDebuggerHandleEvents::Instance().GetErrorDescription());
return MIstatus::success;
}
//++ ------------------------------------------------------------------------------------

View File

@ -10,8 +10,9 @@
#pragma once
// Third party headers
#include <queue>
#include <condition_variable>
#include <map>
#include <mutex>
#include "lldb/API/SBDebugger.h"
#include "lldb/API/SBListener.h"
#include "lldb/API/SBEvent.h"
@ -48,6 +49,7 @@ class CMICmnLLDBDebugger : public CMICmnBase, public CMIUtilThreadActiveObjBase,
CMIDriverBase &GetDriver(void) const;
lldb::SBDebugger &GetTheDebugger(void);
lldb::SBListener &GetTheListener(void);
void WaitForHandleEvent(void);
// MI Commands can use these functions to listen for events they require
bool RegisterForEvent(const CMIUtilString &vClientName, const CMIUtilString &vBroadcasterClass, const MIuint vEventMask);
@ -106,4 +108,6 @@ class CMICmnLLDBDebugger : public CMICmnBase, public CMIUtilThreadActiveObjBase,
const CMIUtilString m_constStrThisThreadId;
MapBroadcastClassNameToEventMask_t m_mapBroadcastClassNameToEventMask;
MapIdToEventMask_t m_mapIdToEventMask;
std::mutex m_mutexEventQueue;
std::condition_variable m_conditionEventQueueEmpty;
};

View File

@ -536,12 +536,8 @@ CMIDriver::DoMainLoop(void)
CMIUtilString lineText(pCmd);
if (!lineText.empty ())
{
if (lineText == "quit")
{
// We want to be exiting when receiving a quit command
m_bExitApp = true;
break;
}
// Check that the handler thread is alive (otherwise we stuck here)
assert(CMICmnLLDBDebugger::Instance().ThreadIsActive());
{
// Lock Mutex before processing commands so that we don't disturb an event
@ -549,9 +545,13 @@ CMIDriver::DoMainLoop(void)
CMIUtilThreadLock lock(CMICmnLLDBDebugSessionInfo::Instance().GetSessionMutex());
bOk = InterpretCommand(lineText);
}
// Draw prompt if desired
if (bOk && m_rStdin.GetEnablePrompt())
bOk = m_rStdOut.WriteMIResponse(m_rStdin.GetPrompt());
// Wait while the handler thread handles incoming events
CMICmnLLDBDebugger::Instance().WaitForHandleEvent();
}
}
}