summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lldb/include/lldb/API/SBCommandInterpreter.h4
-rw-r--r--lldb/include/lldb/API/SBDebugger.h3
-rw-r--r--lldb/include/lldb/Core/Debugger.h3
-rw-r--r--lldb/include/lldb/Core/Event.h3
-rw-r--r--lldb/include/lldb/Core/StreamAsynchronousIO.h42
-rw-r--r--lldb/include/lldb/Interpreter/CommandInterpreter.h4
-rw-r--r--lldb/include/lldb/lldb-enumerations.h1
-rw-r--r--lldb/lldb.xcodeproj/project.pbxproj12
-rw-r--r--lldb/source/API/SBDebugger.cpp12
-rw-r--r--lldb/source/Commands/CommandObjectBreakpointCommand.cpp3
-rw-r--r--lldb/source/Commands/CommandObjectCommands.cpp5
-rw-r--r--lldb/source/Commands/CommandObjectExpression.cpp3
-rw-r--r--lldb/source/Commands/CommandObjectTarget.cpp3
-rw-r--r--lldb/source/Core/Debugger.cpp14
-rw-r--r--lldb/source/Core/Event.cpp7
-rw-r--r--lldb/source/Core/InputReader.cpp3
-rw-r--r--lldb/source/Core/StreamAsynchronousIO.cpp52
-rw-r--r--lldb/source/Interpreter/CommandInterpreter.cpp11
-rw-r--r--lldb/source/Interpreter/ScriptInterpreterPython.cpp6
-rw-r--r--lldb/source/Target/Process.cpp3
-rw-r--r--lldb/source/Target/Target.cpp12
-rw-r--r--lldb/tools/driver/Driver.cpp84
-rw-r--r--lldb/tools/driver/Driver.h2
-rw-r--r--lldb/tools/driver/IOChannel.cpp160
-rw-r--r--lldb/tools/driver/IOChannel.h18
25 files changed, 351 insertions, 119 deletions
diff --git a/lldb/include/lldb/API/SBCommandInterpreter.h b/lldb/include/lldb/API/SBCommandInterpreter.h
index 0ce9d4a588c..c3bda082478 100644
--- a/lldb/include/lldb/API/SBCommandInterpreter.h
+++ b/lldb/include/lldb/API/SBCommandInterpreter.h
@@ -21,7 +21,9 @@ public:
{
eBroadcastBitThreadShouldExit = (1 << 0),
eBroadcastBitResetPrompt = (1 << 1),
- eBroadcastBitQuitCommandReceived = (1 << 2) // User entered quit
+ eBroadcastBitQuitCommandReceived = (1 << 2), // User entered quit
+ eBroadcastBitAsynchronousOutputData = (1 << 3),
+ eBroadcastBitAsynchronousErrorData = (1 << 4)
};
SBCommandInterpreter (const lldb::SBCommandInterpreter &rhs);
diff --git a/lldb/include/lldb/API/SBDebugger.h b/lldb/include/lldb/API/SBDebugger.h
index a1dd5834c6c..64253be3582 100644
--- a/lldb/include/lldb/API/SBDebugger.h
+++ b/lldb/include/lldb/API/SBDebugger.h
@@ -163,6 +163,9 @@ public:
void
PushInputReader (lldb::SBInputReader &reader);
+ void
+ NotifyTopInputReader (lldb::InputReaderAction notification);
+
const char *
GetInstanceName ();
diff --git a/lldb/include/lldb/Core/Debugger.h b/lldb/include/lldb/Core/Debugger.h
index 6d7a29a3974..bdee600560c 100644
--- a/lldb/include/lldb/Core/Debugger.h
+++ b/lldb/include/lldb/Core/Debugger.h
@@ -388,6 +388,9 @@ public:
bool
PopInputReader (const lldb::InputReaderSP& reader_sp);
+ void
+ NotifyTopInputReader (lldb::InputReaderAction notification);
+
static lldb::DebuggerSP
FindDebuggerWithID (lldb::user_id_t id);
diff --git a/lldb/include/lldb/Core/Event.h b/lldb/include/lldb/Core/Event.h
index dd6988daaba..0fb6c67b08f 100644
--- a/lldb/include/lldb/Core/Event.h
+++ b/lldb/include/lldb/Core/Event.h
@@ -87,6 +87,9 @@ public:
void
SetBytes (const void *src, size_t src_len);
+
+ void
+ SwapBytes (std::string &new_bytes);
void
SetBytesFromCString (const char *cstr);
diff --git a/lldb/include/lldb/Core/StreamAsynchronousIO.h b/lldb/include/lldb/Core/StreamAsynchronousIO.h
new file mode 100644
index 00000000000..9dd798ce6d5
--- /dev/null
+++ b/lldb/include/lldb/Core/StreamAsynchronousIO.h
@@ -0,0 +1,42 @@
+//===-- StreamAsynchronousIO.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_StreamAsynchronousIO_h_
+#define liblldb_StreamAsynchronousIO_h_
+
+#include <string>
+
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamString.h"
+
+namespace lldb_private {
+
+class StreamAsynchronousIO :
+ public Stream
+{
+public:
+ StreamAsynchronousIO (Broadcaster &broadcaster, uint32_t broadcast_event_type);
+
+ virtual ~StreamAsynchronousIO ();
+
+ virtual void
+ Flush ();
+
+ virtual int
+ Write (const void *src, size_t src_len);
+
+
+private:
+ Broadcaster &m_broadcaster;
+ uint32_t m_broadcast_event_type;
+ StreamString m_accumulated_data;
+};
+
+} // namespace lldb_private
+#endif // #ifndef liblldb_StreamAsynchronousIO_h
diff --git a/lldb/include/lldb/Interpreter/CommandInterpreter.h b/lldb/include/lldb/Interpreter/CommandInterpreter.h
index 2f03c061a9b..5567f0c4e47 100644
--- a/lldb/include/lldb/Interpreter/CommandInterpreter.h
+++ b/lldb/include/lldb/Interpreter/CommandInterpreter.h
@@ -35,7 +35,9 @@ public:
{
eBroadcastBitThreadShouldExit = (1 << 0),
eBroadcastBitResetPrompt = (1 << 1),
- eBroadcastBitQuitCommandReceived = (1 << 2) // User entered quit
+ eBroadcastBitQuitCommandReceived = (1 << 2), // User entered quit
+ eBroadcastBitAsynchronousOutputData = (1 << 3),
+ eBroadcastBitAsynchronousErrorData = (1 << 4)
};
void
diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h
index a3388b8873a..f37b83293eb 100644
--- a/lldb/include/lldb/lldb-enumerations.h
+++ b/lldb/include/lldb/lldb-enumerations.h
@@ -265,6 +265,7 @@ namespace lldb {
typedef enum InputReaderAction
{
eInputReaderActivate, // reader is newly pushed onto the reader stack
+ eInputReaderAsynchronousOutputWritten, // an async output event occurred; the reader may want to do something
eInputReaderReactivate, // reader is on top of the stack again after another reader was popped off
eInputReaderDeactivate, // another reader was pushed on the stack
eInputReaderGotToken, // reader got one of its tokens (granularity)
diff --git a/lldb/lldb.xcodeproj/project.pbxproj b/lldb/lldb.xcodeproj/project.pbxproj
index 9932d37019c..2976fe09562 100644
--- a/lldb/lldb.xcodeproj/project.pbxproj
+++ b/lldb/lldb.xcodeproj/project.pbxproj
@@ -433,6 +433,8 @@
9A357673116E7B6400E8ED2F /* SBStringList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A357672116E7B6400E8ED2F /* SBStringList.cpp */; };
9A3576A8116E9AB700E8ED2F /* SBHostOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A3576A7116E9AB700E8ED2F /* SBHostOS.h */; settings = {ATTRIBUTES = (Public, ); }; };
9A3576AA116E9AC700E8ED2F /* SBHostOS.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A3576A9116E9AC700E8ED2F /* SBHostOS.cpp */; };
+ 9A4F35101368A51A00823F52 /* StreamAsynchronousIO.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A4F350F1368A51A00823F52 /* StreamAsynchronousIO.cpp */; };
+ 9A4F35121368A54100823F52 /* StreamAsynchronousIO.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A4F35111368A54100823F52 /* StreamAsynchronousIO.h */; };
9AA69DA61188F52100D753A0 /* PseudoTerminal.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2682F16A115EDA0D00CCFF99 /* PseudoTerminal.cpp */; };
9AA69DAF118A023300D753A0 /* SBInputReader.h in Headers */ = {isa = PBXBuildFile; fileRef = 9AA69DAE118A023300D753A0 /* SBInputReader.h */; settings = {ATTRIBUTES = (Public, ); }; };
9AA69DB1118A024600D753A0 /* SBInputReader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9AA69DB0118A024600D753A0 /* SBInputReader.cpp */; };
@@ -1192,6 +1194,8 @@
9A4633DA11F65D8600955CE1 /* UserSettingsController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UserSettingsController.h; path = include/lldb/Core/UserSettingsController.h; sourceTree = "<group>"; };
9A4633DC11F65D9A00955CE1 /* UserSettingsController.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UserSettingsController.cpp; path = source/Core/UserSettingsController.cpp; sourceTree = "<group>"; };
9A48A3A7124AAA5A00922451 /* python-extensions.swig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "python-extensions.swig"; sourceTree = "<group>"; };
+ 9A4F350F1368A51A00823F52 /* StreamAsynchronousIO.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StreamAsynchronousIO.cpp; path = source/Core/StreamAsynchronousIO.cpp; sourceTree = "<group>"; };
+ 9A4F35111368A54100823F52 /* StreamAsynchronousIO.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StreamAsynchronousIO.h; path = include/lldb/Core/StreamAsynchronousIO.h; sourceTree = "<group>"; };
9A633FE7112DCE3C001A7E43 /* SBFrame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBFrame.cpp; path = source/API/SBFrame.cpp; sourceTree = "<group>"; };
9A633FE8112DCE3C001A7E43 /* SBFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBFrame.h; path = include/lldb/API/SBFrame.h; sourceTree = "<group>"; };
9A82010B10FFB49800182560 /* ScriptInterpreter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ScriptInterpreter.cpp; path = source/Interpreter/ScriptInterpreter.cpp; sourceTree = "<group>"; };
@@ -1327,7 +1331,6 @@
26BC7E7510F1B85900F91463 /* lldb-log.cpp */,
26BC7C2A10F1B3BC00F91463 /* lldb-private.h */,
26217932133BCB850083B112 /* lldb-private-enumerations.h */,
- 26BC7C2810F1B3BC00F91463 /* lldb-private-interfaces.h */,
26BC7D5D10F1B77400F91463 /* lldb-private-log.h */,
26217930133BC8640083B112 /* lldb-private-types.h */,
262D3190111B4341004E6F88 /* API */,
@@ -1977,6 +1980,8 @@
26BC7D7810F1B77400F91463 /* STLUtils.h */,
26BC7D7910F1B77400F91463 /* Stream.h */,
26BC7E9110F1B85900F91463 /* Stream.cpp */,
+ 9A4F35111368A54100823F52 /* StreamAsynchronousIO.h */,
+ 9A4F350F1368A51A00823F52 /* StreamAsynchronousIO.cpp */,
26BC7D7A10F1B77400F91463 /* StreamFile.h */,
26BC7E9210F1B85900F91463 /* StreamFile.cpp */,
26BC7D7B10F1B77400F91463 /* StreamString.h */,
@@ -2176,6 +2181,7 @@
26BC7DBE10F1B78200F91463 /* Expression */ = {
isa = PBXGroup;
children = (
+ 26BC7C2810F1B3BC00F91463 /* lldb-private-interfaces.h */,
49D7072611B5AD03001AD875 /* ClangASTSource.h */,
49D7072811B5AD11001AD875 /* ClangASTSource.cpp */,
26BC7DC010F1B79500F91463 /* ClangExpression.h */,
@@ -2677,6 +2683,7 @@
2671A0CE134825F6003A87BB /* ConnectionMachPort.h in Headers */,
4CABA9DD134A8BA800539BDD /* ValueObjectMemory.h in Headers */,
4CD0BD0D134BFAB600CB44D4 /* ValueObjectDynamicValue.h in Headers */,
+ 9A4F35121368A54100823F52 /* StreamAsynchronousIO.h in Headers */,
4C2FAE2F135E3A70001EDE44 /* SharedCluster.h in Headers */,
2692BA16136610C100F9E14D /* UnwindAssemblyInstEmulation.h in Headers */,
);
@@ -3246,6 +3253,7 @@
26A7A035135E6E4200FB369E /* NamedOptionValue.cpp in Sources */,
9A22A161135E30370024DDC3 /* EmulateInstructionARM.cpp in Sources */,
9A22A163135E30370024DDC3 /* EmulationStateARM.cpp in Sources */,
+ 9A4F35101368A51A00823F52 /* StreamAsynchronousIO.cpp in Sources */,
2630BFAF1365F3220070C534 /* ArchDefaultUnwindPlan.cpp in Sources */,
2630BFB01365F3220070C534 /* ArchVolatileRegs.cpp in Sources */,
2692BA15136610C100F9E14D /* UnwindAssemblyInstEmulation.cpp in Sources */,
@@ -3336,7 +3344,7 @@
__STDC_LIMIT_MACROS,
LLDB_CONFIGURATION_DEBUG,
);
- GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
+ GCC_VERSION = 4.2;
GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
diff --git a/lldb/source/API/SBDebugger.cpp b/lldb/source/API/SBDebugger.cpp
index 84b13ab641e..04f15cbba3f 100644
--- a/lldb/source/API/SBDebugger.cpp
+++ b/lldb/source/API/SBDebugger.cpp
@@ -640,6 +640,18 @@ SBDebugger::PushInputReader (SBInputReader &reader)
}
void
+SBDebugger::NotifyTopInputReader (InputReaderAction notification)
+{
+ LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ log->Printf ("SBDebugger(%p)::NotifyTopInputReader (%d)", m_opaque_sp.get(), notification);
+
+ if (m_opaque_sp)
+ m_opaque_sp->NotifyTopInputReader (notification);
+}
+
+void
SBDebugger::reset (const DebuggerSP &debugger_sp)
{
m_opaque_sp = debugger_sp;
diff --git a/lldb/source/Commands/CommandObjectBreakpointCommand.cpp b/lldb/source/Commands/CommandObjectBreakpointCommand.cpp
index a188baebdeb..16466481fcf 100644
--- a/lldb/source/Commands/CommandObjectBreakpointCommand.cpp
+++ b/lldb/source/Commands/CommandObjectBreakpointCommand.cpp
@@ -466,6 +466,9 @@ CommandObjectBreakpointCommandAdd::GenerateBreakpointCommandCallback
}
break;
+ case eInputReaderAsynchronousOutputWritten:
+ break;
+
case eInputReaderGotToken:
if (bytes && bytes_len && baton)
{
diff --git a/lldb/source/Commands/CommandObjectCommands.cpp b/lldb/source/Commands/CommandObjectCommands.cpp
index 142f29d79e7..9d31cf7f1f9 100644
--- a/lldb/source/Commands/CommandObjectCommands.cpp
+++ b/lldb/source/Commands/CommandObjectCommands.cpp
@@ -975,7 +975,10 @@ CommandObjectCommandsAddRegex::InputReaderCallback (void *baton,
case eInputReaderDeactivate:
break;
-
+
+ case eInputReaderAsynchronousOutputWritten:
+ break;
+
case eInputReaderGotToken:
while (bytes_len > 0 && (bytes[bytes_len-1] == '\r' || bytes[bytes_len-1] == '\n'))
--bytes_len;
diff --git a/lldb/source/Commands/CommandObjectExpression.cpp b/lldb/source/Commands/CommandObjectExpression.cpp
index ed7824bd823..fa578f49987 100644
--- a/lldb/source/Commands/CommandObjectExpression.cpp
+++ b/lldb/source/Commands/CommandObjectExpression.cpp
@@ -205,6 +205,9 @@ CommandObjectExpression::MultiLineExpressionCallback
case eInputReaderDeactivate:
break;
+ case eInputReaderAsynchronousOutputWritten:
+ break;
+
case eInputReaderGotToken:
++cmd_object_expr->m_expr_line_count;
if (bytes && bytes_len)
diff --git a/lldb/source/Commands/CommandObjectTarget.cpp b/lldb/source/Commands/CommandObjectTarget.cpp
index 958aa2cf047..f7f873cd8f3 100644
--- a/lldb/source/Commands/CommandObjectTarget.cpp
+++ b/lldb/source/Commands/CommandObjectTarget.cpp
@@ -1032,6 +1032,9 @@ public:
}
break;
+ case eInputReaderAsynchronousOutputWritten:
+ break;
+
case eInputReaderGotToken:
if (bytes && bytes_len && baton)
{
diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp
index f1a64b98209..f328c626fd1 100644
--- a/lldb/source/Core/Debugger.cpp
+++ b/lldb/source/Core/Debugger.cpp
@@ -423,6 +423,20 @@ Debugger::CleanUpInputReaders ()
}
void
+Debugger::NotifyTopInputReader (InputReaderAction notification)
+{
+ InputReaderSP reader_sp (GetCurrentInputReader());
+ if (reader_sp)
+ {
+ reader_sp->Notify (notification);
+
+ // Flush out any input readers that are done.
+ while (CheckIfTopInputReaderIsDone ())
+ /* Do nothing. */;
+ }
+}
+
+void
Debugger::WriteToDefaultReader (const char *bytes, size_t bytes_len)
{
if (bytes && bytes_len)
diff --git a/lldb/source/Core/Event.cpp b/lldb/source/Core/Event.cpp
index 8b0ac16e2b6..ac122858c71 100644
--- a/lldb/source/Core/Event.cpp
+++ b/lldb/source/Core/Event.cpp
@@ -198,3 +198,10 @@ EventDataBytes::GetEventDataFromEvent (const Event *event_ptr)
return NULL;
}
+void
+EventDataBytes::SwapBytes (std::string &new_bytes)
+{
+ m_bytes.swap (new_bytes);
+}
+
+
diff --git a/lldb/source/Core/InputReader.cpp b/lldb/source/Core/InputReader.cpp
index fc94bed0834..26f7f842314 100644
--- a/lldb/source/Core/InputReader.cpp
+++ b/lldb/source/Core/InputReader.cpp
@@ -327,6 +327,9 @@ InputReader::Notify (InputReaderAction notification)
m_active = false;
break;
+ case eInputReaderAsynchronousOutputWritten:
+ break;
+
case eInputReaderInterrupt:
case eInputReaderEndOfFile:
break;
diff --git a/lldb/source/Core/StreamAsynchronousIO.cpp b/lldb/source/Core/StreamAsynchronousIO.cpp
new file mode 100644
index 00000000000..84659c6e16b
--- /dev/null
+++ b/lldb/source/Core/StreamAsynchronousIO.cpp
@@ -0,0 +1,52 @@
+//===-- StreamBroadcast.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdio.h>
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Broadcaster.h"
+#include "lldb/Core/Event.h"
+#include "lldb/Core/StreamAsynchronousIO.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+StreamAsynchronousIO::StreamAsynchronousIO (Broadcaster &broadcaster, uint32_t broadcast_event_type) :
+ Stream (0, 4, eByteOrderBig),
+ m_broadcaster (broadcaster),
+ m_broadcast_event_type (broadcast_event_type),
+ m_accumulated_data ()
+{
+}
+
+StreamAsynchronousIO::~StreamAsynchronousIO ()
+{
+}
+
+void
+StreamAsynchronousIO::Flush ()
+{
+ if (m_accumulated_data.GetSize() > 0)
+ {
+ std::auto_ptr<EventDataBytes> data_bytes_ap (new EventDataBytes);
+ // Let's swap the bytes to avoid LARGE string copies.
+ data_bytes_ap->SwapBytes (m_accumulated_data.GetString());
+ EventSP new_event_sp (new Event (m_broadcast_event_type, data_bytes_ap.release()));
+ m_broadcaster.BroadcastEvent (new_event_sp);
+ m_accumulated_data.Clear();
+ }
+}
+
+int
+StreamAsynchronousIO::Write (const void *s, size_t length)
+{
+ m_accumulated_data.Write (s, length);
+ return length;
+}
diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp
index a36d9c299e8..16e5f3b75af 100644
--- a/lldb/source/Interpreter/CommandInterpreter.cpp
+++ b/lldb/source/Interpreter/CommandInterpreter.cpp
@@ -1226,7 +1226,10 @@ CommandInterpreter::GetConfirmationInputReaderCallback
out_file.Flush ();
}
break;
-
+
+ case eInputReaderAsynchronousOutputWritten:
+ break;
+
case eInputReaderGotToken:
if (bytes_len == 0)
{
@@ -1642,6 +1645,12 @@ CommandInterpreter::HandleCommands (const StringList &commands,
}
}
+ if (result.GetImmediateOutputStream())
+ result.GetImmediateOutputStream()->Flush();
+
+ if (result.GetImmediateErrorStream())
+ result.GetImmediateErrorStream()->Flush();
+
// N.B. Can't depend on DidChangeProcessState, because the state coming into the command execution
// could be running (for instance in Breakpoint Commands.
// So we check the return value to see if it is has running in it.
diff --git a/lldb/source/Interpreter/ScriptInterpreterPython.cpp b/lldb/source/Interpreter/ScriptInterpreterPython.cpp
index 10b9792f009..47302be0ee4 100644
--- a/lldb/source/Interpreter/ScriptInterpreterPython.cpp
+++ b/lldb/source/Interpreter/ScriptInterpreterPython.cpp
@@ -639,6 +639,9 @@ ScriptInterpreterPython::InputReaderCallback
script_interpreter->EnterSession ();
break;
+ case eInputReaderAsynchronousOutputWritten:
+ break;
+
case eInputReaderInterrupt:
::write (script_interpreter->m_embedded_python_pty.GetMasterFileDescriptor(), "raise KeyboardInterrupt\n", 24);
break;
@@ -1047,6 +1050,9 @@ ScriptInterpreterPython::GenerateBreakpointOptionsCommandCallback
}
break;
+ case eInputReaderAsynchronousOutputWritten:
+ break;
+
case eInputReaderGotToken:
{
std::string temp_string (bytes, bytes_len);
diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp
index 8e96c716e74..7bdccdaf4d0 100644
--- a/lldb/source/Target/Process.cpp
+++ b/lldb/source/Target/Process.cpp
@@ -3183,6 +3183,9 @@ Process::ProcessInputReaderCallback (void *baton,
case eInputReaderReactivate:
break;
+ case eInputReaderAsynchronousOutputWritten:
+ break;
+
case eInputReaderGotToken:
{
Error error;
diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp
index 11804798490..a023bf5b764 100644
--- a/lldb/source/Target/Target.cpp
+++ b/lldb/source/Target/Target.cpp
@@ -20,6 +20,7 @@
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Event.h"
#include "lldb/Core/Log.h"
+#include "lldb/Core/StreamAsynchronousIO.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Core/Timer.h"
#include "lldb/Core/ValueObject.h"
@@ -1104,8 +1105,12 @@ Target::RunStopHooks ()
if (num_exe_ctx == 0)
return;
- result.SetImmediateOutputFile (m_debugger.GetOutputFile().GetStream());
- result.SetImmediateErrorFile (m_debugger.GetErrorFile().GetStream());
+ StreamSP output_stream (new StreamAsynchronousIO (m_debugger.GetCommandInterpreter(),
+ CommandInterpreter::eBroadcastBitAsynchronousOutputData));
+ StreamSP error_stream (new StreamAsynchronousIO (m_debugger.GetCommandInterpreter(),
+ CommandInterpreter::eBroadcastBitAsynchronousErrorData));
+ result.SetImmediateOutputStream (output_stream);
+ result.SetImmediateErrorStream (error_stream);
bool keep_going = true;
bool hooks_ran = false;
@@ -1176,6 +1181,9 @@ Target::RunStopHooks ()
}
if (hooks_ran)
result.AppendMessage ("\n** End Stop Hooks **\n");
+
+ result.GetImmediateOutputStream()->Flush();
+ result.GetImmediateErrorStream()->Flush();
}
//--------------------------------------------------------------
diff --git a/lldb/tools/driver/Driver.cpp b/lldb/tools/driver/Driver.cpp
index 83e42fe2e0c..5107708e8a2 100644
--- a/lldb/tools/driver/Driver.cpp
+++ b/lldb/tools/driver/Driver.cpp
@@ -658,7 +658,7 @@ Driver::GetProcessSTDOUT ()
size_t total_bytes = 0;
while ((len = m_debugger.GetSelectedTarget().GetProcess().GetSTDOUT (stdio_buffer, sizeof (stdio_buffer))) > 0)
{
- m_io_channel_ap->OutWrite (stdio_buffer, len);
+ m_io_channel_ap->OutWrite (stdio_buffer, len, ASYNC);
total_bytes += len;
}
return total_bytes;
@@ -673,7 +673,7 @@ Driver::GetProcessSTDERR ()
size_t total_bytes = 0;
while ((len = m_debugger.GetSelectedTarget().GetProcess().GetSTDERR (stdio_buffer, sizeof (stdio_buffer))) > 0)
{
- m_io_channel_ap->ErrWrite (stdio_buffer, len);
+ m_io_channel_ap->ErrWrite (stdio_buffer, len, ASYNC);
total_bytes += len;
}
return total_bytes;
@@ -755,24 +755,20 @@ Driver::HandleProcessEvent (const SBEvent &event)
{
// The process has stdout available, get it and write it out to the
// appropriate place.
- if (GetProcessSTDOUT ())
- m_io_channel_ap->RefreshPrompt();
+ GetProcessSTDOUT ();
}
else if (event_type & SBProcess::eBroadcastBitSTDERR)
{
// The process has stderr available, get it and write it out to the
// appropriate place.
- if (GetProcessSTDERR ())
- m_io_channel_ap->RefreshPrompt();
+ GetProcessSTDERR ();
}
else if (event_type & SBProcess::eBroadcastBitStateChanged)
{
// Drain all stout and stderr so we don't see any output come after
// we print our prompts
- if (GetProcessSTDOUT ()
- || GetProcessSTDERR ())
- m_io_channel_ap->RefreshPrompt();
-
+ GetProcessSTDOUT ();
+ GetProcessSTDERR ();
// Something changed in the process; get the event and report the process's current status and location to
// the user.
StateType event_state = SBProcess::GetStateFromEvent (event);
@@ -795,7 +791,7 @@ Driver::HandleProcessEvent (const SBEvent &event)
char message[1024];
int message_len = ::snprintf (message, sizeof(message), "Process %d %s\n", process.GetProcessID(),
m_debugger.StateAsCString (event_state));
- m_io_channel_ap->OutWrite(message, message_len);
+ m_io_channel_ap->OutWrite(message, message_len, ASYNC);
}
break;
@@ -807,9 +803,8 @@ Driver::HandleProcessEvent (const SBEvent &event)
{
SBCommandReturnObject result;
m_debugger.GetCommandInterpreter().HandleCommand("process status", result, false);
- m_io_channel_ap->ErrWrite (result.GetError(), result.GetErrorSize());
- m_io_channel_ap->OutWrite (result.GetOutput(), result.GetOutputSize());
- m_io_channel_ap->RefreshPrompt();
+ m_io_channel_ap->ErrWrite (result.GetError(), result.GetErrorSize(), ASYNC);
+ m_io_channel_ap->OutWrite (result.GetOutput(), result.GetOutputSize(), ASYNC);
}
break;
@@ -823,17 +818,15 @@ Driver::HandleProcessEvent (const SBEvent &event)
char message[1024];
int message_len = ::snprintf (message, sizeof(message), "Process %d stopped and was programmatically restarted.\n",
process.GetProcessID());
- m_io_channel_ap->OutWrite(message, message_len);
- m_io_channel_ap->RefreshPrompt ();
+ m_io_channel_ap->OutWrite(message, message_len, ASYNC);
}
else
{
SBCommandReturnObject result;
UpdateSelectedThread ();
m_debugger.GetCommandInterpreter().HandleCommand("process status", result, false);
- m_io_channel_ap->ErrWrite (result.GetError(), result.GetErrorSize());
- m_io_channel_ap->OutWrite (result.GetOutput(), result.GetOutputSize());
- m_io_channel_ap->RefreshPrompt ();
+ m_io_channel_ap->ErrWrite (result.GetError(), result.GetErrorSize(), ASYNC);
+ m_io_channel_ap->OutWrite (result.GetOutput(), result.GetOutputSize(), ASYNC);
}
break;
}
@@ -935,11 +928,16 @@ Driver::EditLineInputReaderCallback
case eInputReaderDeactivate:
break;
+
+ case eInputReaderAsynchronousOutputWritten:
+ if (driver->m_io_channel_ap.get() != NULL)
+ driver->m_io_channel_ap->RefreshPrompt();
+ break;
case eInputReaderInterrupt:
if (driver->m_io_channel_ap.get() != NULL)
{
- driver->m_io_channel_ap->OutWrite ("^C\n", 3);
+ driver->m_io_channel_ap->OutWrite ("^C\n", 3, NO_ASYNC);
driver->m_io_channel_ap->RefreshPrompt();
}
break;
@@ -947,7 +945,7 @@ Driver::EditLineInputReaderCallback
case eInputReaderEndOfFile:
if (driver->m_io_channel_ap.get() != NULL)
{
- driver->m_io_channel_ap->OutWrite ("^D\n", 3);
+ driver->m_io_channel_ap->OutWrite ("^D\n", 3, NO_ASYNC);
driver->m_io_channel_ap->RefreshPrompt ();
}
write (driver->m_editline_pty.GetMasterFileDescriptor(), "quit\n", 5);
@@ -996,6 +994,36 @@ Driver::MainLoop ()
}
}
+ lldb_utility::PseudoTerminal editline_output_pty;
+ FILE *editline_output_slave_fh = NULL;
+
+ if (editline_output_pty.OpenFirstAvailableMaster (O_RDWR|O_NOCTTY, error_str, sizeof (error_str)) == false)
+ {
+ ::fprintf (stderr, "error: failed to open output pseudo terminal : %s", error_str);
+ exit(1);
+ }
+ else
+ {
+ const char *output_slave_name = editline_output_pty.GetSlaveName (error_str, sizeof(error_str));
+ if (output_slave_name == NULL)
+ {
+ ::fprintf (stderr, "error: failed to get slave name for output pseudo terminal : %s", error_str);
+ exit(2);
+ }
+ else
+ {
+ editline_output_slave_fh = ::fopen (output_slave_name, "r+");
+ if (editline_output_slave_fh == NULL)
+ {
+ SBError error;
+ error.SetErrorToErrno();
+ ::fprintf (stderr, "error: failed to get open slave for output pseudo terminal : %s",
+ error.GetCString());
+ exit(3);
+ }
+ ::setbuf (editline_output_slave_fh, NULL);
+ }
+ }
// struct termios stdin_termios;
@@ -1038,7 +1066,19 @@ Driver::MainLoop ()
//
SBCommandInterpreter sb_interpreter = m_debugger.GetCommandInterpreter();
- m_io_channel_ap.reset (new IOChannel(m_editline_slave_fh, stdout, stderr, this));
+ m_io_channel_ap.reset (new IOChannel(m_editline_slave_fh, editline_output_slave_fh, stdout, stderr, this));
+
+ SBCommunication out_comm_2("driver.editline_output");
+ out_comm_2.SetCloseOnEOF (false);
+ out_comm_2.AdoptFileDesriptor (editline_output_pty.GetMasterFileDescriptor(), false);
+ out_comm_2.SetReadThreadBytesReceivedCallback (IOChannel::LibeditOutputBytesReceived, m_io_channel_ap.get());
+
+ if (out_comm_2.ReadThreadStart () == false)
+ {
+ ::fprintf (stderr, "error: failed to start libedit output read thread");
+ exit (5);
+ }
+
struct winsize window_size;
if (isatty (STDIN_FILENO)
diff --git a/lldb/tools/driver/Driver.h b/lldb/tools/driver/Driver.h
index ffeef8951c9..1c09e63a77c 100644
--- a/lldb/tools/driver/Driver.h
+++ b/lldb/tools/driver/Driver.h
@@ -23,6 +23,8 @@
#include "lldb/API/SBError.h"
#include "lldb/API/SBInputReader.h"
+#define ASYNC true
+#define NO_ASYNC false
class IOChannel;
diff --git a/lldb/tools/driver/IOChannel.cpp b/lldb/tools/driver/IOChannel.cpp
index 9bf2b8e583f..6c2c3d9cc98 100644
--- a/lldb/tools/driver/IOChannel.cpp
+++ b/lldb/tools/driver/IOChannel.cpp
@@ -29,10 +29,6 @@ typedef std::map<EditLine *, std::string> PromptMap;
const char *g_default_prompt = "(lldb) ";
PromptMap g_prompt_map;
-#define NSEC_PER_USEC 1000ull
-#define USEC_PER_SEC 1000000ull
-#define NSEC_PER_SEC 1000000000ull
-
static const char*
el_prompt(EditLine *el)
{
@@ -100,16 +96,16 @@ IOChannel::HandleCompletion (EditLine *e, int ch)
const char *comment = "\nAvailable completions:";
int num_elements = num_completions + 1;
- OutWrite(comment, strlen (comment));
+ OutWrite(comment, strlen (comment), NO_ASYNC);
if (num_completions < page_size)
{
for (int i = 1; i < num_elements; i++)
{
completion_str = completions.GetStringAtIndex(i);
- OutWrite("\n\t", 2);
- OutWrite(completion_str, strlen (completion_str));
+ OutWrite("\n\t", 2, NO_ASYNC);
+ OutWrite(completion_str, strlen (completion_str), NO_ASYNC);
}
- OutWrite ("\n", 1);
+ OutWrite ("\n", 1, NO_ASYNC);
}
else
{
@@ -124,17 +120,17 @@ IOChannel::HandleCompletion (EditLine *e, int ch)
for (; cur_pos < endpoint; cur_pos++)
{
completion_str = completions.GetStringAtIndex(cur_pos);
- OutWrite("\n\t", 2);
- OutWrite(completion_str, strlen (completion_str));
+ OutWrite("\n\t", 2, NO_ASYNC);
+ OutWrite(completion_str, strlen (completion_str), NO_ASYNC);
}
if (cur_pos >= num_elements)
{
- OutWrite("\n", 1);
+ OutWrite("\n", 1, NO_ASYNC);
break;
}
- OutWrite("\nMore (Y/n/a): ", strlen ("\nMore (Y/n/a): "));
+ OutWrite("\nMore (Y/n/a): ", strlen ("\nMore (Y/n/a): "), NO_ASYNC);
reply = 'n';
got_char = el_getc(m_edit_line, &reply);
if (got_char == -1 || reply == 'n')
@@ -154,8 +150,9 @@ IOChannel::HandleCompletion (EditLine *e, int ch)
IOChannel::IOChannel
(
- FILE *in,
- FILE *out,
+ FILE *editline_in,
+ FILE *editline_out,
+ FILE *out,
FILE *err,
Driver *driver
) :
@@ -169,10 +166,12 @@ IOChannel::IOChannel
m_err_file (err),
m_command_queue (),
m_completion_key ("\t"),
- m_edit_line (::el_init (SBHostOS::GetProgramFileSpec().GetFilename(), in, out, err)),
+ m_edit_line (::el_init (SBHostOS::GetProgramFileSpec().GetFilename(), editline_in, editline_out, editline_out)),
m_history (history_init()),
m_history_event(),
- m_getting_command (false)
+ m_getting_command (false),
+ m_expecting_prompt (false),
+ m_prompt_str ()
{
assert (m_edit_line);
::el_set (m_edit_line, EL_PROMPT, el_prompt);
@@ -252,6 +251,36 @@ IOChannel::HistorySaveLoad (bool save)
}
}
+void
+IOChannel::LibeditOutputBytesReceived (void *baton, const void *src, size_t src_len)
+{
+ // Make this a member variable.
+ // static std::string prompt_str;
+ IOChannel *io_channel = (IOChannel *) baton;
+ const char *bytes = (const char *) src;
+
+ if (io_channel->IsGettingCommand() && io_channel->m_expecting_prompt)
+ {
+ io_channel->m_prompt_str.append (bytes, src_len);
+ // Log this to make sure the prompt is really what you think it is.
+ if (io_channel->m_prompt_str.find (el_prompt(io_channel->m_edit_line)) == 0)
+ {
+ io_channel->m_expecting_prompt = false;
+ io_channel->OutWrite (io_channel->m_prompt_str.c_str(),
+ io_channel->m_prompt_str.size(), NO_ASYNC);
+ io_channel->m_prompt_str.clear();
+ }
+ else
+ assert (io_channel->m_prompt_str.find (el_prompt(io_channel->m_edit_line)) == std::string::npos);
+ }
+ else
+ {
+ if (io_channel->m_prompt_str.size() > 0)
+ io_channel->m_prompt_str.clear();
+ io_channel->OutWrite (bytes, src_len, NO_ASYNC);
+ }
+}
+
bool
IOChannel::LibeditGetInput (std::string &new_line)
{
@@ -262,12 +291,7 @@ IOChannel::LibeditGetInput (std::string &new_line)
// Set boolean indicating whether or not el_gets is trying to get input (i.e. whether or not to attempt
// to refresh the prompt after writing data).
SetGettingCommand (true);
-
- // Get the current time just before calling el_gets; this is used by OutWrite, ErrWrite, and RefreshPrompt
- // to make sure they have given el_gets enough time to write the prompt before they attempt to write
- // anything.
-
- ::gettimeofday (&m_enter_elgets_time, NULL);
+ m_expecting_prompt = true;
// Call el_gets to prompt the user and read the user's input.
const char *line = ::el_gets (m_edit_line, &line_len);
@@ -318,7 +342,9 @@ IOChannel::Run ()
listener.StartListeningForEvents (interpreter_broadcaster,
SBCommandInterpreter::eBroadcastBitResetPrompt |
SBCommandInterpreter::eBroadcastBitThreadShouldExit |
- SBCommandInterpreter::eBroadcastBitQuitCommandReceived);
+ SBCommandInterpreter::eBroadcastBitQuitCommandReceived |
+ SBCommandInterpreter::eBroadcastBitAsynchronousOutputData |
+ SBCommandInterpreter::eBroadcastBitAsynchronousErrorData);
listener.StartListeningForEvents (*this,
IOChannel::eBroadcastBitThreadShouldExit);
@@ -392,6 +418,18 @@ IOChannel::Run ()
case SBCommandInterpreter::eBroadcastBitQuitCommandReceived:
done = true;
break;
+ case SBCommandInterpreter::eBroadcastBitAsynchronousErrorData:
+ {
+ const char *data = SBEvent::GetCStringFromEvent (event);
+ ErrWrite (data, strlen(data), ASYNC);
+ }
+ break;
+ case SBCommandInterpreter::eBroadcastBitAsynchronousOutputData:
+ {
+ const char *data = SBEvent::GetCStringFromEvent (event);
+ OutWrite (data, strlen(data), ASYNC);
+ }
+ break;
}
}
else if (event.BroadcasterMatchesPtr (this))
@@ -448,60 +486,41 @@ IOChannel::RefreshPrompt ()
if (! IsGettingCommand())
return;
- // Compare the current time versus the last time el_gets was called. If less than 40 milliseconds
- // (40,0000 microseconds or 40,000,0000 nanoseconds) have elapsed, wait 40,0000 microseconds, to ensure el_gets had
- // time to finish writing the prompt before we start writing here.
-
- if (ElapsedNanoSecondsSinceEnteringElGets() < (40 * 1000 * 1000))
- usleep (40 * 1000);
-
- // Use the mutex to make sure OutWrite, ErrWrite and Refresh prompt do not interfere with
- // each other's output.
+ // If we haven't finished writing the prompt, there's no need to refresh it.
+ if (m_expecting_prompt)
+ return;
- IOLocker locker (m_output_mutex);
::el_set (m_edit_line, EL_REFRESH);
}
void
-IOChannel::OutWrite (const char *buffer, size_t len)
+IOChannel::OutWrite (const char *buffer, size_t len, bool asynchronous)
{
if (len == 0)
return;
- // Compare the current time versus the last time el_gets was called. If less than
- // 10000 microseconds (10000000 nanoseconds) have elapsed, wait 10000 microseconds, to ensure el_gets had time
- // to finish writing the prompt before we start writing here.
-
- if (ElapsedNanoSecondsSinceEnteringElGets() < 10000000)
- usleep (10000);
-
- {
- // Use the mutex to make sure OutWrite, ErrWrite and Refresh prompt do not interfere with
- // each other's output.
- IOLocker locker (m_output_mutex);
- ::fwrite (buffer, 1, len, m_out_file);
- }
+ // Use the mutex to make sure OutWrite and ErrWrite do not interfere with each other's output.
+ IOLocker locker (m_output_mutex);
+ if (asynchronous)
+ ::fwrite ("\n", 1, 1, m_out_file);
+ ::fwrite (buffer, 1, len, m_out_file);
+ if (asynchronous)
+ m_driver->GetDebugger().NotifyTopInputReader (eInputReaderAsynchronousOutputWritten);
}
void
-IOChannel::ErrWrite (const char *buffer, size_t len)
+IOChannel::ErrWrite (const char *buffer, size_t len, bool asynchronous)
{
if (len == 0)
return;
- // Compare the current time versus the last time el_gets was called. If less than
- // 10000 microseconds (10000000 nanoseconds) have elapsed, wait 10000 microseconds, to ensure el_gets had time
- // to finish writing the prompt before we start writing here.
-
- if (ElapsedNanoSecondsSinceEnteringElGets() < 10000000)
- usleep (10000);
-
- {
- // Use the mutex to make sure OutWrite, ErrWrite and Refresh prompt do not interfere with
- // each other's output.
- IOLocker locker (m_output_mutex);
- ::fwrite (buffer, 1, len, m_err_file);
- }
+ // Use the mutex to make sure OutWrite and ErrWrite do not interfere with each other's output.
+ IOLocker locker (m_output_mutex);
+ if (asynchronous)
+ ::fwrite ("\n", 1, 1, m_err_file);
+ ::fwrite (buffer, 1, len, m_err_file);
+ if (asynchronous)
+ m_driver->GetDebugger().NotifyTopInputReader (eInputReaderAsynchronousOutputWritten);
}
void
@@ -551,25 +570,6 @@ IOChannel::SetGettingCommand (bool new_value)
m_getting_command = new_value;
}
-uint64_t
-IOChannel::Nanoseconds (const struct timeval &time_val) const
-{
- uint64_t nanoseconds = time_val.tv_sec * NSEC_PER_SEC + time_val.tv_usec * NSEC_PER_USEC;
-
- return nanoseconds;
-}
-
-uint64_t
-IOChannel::ElapsedNanoSecondsSinceEnteringElGets ()
-{
- if (! IsGettingCommand())
- return 0;
-
- struct timeval current_time;
- ::gettimeofday (&current_time, NULL);
- return (Nanoseconds (current_time) - Nanoseconds (m_enter_elgets_time));
-}
-
IOLocker::IOLocker (pthread_mutex_t &mutex) :
m_mutex_ptr (&mutex)
{
diff --git a/lldb/tools/driver/IOChannel.h b/lldb/tools/driver/IOChannel.h
index 188e2a20975..886de1b5ba1 100644
--- a/lldb/tools/driver/IOChannel.h
+++ b/lldb/tools/driver/IOChannel.h
@@ -35,7 +35,8 @@ public:
eAllEventBits = 0xffffffff
};
- IOChannel (FILE *in,
+ IOChannel (FILE *editline_in,
+ FILE *editline_out,
FILE *out,
FILE *err,
Driver *driver = NULL);
@@ -56,13 +57,16 @@ public:
Run ();
void
- OutWrite (const char *buffer, size_t len);
+ OutWrite (const char *buffer, size_t len, bool asynchronous);
void
- ErrWrite (const char *buffer, size_t len);
+ ErrWrite (const char *buffer, size_t len, bool asynchronous);
bool
LibeditGetInput (std::string &);
+
+ static void
+ LibeditOutputBytesReceived (void *baton, const void *src,size_t src_len);
void
SetPrompt ();
@@ -99,12 +103,6 @@ protected:
void
SetGettingCommand (bool new_value);
- uint64_t
- Nanoseconds (const struct timeval &time_val) const;
-
- uint64_t
- ElapsedNanoSecondsSinceEnteringElGets ();
-
private:
pthread_mutex_t m_output_mutex;
@@ -122,6 +120,8 @@ private:
History *m_history;
HistEvent m_history_event;
bool m_getting_command;
+ bool m_expecting_prompt;
+ std::string m_prompt_str; // for accumlating the prompt as it gets written out by editline
void
HistorySaveLoad (bool save);
OpenPOWER on IntegriCloud