From: Jonas Devlieghere Date: Tue, 15 Mar 2022 16:13:57 +0000 (-0700) Subject: [lldb] Synchronize output through the IOHandler X-Git-Tag: upstream/15.0.7~13595 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=242c574dc03e4b90e992cc8d07436efc3954727f;p=platform%2Fupstream%2Fllvm.git [lldb] Synchronize output through the IOHandler Add synchronization to the IOHandler to prevent multiple threads from writing concurrently to the output or error stream. A scenario where this could happen is when a thread (the default event thread for example) is using the debugger's asynchronous stream. We would delegate this operation to the IOHandler which might be running on another thread. Until this patch there was nothing to synchronize the two at the IOHandler level. Differential revision: https://reviews.llvm.org/D121500 --- diff --git a/lldb/include/lldb/Core/IOHandler.h b/lldb/include/lldb/Core/IOHandler.h index d58ad68..0f558f1 100644 --- a/lldb/include/lldb/Core/IOHandler.h +++ b/lldb/include/lldb/Core/IOHandler.h @@ -165,11 +165,14 @@ public: 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; diff --git a/lldb/include/lldb/Host/Editline.h b/lldb/include/lldb/Host/Editline.h index 14b6778..987dd03 100644 --- a/lldb/include/lldb/Host/Editline.h +++ b/lldb/include/lldb/Host/Editline.h @@ -154,7 +154,7 @@ using namespace line_editor; class Editline { public: Editline(const char *editor_name, FILE *input_file, FILE *output_file, - FILE *error_file, bool color_prompts); + FILE *error_file, std::mutex &output_mutex, bool color_prompts); ~Editline(); @@ -402,7 +402,7 @@ private: std::string m_suggestion_ansi_suffix; std::size_t m_previous_autosuggestion_size = 0; - std::mutex m_output_mutex; + std::mutex &m_output_mutex; }; } diff --git a/lldb/include/lldb/Interpreter/CommandInterpreter.h b/lldb/include/lldb/Interpreter/CommandInterpreter.h index 938d36b..787dfdb 100644 --- a/lldb/include/lldb/Interpreter/CommandInterpreter.h +++ b/lldb/include/lldb/Interpreter/CommandInterpreter.h @@ -655,7 +655,8 @@ private: 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_stdout); bool EchoCommandNonInteractive(llvm::StringRef line, const Flags &io_handler_flags) const; diff --git a/lldb/source/Core/IOHandler.cpp b/lldb/source/Core/IOHandler.cpp index 8ed2cfb..0761e1f 100644 --- a/lldb/source/Core/IOHandler.cpp +++ b/lldb/source/Core/IOHandler.cpp @@ -123,6 +123,7 @@ void IOHandler::SetPopped(bool b) { m_popped.SetValue(b, eBroadcastOnChange); } 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(); @@ -266,9 +267,9 @@ IOHandlerEditline::IOHandlerEditline( m_input_sp && m_input_sp->GetIsRealTerminal(); if (use_editline) { - m_editline_up = std::make_unique(editline_name, GetInputFILE(), - GetOutputFILE(), GetErrorFILE(), - m_color_prompts); + m_editline_up = std::make_unique( + editline_name, GetInputFILE(), GetOutputFILE(), GetErrorFILE(), + GetOutputMutex(), m_color_prompts); m_editline_up->SetIsInputCompleteCallback( [this](Editline *editline, StringList &lines) { return this->IsInputCompleteCallback(editline, lines); @@ -619,6 +620,7 @@ void IOHandlerEditline::GotEOF() { 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 diff --git a/lldb/source/Host/common/Editline.cpp b/lldb/source/Host/common/Editline.cpp index 826db61..d632c9c 100644 --- a/lldb/source/Host/common/Editline.cpp +++ b/lldb/source/Host/common/Editline.cpp @@ -1376,10 +1376,12 @@ Editline *Editline::InstanceFor(EditLine *editline) { } Editline::Editline(const char *editline_name, FILE *input_file, - FILE *output_file, FILE *error_file, bool color_prompts) + FILE *output_file, FILE *error_file, + std::mutex &output_mutex, bool color_prompts) : m_editor_status(EditorStatus::Complete), m_color_prompts(color_prompts), m_input_file(input_file), m_output_file(output_file), - m_error_file(error_file), m_input_connection(fileno(input_file), false) { + m_error_file(error_file), m_input_connection(fileno(input_file), false), + m_output_mutex(output_mutex) { // Get a shared history instance m_editor_name = (editline_name == nullptr) ? "lldb-tmp" : editline_name; m_history_sp = EditlineHistory::GetHistory(m_editor_name); diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp index edf4f59..8406ddc 100644 --- a/lldb/source/Interpreter/CommandInterpreter.cpp +++ b/lldb/source/Interpreter/CommandInterpreter.cpp @@ -2975,8 +2975,12 @@ bool CommandInterpreter::WasInterrupted() const { 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 @@ void CommandInterpreter::PrintCommandOutput(Stream &stream, 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 @@ void CommandInterpreter::IOHandlerInputComplete(IOHandler &io_handler, // 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 @@ void CommandInterpreter::IOHandlerInputComplete(IOHandler &io_handler, 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); } } diff --git a/lldb/unittests/Editline/EditlineTest.cpp b/lldb/unittests/Editline/EditlineTest.cpp index 3a1aba4..4fa440f 100644 --- a/lldb/unittests/Editline/EditlineTest.cpp +++ b/lldb/unittests/Editline/EditlineTest.cpp @@ -84,6 +84,7 @@ private: bool IsInputComplete(lldb_private::Editline *editline, lldb_private::StringList &lines); + std::mutex output_mutex; std::unique_ptr _editline_sp; PseudoTerminal _pty; @@ -117,7 +118,7 @@ EditlineAdapter::EditlineAdapter() // Create an Editline instance. _editline_sp.reset(new lldb_private::Editline( "gtest editor", *_el_secondary_file, *_el_secondary_file, - *_el_secondary_file, false)); + *_el_secondary_file, output_mutex, false)); _editline_sp->SetPrompt("> "); // Hookup our input complete callback.