Debugger: Fix #11411.

CliContext/CommandLineUserInterface:
- Process the debug report event asynchronously. The missing lock that
  was fixed in commit 5ac34e5a78 highlighted
  a problem in how the CLI was handling the case where it was intended to
  exit immediately after saving a report, since it issued the quit request
  directly from the report event handler. This resulted in locking issues,
  as the team debugger would then attempt to tear itself down, during which
  it needs to acquire the team lock. However, that was already being held
  by the thread in which the CLI was initiating the quit, resulting in a
  deadlock.
This commit is contained in:
Rene Gollent
2014-11-04 19:21:20 -05:00
parent 9a6331459f
commit 8b9099b1b2
4 changed files with 42 additions and 23 deletions
@@ -97,6 +97,7 @@ CliContext::CliContext()
fInputLoopWaitingForEvents(0), fInputLoopWaitingForEvents(0),
fEventsOccurred(0), fEventsOccurred(0),
fInputLoopWaiting(false), fInputLoopWaiting(false),
fInteractive(true),
fTerminating(false), fTerminating(false),
fCurrentThread(NULL), fCurrentThread(NULL),
fCurrentStackTrace(NULL), fCurrentStackTrace(NULL),
@@ -207,6 +208,13 @@ CliContext::Terminating()
} }
void
CliContext::SetInteractive(bool interactive)
{
fInteractive = interactive;
}
thread_id thread_id
CliContext::CurrentThreadID() const CliContext::CurrentThreadID() const
{ {
@@ -444,6 +452,13 @@ CliContext::ProcessPendingEvents()
fExpressionValue->AcquireReference(); fExpressionValue->AcquireReference();
} }
break; break;
case EVENT_DEBUG_REPORT_CHANGED:
if (!IsInteractive()) {
Terminating();
QuitSession(true);
}
break;
} }
} }
} }
@@ -503,6 +518,17 @@ CliContext::ExpressionEvaluated(const Team::ExpressionEvaluationEvent& event)
} }
void
CliContext::DebugReportChanged(const Team::DebugReportEvent& event)
{
printf("Successfully saved debug report to %s\n",
event.GetReportPath());
_QueueEvent(new(std::nothrow) Event(EVENT_DEBUG_REPORT_CHANGED));
_SignalInputLoop(EVENT_DEBUG_REPORT_CHANGED);
}
void void
CliContext::MemoryBlockRetrieved(TeamMemoryBlock* block) CliContext::MemoryBlockRetrieved(TeamMemoryBlock* block)
{ {
@@ -39,7 +39,8 @@ public:
EVENT_THREAD_STACK_TRACE_CHANGED = 0x20, EVENT_THREAD_STACK_TRACE_CHANGED = 0x20,
EVENT_VALUE_NODE_CHANGED = 0x40, EVENT_VALUE_NODE_CHANGED = 0x40,
EVENT_TEAM_MEMORY_BLOCK_RETRIEVED = 0x80, EVENT_TEAM_MEMORY_BLOCK_RETRIEVED = 0x80,
EVENT_EXPRESSION_EVALUATED = 0x100 EVENT_EXPRESSION_EVALUATED = 0x100,
EVENT_DEBUG_REPORT_CHANGED = 0x200
}; };
public: public:
@@ -54,6 +55,9 @@ public:
bool IsTerminating() const { return fTerminating; } bool IsTerminating() const { return fTerminating; }
bool IsInteractive() const { return fInteractive; }
void SetInteractive(bool interactive);
// service methods for the input loop thread follow // service methods for the input loop thread follow
Team* GetTeam() const { return fTeam; } Team* GetTeam() const { return fTeam; }
@@ -110,6 +114,9 @@ private:
const Team::ExpressionEvaluationEvent& const Team::ExpressionEvaluationEvent&
event); event);
virtual void DebugReportChanged(
const Team::DebugReportEvent& event);
// TeamMemoryBlock::Listener // TeamMemoryBlock::Listener
virtual void MemoryBlockRetrieved(TeamMemoryBlock* block); virtual void MemoryBlockRetrieved(TeamMemoryBlock* block);
@@ -141,6 +148,7 @@ private:
uint32 fInputLoopWaitingForEvents; uint32 fInputLoopWaitingForEvents;
uint32 fEventsOccurred; uint32 fEventsOccurred;
bool fInputLoopWaiting; bool fInputLoopWaiting;
bool fInteractive;
volatile bool fTerminating; volatile bool fTerminating;
Thread* fCurrentThread; Thread* fCurrentThread;
@@ -128,6 +128,8 @@ CommandLineUserInterface::Init(Team* team, UserInterfaceListener* listener)
if (error != B_OK) if (error != B_OK)
return error; return error;
fContext.SetInteractive(!fSaveReport);
error = _RegisterCommands(); error = _RegisterCommands();
if (error != B_OK) if (error != B_OK)
return error; return error;
@@ -229,11 +231,7 @@ CommandLineUserInterface::Run()
if (error != B_OK) if (error != B_OK)
return; return;
if (!fSaveReport) { if (fSaveReport) {
_InputLoop();
// Release the Show() semaphore to signal Terminate().
release_sem(fShowSemaphore);
} else {
ArgumentVector args; ArgumentVector args;
char buffer[256]; char buffer[256];
const char* parseErrorLocation; const char* parseErrorLocation;
@@ -245,6 +243,10 @@ CommandLineUserInterface::Run()
} else } else
_SubmitSaveReport(); _SubmitSaveReport();
} }
_InputLoop();
// Release the Show() semaphore to signal Terminate().
release_sem(fShowSemaphore);
} }
@@ -266,21 +268,6 @@ CommandLineUserInterface::ThreadStateChanged(const Team::ThreadEvent& event)
} }
void
CommandLineUserInterface::DebugReportChanged(
const Team::DebugReportEvent& event)
{
printf("Successfully saved debug report to %s\n",
event.GetReportPath());
if (fSaveReport) {
fContext.QuitSession(true);
// Release the Show() semaphore to signal Terminate().
release_sem(fShowSemaphore);
}
}
/*static*/ status_t /*static*/ status_t
CommandLineUserInterface::_InputLoopEntry(void* data) CommandLineUserInterface::_InputLoopEntry(void* data)
{ {
@@ -55,8 +55,6 @@ public:
// Team::Listener // Team::Listener
virtual void ThreadStateChanged( virtual void ThreadStateChanged(
const Team::ThreadEvent& event); const Team::ThreadEvent& event);
virtual void DebugReportChanged(
const Team::DebugReportEvent& event);
private: private:
struct CommandEntry; struct CommandEntry;