summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lldb/include/lldb/Core/Debugger.h9
-rw-r--r--lldb/include/lldb/Core/IOHandler.h145
-rw-r--r--lldb/include/lldb/Core/StreamAsynchronousIO.h8
-rw-r--r--lldb/include/lldb/Host/Editline.h18
-rw-r--r--lldb/include/lldb/Target/Process.h16
-rw-r--r--lldb/source/Commands/CommandObjectProcess.cpp10
-rw-r--r--lldb/source/Commands/CommandObjectThread.cpp4
-rw-r--r--lldb/source/Core/Debugger.cpp188
-rw-r--r--lldb/source/Core/IOHandler.cpp71
-rw-r--r--lldb/source/Core/StreamAsynchronousIO.cpp25
-rw-r--r--lldb/source/Host/common/Editline.cpp105
-rw-r--r--lldb/source/Interpreter/ScriptInterpreterPython.cpp35
-rw-r--r--lldb/source/Target/Process.cpp80
13 files changed, 312 insertions, 402 deletions
diff --git a/lldb/include/lldb/Core/Debugger.h b/lldb/include/lldb/Core/Debugger.h
index d18e896a8b4..0d9b90c8919 100644
--- a/lldb/include/lldb/Core/Debugger.h
+++ b/lldb/include/lldb/Core/Debugger.h
@@ -210,6 +210,9 @@ public:
bool
IsTopIOHandler (const lldb::IOHandlerSP& reader_sp);
+ void
+ PrintAsync (const char *s, size_t len, bool is_stdout);
+
ConstString
GetTopIOHandlerControlSequence(char ch);
@@ -219,12 +222,6 @@ public:
const char *
GetIOHandlerHelpPrologue();
- bool
- HideTopIOHandler();
-
- void
- RefreshTopIOHandler();
-
static lldb::DebuggerSP
FindDebuggerWithID (lldb::user_id_t id);
diff --git a/lldb/include/lldb/Core/IOHandler.h b/lldb/include/lldb/Core/IOHandler.h
index d750a23533d..8abdeabbb19 100644
--- a/lldb/include/lldb/Core/IOHandler.h
+++ b/lldb/include/lldb/Core/IOHandler.h
@@ -67,18 +67,6 @@ namespace lldb_private {
virtual void
Run () = 0;
- // Hide any characters that have been displayed so far so async
- // output can be displayed. Refresh() will be called after the
- // output has been displayed.
- virtual void
- Hide () = 0;
-
- // Called when the async output has been received in order to update
- // the input reader (refresh the prompt and redisplay any current
- // line(s) that are being edited
- virtual void
- Refresh () = 0;
-
// Called when an input reader should relinquish its control so another
// can be pushed onto the IO handler stack, or so the current IO
// handler can pop itself off the stack
@@ -246,7 +234,14 @@ namespace lldb_private {
void
WaitForPop ();
-
+
+ virtual void
+ PrintAsync (Stream *stream, const char *s, size_t len)
+ {
+ stream->Write (s, len);
+ stream->Flush();
+ }
+
protected:
Debugger &m_debugger;
lldb::StreamFileSP m_input_sp;
@@ -448,17 +443,17 @@ namespace lldb_private {
{
}
- virtual ConstString
- IOHandlerGetControlSequence (char ch)
+ ConstString
+ IOHandlerGetControlSequence (char ch) override
{
if (ch == 'd')
return ConstString (m_end_line + "\n");
return ConstString();
}
- virtual bool
+ bool
IOHandlerIsInputComplete (IOHandler &io_handler,
- StringList &lines)
+ StringList &lines) override
{
// Determine whether the end of input signal has been entered
const size_t num_lines = lines.GetSize();
@@ -507,53 +502,47 @@ namespace lldb_private {
virtual
~IOHandlerEditline ();
- virtual void
- Run ();
+ void
+ Run () override;
- virtual void
- Hide ();
-
- virtual void
- Refresh ();
-
- virtual void
- Cancel ();
+ void
+ Cancel () override;
- virtual bool
- Interrupt ();
+ bool
+ Interrupt () override;
- virtual void
- GotEOF();
+ void
+ GotEOF() override;
- virtual void
- Activate ();
+ void
+ Activate () override;
- virtual void
- Deactivate ();
+ void
+ Deactivate () override;
- virtual ConstString
- GetControlSequence (char ch)
+ ConstString
+ GetControlSequence (char ch) override
{
return m_delegate.IOHandlerGetControlSequence (ch);
}
- virtual const char *
- GetCommandPrefix ()
+ const char *
+ GetCommandPrefix () override
{
return m_delegate.IOHandlerGetCommandPrefix ();
}
- virtual const char *
- GetHelpPrologue ()
+ const char *
+ GetHelpPrologue () override
{
return m_delegate.IOHandlerGetHelpPrologue ();
}
- virtual const char *
- GetPrompt ();
+ const char *
+ GetPrompt () override;
- virtual bool
- SetPrompt (const char *prompt);
+ bool
+ SetPrompt (const char *prompt) override;
const char *
GetContinuationPrompt ();
@@ -591,6 +580,9 @@ namespace lldb_private {
uint32_t
GetCurrentLineIndex () const;
+ void
+ PrintAsync (Stream *stream, const char *s, size_t len) override;
+
private:
#ifndef LLDB_DISABLE_LIBEDIT
static bool
@@ -649,17 +641,17 @@ namespace lldb_private {
return m_user_response;
}
- virtual int
+ int
IOHandlerComplete (IOHandler &io_handler,
const char *current_line,
const char *cursor,
const char *last_char,
int skip_first_n_matches,
int max_matches,
- StringList &matches);
+ StringList &matches) override;
- virtual void
- IOHandlerInputComplete (IOHandler &io_handler, std::string &data);
+ void
+ IOHandlerInputComplete (IOHandler &io_handler, std::string &data) override;
protected:
const bool m_default_response;
@@ -672,32 +664,25 @@ namespace lldb_private {
public:
IOHandlerCursesGUI (Debugger &debugger);
- virtual
- ~IOHandlerCursesGUI ();
-
- virtual void
- Run ();
+ ~IOHandlerCursesGUI () override;
- virtual void
- Hide ();
+ void
+ Run () override;
- virtual void
- Refresh ();
-
- virtual void
- Cancel ();
+ void
+ Cancel () override;
- virtual bool
- Interrupt ();
+ bool
+ Interrupt () override;
- virtual void
- GotEOF();
+ void
+ GotEOF() override;
- virtual void
- Activate ();
+ void
+ Activate () override;
- virtual void
- Deactivate ();
+ void
+ Deactivate () override;
protected:
curses::ApplicationAP m_app_ap;
@@ -712,20 +697,11 @@ namespace lldb_private {
virtual
~IOHandlerCursesValueObjectList ();
- virtual void
- Run ();
-
- virtual void
- Hide ();
-
- virtual void
- Refresh ();
-
- virtual bool
- HandleInterrupt ();
+ void
+ Run () override;
- virtual void
- GotEOF();
+ void
+ GotEOF() override;
protected:
ValueObjectList m_valobj_list;
};
@@ -850,7 +826,10 @@ namespace lldb_private {
return NULL;
}
- protected:
+ void
+ PrintAsync (Stream *stream, const char *s, size_t len);
+
+ protected:
typedef std::vector<lldb::IOHandlerSP> collection;
collection m_stack;
diff --git a/lldb/include/lldb/Core/StreamAsynchronousIO.h b/lldb/include/lldb/Core/StreamAsynchronousIO.h
index a73a9567fe8..d3b054463fa 100644
--- a/lldb/include/lldb/Core/StreamAsynchronousIO.h
+++ b/lldb/include/lldb/Core/StreamAsynchronousIO.h
@@ -20,7 +20,7 @@ class StreamAsynchronousIO :
public Stream
{
public:
- StreamAsynchronousIO (Broadcaster &broadcaster, uint32_t broadcast_event_type);
+ StreamAsynchronousIO (Debugger &debugger, bool for_stdout);
virtual ~StreamAsynchronousIO ();
@@ -32,9 +32,9 @@ public:
private:
- Broadcaster &m_broadcaster;
- uint32_t m_broadcast_event_type;
- std::string m_accumulated_data;
+ Debugger &m_debugger;
+ std::string m_data;
+ bool m_for_stdout;
};
} // namespace lldb_private
diff --git a/lldb/include/lldb/Host/Editline.h b/lldb/include/lldb/Host/Editline.h
index 9fce193efc9..697be4cd8e7 100644
--- a/lldb/include/lldb/Host/Editline.h
+++ b/lldb/include/lldb/Host/Editline.h
@@ -171,17 +171,13 @@ namespace lldb_private {
uint32_t
GetCurrentLine();
- /// Hides the current input session in preparation for output
- void
- Hide();
-
- /// Prepare to return to editing after a call to Hide()
- void
- Refresh();
-
/// Interrupt the current edit as if ^C was pressed
bool
Interrupt();
+
+ /// Cancel this edit and oblitarate all trace of it
+ bool
+ Cancel();
/// Register a callback for the tab key
void
@@ -207,6 +203,9 @@ namespace lldb_private {
bool
GetLines (int first_line_number, StringList &lines, bool &interrupted);
+ void
+ PrintAsync (Stream *stream, const char *s, size_t len);
+
private:
/// Sets the lowest line number for multi-line editing sessions. A value of zero suppresses
@@ -335,7 +334,6 @@ namespace lldb_private {
bool m_multiline_enabled = false;
std::vector<EditLineStringType> m_input_lines;
EditorStatus m_editor_status;
- bool m_editor_getting_char = false;
bool m_color_prompts = true;
int m_terminal_width = 0;
int m_base_line_number = 0;
@@ -359,6 +357,8 @@ namespace lldb_private {
const char * m_fix_indentation_callback_chars = nullptr;
CompleteCallbackType m_completion_callback = nullptr;
void * m_completion_callback_baton = nullptr;
+
+ Mutex m_output_mutex;
};
}
diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h
index 34e188dadc9..0be09b3ef33 100644
--- a/lldb/include/lldb/Target/Process.h
+++ b/lldb/include/lldb/Target/Process.h
@@ -2746,6 +2746,11 @@ public:
Listener *hijack_listener = NULL,
Stream *stream = NULL);
+ uint32_t
+ GetIOHandlerID () const
+ {
+ return m_iohandler_sync.GetValue();
+ }
//--------------------------------------------------------------------------------------
/// Waits for the process state to be running within a given msec timeout.
@@ -2756,14 +2761,9 @@ public:
/// @param[in] timeout_msec
/// The maximum time length to wait for the process to transition to the
/// eStateRunning state, specified in milliseconds.
- ///
- /// @return
- /// true if successfully signalled that process started and IOHandler pushes, false
- /// if it timed out.
//--------------------------------------------------------------------------------------
- bool
- SyncIOHandler (uint64_t timeout_msec);
-
+ void
+ SyncIOHandler (uint32_t iohandler_id, uint64_t timeout_msec);
lldb::StateType
WaitForStateChangedEvents (const TimeValue *timeout,
@@ -3186,7 +3186,7 @@ protected:
std::string m_stderr_data;
Mutex m_profile_data_comm_mutex;
std::vector<std::string> m_profile_data;
- Predicate<bool> m_iohandler_sync;
+ Predicate<uint32_t> m_iohandler_sync;
MemoryCache m_memory_cache;
AllocatedMemoryCache m_allocated_memory_cache;
bool m_should_detach; /// Should we detach if the process object goes away with an explicit call to Kill or Detach?
diff --git a/lldb/source/Commands/CommandObjectProcess.cpp b/lldb/source/Commands/CommandObjectProcess.cpp
index 14b7e2f74c5..e9ca8026b0e 100644
--- a/lldb/source/Commands/CommandObjectProcess.cpp
+++ b/lldb/source/Commands/CommandObjectProcess.cpp
@@ -270,7 +270,7 @@ protected:
// There is a race condition where this thread will return up the call stack to the main command
// handler and show an (lldb) prompt before HandlePrivateEvent (from PrivateStateThread) has
// a chance to call PushProcessIOHandler().
- process_sp->SyncIOHandler(2000);
+ process_sp->SyncIOHandler (0, 2000);
const char *data = stream.GetData();
if (data && strlen(data) > 0)
@@ -762,6 +762,8 @@ protected:
}
}
+ const uint32_t iohandler_id = process->GetIOHandlerID();
+
StreamString stream;
Error error;
if (synchronous_execution)
@@ -772,9 +774,9 @@ protected:
if (error.Success())
{
// There is a race condition where this thread will return up the call stack to the main command
- // handler and show an (lldb) prompt before HandlePrivateEvent (from PrivateStateThread) has
- // a chance to call PushProcessIOHandler().
- process->SyncIOHandler(2000);
+ // handler and show an (lldb) prompt before HandlePrivateEvent (from PrivateStateThread) has
+ // a chance to call PushProcessIOHandler().
+ process->SyncIOHandler(iohandler_id, 2000);
result.AppendMessageWithFormat ("Process %" PRIu64 " resuming\n", process->GetID());
if (synchronous_execution)
diff --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp
index 78271f25c66..8fb962948c0 100644
--- a/lldb/source/Commands/CommandObjectThread.cpp
+++ b/lldb/source/Commands/CommandObjectThread.cpp
@@ -675,6 +675,8 @@ protected:
process->GetThreadList().SetSelectedThreadByID (thread->GetID());
+ const uint32_t iohandler_id = process->GetIOHandlerID();
+
StreamString stream;
Error error;
if (synchronous_execution)
@@ -685,7 +687,7 @@ protected:
// There is a race condition where this thread will return up the call stack to the main command handler
// and show an (lldb) prompt before HandlePrivateEvent (from PrivateStateThread) has
// a chance to call PushProcessIOHandler().
- process->SyncIOHandler(2000);
+ process->SyncIOHandler(iohandler_id, 2000);
if (synchronous_execution)
{
diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp
index ee2354e7b50..2f7dd9f42a5 100644
--- a/lldb/source/Core/Debugger.cpp
+++ b/lldb/source/Core/Debugger.cpp
@@ -885,34 +885,27 @@ Debugger::ClearIOHandlers ()
{
IOHandlerSP reader_sp (m_input_reader_stack.Top());
if (reader_sp)
- {
- m_input_reader_stack.Pop();
- reader_sp->SetIsDone(true);
- reader_sp->Cancel();
- }
+ PopIOHandler (reader_sp);
}
}
void
Debugger::ExecuteIOHandlers()
{
-
while (1)
{
IOHandlerSP reader_sp(m_input_reader_stack.Top());
if (!reader_sp)
break;
- reader_sp->Activate();
reader_sp->Run();
- reader_sp->Deactivate();
// Remove all input readers that are done from the top of the stack
while (1)
{
IOHandlerSP top_reader_sp = m_input_reader_stack.Top();
if (top_reader_sp && top_reader_sp->GetIsDone())
- m_input_reader_stack.Pop();
+ PopIOHandler (top_reader_sp);
else
break;
}
@@ -926,6 +919,12 @@ Debugger::IsTopIOHandler (const lldb::IOHandlerSP& reader_sp)
return m_input_reader_stack.IsTop (reader_sp);
}
+void
+Debugger::PrintAsync (const char *s, size_t len, bool is_stdout)
+{
+ lldb::StreamFileSP stream = is_stdout ? GetOutputFile() : GetErrorFile();
+ m_input_reader_stack.PrintAsync(stream.get(), s, len);
+}
ConstString
Debugger::GetTopIOHandlerControlSequence(char ch)
@@ -949,25 +948,23 @@ void
Debugger::RunIOHandler (const IOHandlerSP& reader_sp)
{
PushIOHandler (reader_sp);
-
+
IOHandlerSP top_reader_sp = reader_sp;
while (top_reader_sp)
{
- top_reader_sp->Activate();
top_reader_sp->Run();
- top_reader_sp->Deactivate();
-
+
if (top_reader_sp.get() == reader_sp.get())
{
if (PopIOHandler (reader_sp))
break;
}
-
+
while (1)
{
top_reader_sp = m_input_reader_stack.Top();
if (top_reader_sp && top_reader_sp->GetIsDone())
- m_input_reader_stack.Pop();
+ PopIOHandler (top_reader_sp);
else
break;
}
@@ -1030,87 +1027,67 @@ Debugger::PushIOHandler (const IOHandlerSP& reader_sp)
if (!reader_sp)
return;
- // Got the current top input reader...
+ Mutex::Locker locker (m_input_reader_stack.GetMutex());
+
+ // Get the current top input reader...
IOHandlerSP top_reader_sp (m_input_reader_stack.Top());
// Don't push the same IO handler twice...
- if (reader_sp.get() != top_reader_sp.get())
- {
- // Push our new input reader
- m_input_reader_stack.Push (reader_sp);
+ if (reader_sp == top_reader_sp)
+ return;
- // Interrupt the top input reader to it will exit its Run() function
- // and let this new input reader take over
- if (top_reader_sp)
- top_reader_sp->Deactivate();
+ // Push our new input reader
+ m_input_reader_stack.Push (reader_sp);
+ reader_sp->Activate();
+
+ // Interrupt the top input reader to it will exit its Run() function
+ // and let this new input reader take over
+ if (top_reader_sp)
+ {
+ top_reader_sp->Deactivate();
+ top_reader_sp->Cancel();
}
}
bool
Debugger::PopIOHandler (const IOHandlerSP& pop_reader_sp)
{
- bool result = false;
-
+ if (! pop_reader_sp)
+ return false;
+
Mutex::Locker locker (m_input_reader_stack.GetMutex());
// The reader on the stop of the stack is done, so let the next
// read on the stack refresh its prompt and if there is one...
- if (!m_input_reader_stack.IsEmpty())
- {
- IOHandlerSP reader_sp(m_input_reader_stack.Top());
-
- if (!pop_reader_sp || pop_reader_sp.get() == reader_sp.get())
- {
- reader_sp->Deactivate();
- reader_sp->Cancel();
- m_input_reader_stack.Pop ();
-
- reader_sp = m_input_reader_stack.Top();
- if (reader_sp)
- reader_sp->Activate();
-
- result = true;
- }
- }
- return result;
-}
+ if (m_input_reader_stack.IsEmpty())
+ return false;
-bool
-Debugger::HideTopIOHandler()
-{
- Mutex::Locker locker;
-
- if (locker.TryLock(m_input_reader_stack.GetMutex()))
- {
- IOHandlerSP reader_sp(m_input_reader_stack.Top());
- if (reader_sp)
- reader_sp->Hide();
- return true;
- }
- return false;
-}
-
-void
-Debugger::RefreshTopIOHandler()
-{
IOHandlerSP reader_sp(m_input_reader_stack.Top());
+
+ if (pop_reader_sp != reader_sp)
+ return false;
+
+ reader_sp->Deactivate();
+ reader_sp->Cancel();
+ m_input_reader_stack.Pop ();
+
+ reader_sp = m_input_reader_stack.Top();
if (reader_sp)
- reader_sp->Refresh();
-}
+ reader_sp->Activate();
+ return true;
+}
StreamSP
Debugger::GetAsyncOutputStream ()
{
- return StreamSP (new StreamAsynchronousIO (GetCommandInterpreter(),
- CommandInterpreter::eBroadcastBitAsynchronousOutputData));
+ return StreamSP (new StreamAsynchronousIO (*this, true));
}
StreamSP
Debugger::GetAsyncErrorStream ()
{
- return StreamSP (new StreamAsynchronousIO (GetCommandInterpreter(),
- CommandInterpreter::eBroadcastBitAsynchronousErrorData));
+ return StreamSP (new StreamAsynchronousIO (*this, false));
}
size_t
@@ -1396,14 +1373,14 @@ Debugger::HandleBreakpointEvent (const EventSP &event_sp)
if (num_new_locations > 0)
{
BreakpointSP breakpoint = Breakpoint::BreakpointEventData::GetBreakpointFromEvent(event_sp);
- StreamFileSP output_sp (GetOutputFile());
+ StreamSP output_sp (GetAsyncOutputStream());
if (output_sp)
{
output_sp->Printf("%d location%s added to breakpoint %d\n",
num_new_locations,
num_new_locations == 1 ? "" : "s",
breakpoint->GetID());
- RefreshTopIOHandler();
+ output_sp->Flush();
}
}
}
@@ -1490,8 +1467,8 @@ Debugger::HandleProcessEvent (const EventSP &event_sp)
const uint32_t event_type = event_sp->GetType();
ProcessSP process_sp = Process::ProcessEventData::GetProcessFromEvent(event_sp.get());
- StreamString output_stream;
- StreamString error_stream;
+ StreamSP output_stream_sp = GetAsyncOutputStream();
+ StreamSP error_stream_sp = GetAsyncErrorStream();
const bool gui_enabled = IsForwardingEvents();
if (!gui_enabled)
@@ -1499,47 +1476,43 @@ Debugger::HandleProcessEvent (const EventSP &event_sp)
bool pop_process_io_handler = false;
assert (process_sp);
- if (event_type & Process::eBroadcastBitSTDOUT || event_type & Process::eBroadcastBitStateChanged)
+ bool state_is_stopped = false;
+ const bool got_state_changed = (event_type & Process::eBroadcastBitStateChanged) != 0;
+ const bool got_stdout = (event_type & Process::eBroadcastBitSTDOUT) != 0;
+ const bool got_stderr = (event_type & Process::eBroadcastBitSTDERR) != 0;
+ if (got_state_changed)
{
- GetProcessSTDOUT (process_sp.get(), &output_stream);
+ StateType event_state = Process::ProcessEventData::GetStateFromEvent (event_sp.get());
+ state_is_stopped = StateIsStoppedState(event_state, false);
}
- if (event_type & Process::eBroadcastBitSTDERR || event_type & Process::eBroadcastBitStateChanged)
+ // Display running state changes first before any STDIO
+ if (got_state_changed && !state_is_stopped)
{
- GetProcessSTDERR (process_sp.get(), &error_stream);
+ Process::HandleProcessStateChangedEvent (event_sp, output_stream_sp.get(), pop_process_io_handler);
}
- if (event_type & Process::eBroadcastBitStateChanged)
+ // Now display and STDOUT
+ if (got_stdout || got_state_changed)
{
- Process::HandleProcessStateChangedEvent (event_sp, &output_stream, pop_process_io_handler);
+ GetProcessSTDOUT (process_sp.get(), output_stream_sp.get());
}
- if (output_stream.GetSize() || error_stream.GetSize())
+ // Now display and STDERR
+ if (got_stderr || got_state_changed)
{
- StreamFileSP error_stream_sp (GetOutputFile());
- bool top_io_handler_hid = false;
-
- if (process_sp->ProcessIOHandlerExists() && process_sp->ProcessIOHandlerIsActive() == false)
- top_io_handler_hid = HideTopIOHandler();
-
- if (output_stream.GetSize())
- {
- StreamFileSP output_stream_sp (GetOutputFile());
- if (output_stream_sp)
- output_stream_sp->Write (output_stream.GetData(), output_stream.GetSize());
- }
-
- if (error_stream.GetSize())
- {
- StreamFileSP error_stream_sp (GetErrorFile());
- if (error_stream_sp)
- error_stream_sp->Write (error_stream.GetData(), error_stream.GetSize());
- }
+ GetProcessSTDERR (process_sp.get(), error_stream_sp.get());
+ }
- if (top_io_handler_hid)
- RefreshTopIOHandler();
+ // Now display any stopped state changes after any STDIO
+ if (got_state_changed && state_is_stopped)
+ {
+ Process::HandleProcessStateChangedEvent (event_sp, output_stream_sp.get(), pop_process_io_handler);
}
+ output_stream_sp->Flush();
+ error_stream_sp->Flush();
+
if (pop_process_io_handler)
process_sp->PopProcessIOHandler();
}
@@ -1558,10 +1531,7 @@ Debugger::HandleThreadEvent (const EventSP &event_sp)
ThreadSP thread_sp (Thread::ThreadEventData::GetThreadFromEvent (event_sp.get()));
if (thread_sp)
{
- HideTopIOHandler();
- StreamFileSP stream_sp (GetOutputFile());
- thread_sp->GetStatus(*stream_sp, 0, 1, 1);
- RefreshTopIOHandler();
+ thread_sp->GetStatus(*GetAsyncOutputStream(), 0, 1, 1);
}
}
}
@@ -1655,13 +1625,11 @@ Debugger::DefaultEventHandler()
const char *data = reinterpret_cast<const char *>(EventDataBytes::GetBytesFromEvent (event_sp.get()));
if (data && data[0])
{
- StreamFileSP error_sp (GetErrorFile());
+ StreamSP error_sp (GetAsyncErrorStream());
if (error_sp)
{
- HideTopIOHandler();
error_sp->PutCString(data);
error_sp->Flush();
- RefreshTopIOHandler();
}
}
}
@@ -1670,13 +1638,11 @@ Debugger::DefaultEventHandler()
const char *data = reinterpret_cast<const char *>(EventDataBytes::GetBytesFromEvent (event_sp.get()));
if (data && data[0])
{
- StreamFileSP output_sp (GetOutputFile());
+ StreamSP output_sp (GetAsyncOutputStream());
if (output_sp)
{
- HideTopIOHandler();
output_sp->PutCString(data);
output_sp->Flush();
- RefreshTopIOHandler();
}
}
}
diff --git a/lldb/source/Core/IOHandler.cpp b/lldb/source/Core/IOHandler.cpp
index b1ee57268ef..9cc280b6d70 100644
--- a/lldb/source/Core/IOHandler.cpp
+++ b/lldb/source/Core/IOHandler.cpp
@@ -169,6 +169,17 @@ IOHandler::WaitForPop ()
m_popped.WaitForValueEqualTo(true);
}
+void
+IOHandlerStack::PrintAsync (Stream *stream, const char *s, size_t len)
+{
+ if (stream)
+ {
+ Mutex::Locker locker (m_mutex);
+ if (m_top)
+ m_top->PrintAsync (stream, s, len);
+ }
+}
+
IOHandlerConfirm::IOHandlerConfirm (Debugger &debugger,
const char *prompt,
bool default_response) :
@@ -740,47 +751,11 @@ IOHandlerEditline::Run ()
}
void
-IOHandlerEditline::Hide ()
-{
-#ifndef LLDB_DISABLE_LIBEDIT
- if (m_editline_ap)
- m_editline_ap->Hide();
-#endif
-}
-
-
-void
-IOHandlerEditline::Refresh ()
-{
-#ifndef LLDB_DISABLE_LIBEDIT
- if (m_editline_ap)
- {
- m_editline_ap->Refresh();
- }
- else if (m_editing)
- {
-#endif
- const char *prompt = GetPrompt();
- if (prompt && prompt[0])
- {
- FILE *out = GetOutputFILE();
- if (out)
- {
- ::fprintf(out, "%s", prompt);
- ::fflush(out);
- }
- }
-#ifndef LLDB_DISABLE_LIBEDIT
- }
-#endif
-}
-
-void
IOHandlerEditline::Cancel ()
{
#ifndef LLDB_DISABLE_LIBEDIT
if (m_editline_ap)
- m_editline_ap->Interrupt ();
+ m_editline_ap->Cancel ();
#endif
}
@@ -807,6 +782,17 @@ IOHandlerEditline::GotEOF()
#endif
}
+void
+IOHandlerEditline::PrintAsync (Stream *stream, const char *s, size_t len)
+{
+#ifndef LLDB_DISABLE_LIBEDIT
+ if (m_editline_ap)
+ m_editline_ap->PrintAsync(stream, s, len);
+ else
+#endif
+ IOHandler::PrintAsync(stream, s, len);
+}
+
// we may want curses to be disabled for some builds
// for instance, windows
#ifndef LLDB_DISABLE_CURSES
@@ -5618,17 +5604,6 @@ IOHandlerCursesGUI::~IOHandlerCursesGUI ()
}
void
-IOHandlerCursesGUI::Hide ()
-{
-}
-
-
-void
-IOHandlerCursesGUI::Refresh ()
-{
-}
-
-void
IOHandlerCursesGUI::Cancel ()
{
}
diff --git a/lldb/source/Core/StreamAsynchronousIO.cpp b/lldb/source/Core/StreamAsynchronousIO.cpp
index 257982ab8b2..ccfde0c9a01 100644
--- a/lldb/source/Core/StreamAsynchronousIO.cpp
+++ b/lldb/source/Core/StreamAsynchronousIO.cpp
@@ -7,22 +7,20 @@
//
//===----------------------------------------------------------------------===//
-#include <stdio.h>
+#include "lldb/Core/StreamAsynchronousIO.h"
#include "lldb/lldb-private.h"
-#include "lldb/Core/Broadcaster.h"
-#include "lldb/Core/Event.h"
-#include "lldb/Core/StreamAsynchronousIO.h"
+#include "lldb/Core/Debugger.h"
using namespace lldb;
using namespace lldb_private;
-StreamAsynchronousIO::StreamAsynchronousIO (Broadcaster &broadcaster, uint32_t broadcast_event_type) :
+StreamAsynchronousIO::StreamAsynchronousIO (Debugger &debugger, bool for_stdout) :
Stream (0, 4, eByteOrderBig),
- m_broadcaster (broadcaster),
- m_broadcast_event_type (broadcast_event_type),
- m_accumulated_data ()
+ m_debugger (debugger),
+ m_data (),
+ m_for_stdout (for_stdout)
{
}
@@ -35,19 +33,16 @@ StreamAsynchronousIO::~StreamAsynchronousIO ()
void
StreamAsynchronousIO::Flush ()
{
- if (!m_accumulated_data.empty())
+ if (!m_data.empty())
{
- std::unique_ptr<EventDataBytes> data_bytes_ap (new EventDataBytes);
- // Let's swap the bytes to avoid LARGE string copies.
- data_bytes_ap->SwapBytes (m_accumulated_data);
- EventSP new_event_sp (new Event (m_broadcast_event_type, data_bytes_ap.release()));
- m_broadcaster.BroadcastEvent (new_event_sp);
+ m_debugger.PrintAsync (m_data.data(), m_data.size(), m_for_stdout);
+ m_data = std::move(std::string());
}
}
size_t
StreamAsynchronousIO::Write (const void *s, size_t length)
{
- m_accumulated_data.append ((const char *)s, length);
+ m_data.append ((const char *)s, length);
return length;
}
diff --git a/lldb/source/Host/common/Editline.cpp b/lldb/source/Host/common/Editline.cpp
index 3d0d4d3dfb8..0264c4b3309 100644
--- a/lldb/source/Host/common/Editline.cpp
+++ b/lldb/source/Host/common/Editline.cpp
@@ -20,6 +20,7 @@
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/Mutex.h"
+#include "lldb/Utility/LLDBAssert.h"
using namespace lldb_private;
using namespace lldb_private::line_editor;
@@ -581,9 +582,22 @@ Editline::GetCharacter (EditLineCharType * c)
{
lldb::ConnectionStatus status = lldb::eConnectionStatusSuccess;
char ch = 0;
- m_editor_getting_char = true;
+
+ // This mutex is locked by our caller (GetLine). Unlock it while we read a character
+ // (blocking operation), so we do not hold the mutex indefinitely. This gives a chance
+ // for someone to interrupt us. After Read returns, immediately lock the mutex again and
+ // check if we were interrupted.
+ m_output_mutex.Unlock();
int read_count = m_input_connection.Read(&ch, 1, UINT32_MAX, status, NULL);
- m_editor_getting_char = false;
+ m_output_mutex.Lock();
+ if (m_editor_status == EditorStatus::Interrupted)
+ {
+ while (read_count > 0 && status == lldb::eConnectionStatusSuccess)
+ read_count = m_input_connection.Read(&ch, 1, UINT32_MAX, status, NULL);
+ lldbassert(status == lldb::eConnectionStatusInterrupted);
+ return 0;
+ }
+
if (read_count)
{
#if LLDB_EDITLINE_USE_WCHAR
@@ -602,14 +616,12 @@ Editline::GetCharacter (EditLineCharType * c)
{
switch (status)
{
- case lldb::eConnectionStatusInterrupted:
- m_editor_status = EditorStatus::Interrupted;
- printf ("^C\n");
- return 0;
-
case lldb::eConnectionStatusSuccess: // Success
break;
+ case lldb::eConnectionStatusInterrupted:
+ lldbassert(0 && "Interrupts should have been handled above.");
+
case lldb::eConnectionStatusError: // Check GetError() for details
case lldb::eConnectionStatusTimedOut: // Request timed out
case lldb::eConnectionStatusEndOfFile: // End-of-file encountered
@@ -1252,41 +1264,31 @@ Editline::GetCurrentLine()
return m_current_line_index;
}
-void
-Editline::Hide()
-{
- // Make sure we're at a stable location waiting for input
- while (m_editor_status == EditorStatus::Editing && !m_editor_getting_char)
- {
- usleep(100000);
- }
-
- // Clear the existing input
- if (m_editor_status == EditorStatus::Editing)
- {
- MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockStart);
- fprintf(m_output_file, ANSI_CLEAR_BELOW);
- }
-}
-
-void
-Editline::Refresh()
+bool
+Editline::Interrupt()
{
- if (m_editor_status == EditorStatus::Editing)
- {
- DisplayInput();
- MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingCursor);
+ bool result = true;
+ Mutex::Locker locker(m_output_mutex);
+ if (m_editor_status == EditorStatus::Editing) {
+ fprintf(m_output_file, "^C\n");
+ result = m_input_connection.InterruptRead();
}
+ m_editor_status = EditorStatus::Interrupted;
+ return result;
}
bool
-Editline::Interrupt()
+Editline::Cancel()
{
- if (m_editor_status == EditorStatus::Editing)
- {
- return m_input_connection.InterruptRead();
+ bool result = true;
+ Mutex::Locker locker(m_output_mutex);
+ if (m_editor_status == EditorStatus::Editing) {
+ MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockStart);
+ fprintf(m_output_file, ANSI_CLEAR_BELOW);
+ result = m_input_connection.InterruptRead();
}
- return false; // Interrupt not handled as we weren't getting a line or lines
+ m_editor_status = EditorStatus::Interrupted;
+ return result;
}
void
@@ -1321,14 +1323,23 @@ Editline::GetLine (std::string &line, bool &interrupted)
m_input_lines = std::vector<EditLineStringType>();
m_input_lines.insert (m_input_lines.begin(), EditLineConstString(""));
+ Mutex::Locker locker(m_output_mutex);
+
+ lldbassert(m_editor_status != EditorStatus::Editing);
+ if (m_editor_status == EditorStatus::Interrupted)
+ {
+ m_editor_status = EditorStatus::Complete;
+ interrupted = true;
+ return true;
+ }
+
SetCurrentLine (0);
m_in_history = false;
m_editor_status = EditorStatus::Editing;
- m_editor_getting_char = false;
m_revert_cursor_index = -1;
#ifdef USE_SETUPTERM_WORKAROUND
- setupterm((char *)0, fileno(m_output_file), (int *)0);
+ setupterm((char *)0, fileno(m_output_file), (int *)0);
#endif
int count;
@@ -1366,12 +1377,12 @@ Editline::GetLines (int first_line_number, StringList &lines, bool &interrupted)
m_input_lines = std::vector<EditLineStringType>();
m_input_lines.insert (m_input_lines.begin(), EditLineConstString(""));
+ Mutex::Locker locker(m_output_mutex);
// Begin the line editing loop
DisplayInput();
SetCurrentLine (0);
MoveCursor (CursorLocation::BlockEnd, CursorLocation::BlockStart);
m_editor_status = EditorStatus::Editing;
- m_editor_getting_char = false;
m_in_history = false;
m_revert_cursor_index = -1;
@@ -1396,3 +1407,21 @@ Editline::GetLines (int first_line_number, StringList &lines, bool &interrupted)
}
return m_editor_status != EditorStatus::EndOfInput;
}
+
+void
+Editline::PrintAsync (Stream *stream, const char *s, size_t len)
+{
+ Mutex::Locker locker(m_output_mutex);
+ if (m_editor_status == EditorStatus::Editing)
+ {
+ MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockStart);
+ fprintf(m_output_file, ANSI_CLEAR_BELOW);
+ }
+ stream->Write (s, len);
+ stream->Flush();
+ if (m_editor_status == EditorStatus::Editing)
+ {
+ DisplayInput();
+ MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingCursor);
+ }
+}
diff --git a/lldb/source/Interpreter/ScriptInterpreterPython.cpp b/lldb/source/Interpreter/ScriptInterpreterPython.cpp
index 1e16fd3bdc6..188f7285776 100644
--- a/lldb/source/Interpreter/ScriptInterpreterPython.cpp
+++ b/lldb/source/Interpreter/ScriptInterpreterPython.cpp
@@ -734,22 +734,21 @@ public:
}
- virtual
- ~IOHandlerPythonInterpreter()
+ ~IOHandlerPythonInterpreter() override
{
}
- virtual ConstString
- GetControlSequence (char ch)
+ ConstString
+ GetControlSequence (char ch) override
{
if (ch == 'd')
return ConstString("quit()\n");
return ConstString();
}
- virtual void
- Run ()
+ void
+ Run () override
{
if (m_python)
{
@@ -795,32 +794,20 @@ public:
SetIsDone(true);
}
- virtual void
- Hide ()
- {
-
- }
-
- virtual void
- Refresh ()
- {
-
- }
-
- virtual void
- Cancel ()
+ void
+ Cancel () override
{
}
- virtual bool
- Interrupt ()
+ bool
+ Interrupt () override
{
return m_python->Interrupt();
}
- virtual void
- GotEOF()
+ void
+ GotEOF() override
{
}
diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp
index 896fb3fedda..f0bd9e3260e 100644
--- a/lldb/source/Target/Process.cpp
+++ b/lldb/source/Target/Process.cpp
@@ -740,7 +740,7 @@ Process::Process(Target &target, Listener &listener, const UnixSignalsSP &unix_s
m_stderr_data (),
m_profile_data_comm_mutex (Mutex::eMutexTypeRecursive),
m_profile_data (),
- m_iohandler_sync (false),
+ m_iohandler_sync (0),
m_memory_cache (*this),
m_allocated_memory_cache (*this),
m_should_detach (false),
@@ -949,33 +949,21 @@ Process::GetNextEvent (EventSP &event_sp)
return state;
}
-bool
-Process::SyncIOHandler (uint64_t timeout_msec)
+void
+Process::SyncIOHandler (uint32_t iohandler_id, uint64_t timeout_msec)
{
- bool timed_out = false;
-
// don't sync (potentially context switch) in case where there is no process IO
- if (m_process_input_reader)
- {
- TimeValue timeout = TimeValue::Now();
- timeout.OffsetWithMicroSeconds(timeout_msec*1000);
-
- m_iohandler_sync.WaitForValueEqualTo(true, &timeout, &timed_out);
-
- Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
- if(log)
- {
- if(timed_out)
- log->Printf ("Process::%s pid %" PRIu64 " (timeout=%" PRIu64 "ms): FAIL", __FUNCTION__, GetID (), timeout_msec);
- else
- log->Printf ("Process::%s pid %" PRIu64 ": SUCCESS", __FUNCTION__, GetID ());
- }
+ if (! m_process_input_reader)
+ return;
- // reset sync one-shot so it will be ready for next launch
- m_iohandler_sync.SetValue(false, eBroadcastNever);
- }
+ TimeValue timeout = TimeValue::Now();
+ timeout.OffsetWithMicroSeconds(timeout_msec*1000);
+ uint32_t new_iohandler_id = 0;
+ m_iohandler_sync.WaitForValueNotEqualTo(iohandler_id, new_iohandler_id, &timeout);
- return !timed_out;
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf("Process::%s waited for m_iohandler_sync to change from %u, new value is %u", __FUNCTION__, iohandler_id, new_iohandler_id);
}
StateType
@@ -4477,12 +4465,15 @@ Process::HandlePrivateEvent (EventSP &event_sp)
// Or don't push it if we are launching since it will come up stopped.
if (!GetTarget().GetDebugger().IsForwardingEvents() && new_state != eStateLaunching &&
new_state != eStateAttaching)
+ {
PushProcessIOHandler ();
- m_iohandler_sync.SetValue(true, eBroadcastAlways);
+ m_iohandler_sync.SetValue(m_iohandler_sync.GetValue()+1, eBroadcastAlways);
+ if (log)
+ log->Printf("Process::%s updated m_iohandler_sync to %d", __FUNCTION__, m_iohandler_sync.GetValue());
+ }
}
else if (StateIsStoppedState(new_state, false))
{
- m_iohandler_sync.SetValue(false, eBroadcastNever);
if (!Process::ProcessEventData::GetRestartedFromEvent(event_sp.get()))
{
// If the lldb_private::Debugger is handling the events, we don't
@@ -5125,8 +5116,8 @@ public:
// Each IOHandler gets to run until it is done. It should read data
// from the "in" and place output into "out" and "err and return
// when done.
- virtual void
- Run ()
+ void
+ Run () override
{
if (m_read_file.IsValid() && m_write_file.IsValid())
{
@@ -5204,33 +5195,16 @@ public:
SetIsDone(true);
}
- // Hide any characters that have been displayed so far so async
- // output can be displayed. Refresh() will be called after the
- // output has been displayed.
- virtual void
- Hide ()
- {
-
- }
- // Called when the async output has been received in order to update
- // the input reader (refresh the prompt and redisplay any current
- // line(s) that are being edited
- virtual void
- Refresh ()
- {
-
- }
-
- virtual void
- Cancel ()
+ void
+ Cancel () override
{
char ch = 'q'; // Send 'q' for quit
size_t bytes_written = 0;
m_pipe.Write(&ch, 1, bytes_written);
}
- virtual bool
- Interrupt ()
+ bool
+ Interrupt () override
{
// Do only things that are safe to do in an interrupt context (like in
// a SIGINT handler), like write 1 byte to a file descriptor. This will
@@ -5263,8 +5237,8 @@ public:
return false;
}
- virtual void
- GotEOF()
+ void
+ GotEOF() override
{
}
@@ -5313,6 +5287,10 @@ Process::PushProcessIOHandler ()
IOHandlerSP io_handler_sp (m_process_input_reader);
if (io_handler_sp)
{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf("Process::%s pushing IO handler", __FUNCTION__);
+
io_handler_sp->SetIsDone(false);
m_target.GetDebugger().PushIOHandler (io_handler_sp);
return true;