Index: lldb/include/lldb/Core/IOHandler.h =================================================================== --- lldb/include/lldb/Core/IOHandler.h +++ lldb/include/lldb/Core/IOHandler.h @@ -165,11 +165,14 @@ virtual void PrintAsync(const char *s, size_t len, bool is_stdout); + std::mutex &GetOutputMutex() { return m_output_mutex; } + protected: Debugger &m_debugger; lldb::FileSP m_input_sp; lldb::StreamFileSP m_output_sp; lldb::StreamFileSP m_error_sp; + std::mutex m_output_mutex; repro::DataRecorder *m_data_recorder; Predicate m_popped; Flags m_flags; Index: lldb/include/lldb/Interpreter/CommandInterpreter.h =================================================================== --- lldb/include/lldb/Interpreter/CommandInterpreter.h +++ lldb/include/lldb/Interpreter/CommandInterpreter.h @@ -655,7 +655,8 @@ const CommandObject::CommandMap &command_map); // An interruptible wrapper around the stream output - void PrintCommandOutput(Stream &stream, llvm::StringRef str); + void PrintCommandOutput(IOHandler &io_handler, llvm::StringRef str, + bool is_stdout0); bool EchoCommandNonInteractive(llvm::StringRef line, const Flags &io_handler_flags) const; Index: lldb/source/Core/IOHandler.cpp =================================================================== --- lldb/source/Core/IOHandler.cpp +++ lldb/source/Core/IOHandler.cpp @@ -123,6 +123,7 @@ void IOHandler::WaitForPop() { m_popped.WaitForValueEqualTo(true); } void IOHandler::PrintAsync(const char *s, size_t len, bool is_stdout) { + std::lock_guard guard(m_output_mutex); lldb::StreamFileSP stream = is_stdout ? m_output_sp : m_error_sp; stream->Write(s, len); stream->Flush(); @@ -619,6 +620,7 @@ void IOHandlerEditline::PrintAsync(const char *s, size_t len, bool is_stdout) { #if LLDB_ENABLE_LIBEDIT if (m_editline_up) { + std::lock_guard guard(m_output_mutex); lldb::StreamFileSP stream = is_stdout ? m_output_sp : m_error_sp; m_editline_up->PrintAsync(stream.get(), s, len); } else Index: lldb/source/Interpreter/CommandInterpreter.cpp =================================================================== --- lldb/source/Interpreter/CommandInterpreter.cpp +++ lldb/source/Interpreter/CommandInterpreter.cpp @@ -2975,8 +2975,12 @@ return was_interrupted; } -void CommandInterpreter::PrintCommandOutput(Stream &stream, - llvm::StringRef str) { +void CommandInterpreter::PrintCommandOutput(IOHandler &io_handler, + llvm::StringRef str, + bool is_stdout) { + + lldb::StreamFileSP stream = is_stdout ? io_handler.GetOutputStreamFileSP() + : io_handler.GetErrorStreamFileSP(); // Split the output into lines and poll for interrupt requests const char *data = str.data(); size_t size = str.size(); @@ -2989,15 +2993,19 @@ break; } } - chunk_size = stream.Write(data, chunk_size); + { + std::lock_guard guard(io_handler.GetOutputMutex()); + chunk_size = stream->Write(data, chunk_size); + } lldbassert(size >= chunk_size); data += chunk_size; size -= chunk_size; } - if (size > 0) { - stream.Printf("\n... Interrupted.\n"); - } - stream.Flush(); + + std::lock_guard guard(io_handler.GetOutputMutex()); + if (size > 0) + stream->Printf("\n... Interrupted.\n"); + stream->Flush(); } bool CommandInterpreter::EchoCommandNonInteractive( @@ -3033,9 +3041,11 @@ // When using a non-interactive file handle (like when sourcing commands // from a file) we need to echo the command out so we don't just see the // command output and no command... - if (EchoCommandNonInteractive(line, io_handler.GetFlags())) + if (EchoCommandNonInteractive(line, io_handler.GetFlags())) { + std::lock_guard guard(io_handler.GetOutputMutex()); io_handler.GetOutputStreamFileSP()->Printf( "%s%s\n", io_handler.GetPrompt(), line.c_str()); + } } StartHandlingCommand(); @@ -3057,13 +3067,13 @@ if (!result.GetImmediateOutputStream()) { llvm::StringRef output = result.GetOutputData(); - PrintCommandOutput(*io_handler.GetOutputStreamFileSP(), output); + PrintCommandOutput(io_handler, output, true); } // Now emit the command error text from the command we just executed if (!result.GetImmediateErrorStream()) { llvm::StringRef error = result.GetErrorData(); - PrintCommandOutput(*io_handler.GetErrorStreamFileSP(), error); + PrintCommandOutput(io_handler, error, false); } }