From 58279d1ee1b567e8ca793d6d1eb6e0f1d5e7279e Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Wed, 19 Feb 2025 20:32:00 -0800 Subject: [lldb] Synchronize the debuggers output & error streams This patch improves the synchronization of the debugger's output and error streams using two new abstractions: `LockableStreamFile` and `LockedStreamFile`. - `LockableStreamFile` is a wrapper around a `StreamFile` and a mutex. Client cannot use the `StreamFile` without calling `Lock`, which returns a `LockedStreamFile`. - `LockedStreamFile` is an RAII object that locks the stream for the duration of its existence. As long as you hold on to the returned object you are permitted to write to the stream. The destruction of the object automatically flush the output stream. --- lldb/source/Commands/CommandObjectCommands.cpp | 62 +++++++++++++++----------- 1 file changed, 36 insertions(+), 26 deletions(-) (limited to 'lldb/source/Commands/CommandObjectCommands.cpp') diff --git a/lldb/source/Commands/CommandObjectCommands.cpp b/lldb/source/Commands/CommandObjectCommands.cpp index f069b2f..dd841cb 100644 --- a/lldb/source/Commands/CommandObjectCommands.cpp +++ b/lldb/source/Commands/CommandObjectCommands.cpp @@ -11,6 +11,7 @@ #include "CommandObjectRegexCommand.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/IOHandler.h" +#include "lldb/Host/StreamFile.h" #include "lldb/Interpreter/CommandHistory.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandOptionArgumentTable.h" @@ -792,12 +793,15 @@ a number follows 'f':" protected: void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { - StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); - if (output_sp && interactive) { - output_sp->PutCString("Enter one or more sed substitution commands in " - "the form: 's///'.\nTerminate the " - "substitution list with an empty line.\n"); - output_sp->Flush(); + if (interactive) { + if (lldb::LockableStreamFileSP output_sp = + io_handler.GetOutputStreamFileSP()) { + LockedStreamFile locked_stream = output_sp->Lock(); + locked_stream.PutCString( + "Enter one or more sed substitution commands in " + "the form: 's///'.\nTerminate the " + "substitution list with an empty line.\n"); + } } } @@ -2377,16 +2381,18 @@ protected: }; void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { - StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); - if (output_sp && interactive) { - output_sp->PutCString(g_python_command_instructions); - output_sp->Flush(); + if (interactive) { + if (lldb::LockableStreamFileSP output_sp = + io_handler.GetOutputStreamFileSP()) { + LockedStreamFile locked_stream = output_sp->Lock(); + locked_stream.PutCString(g_python_command_instructions); + } } } void IOHandlerInputComplete(IOHandler &io_handler, std::string &data) override { - StreamFileSP error_sp = io_handler.GetErrorStreamFileSP(); + LockableStreamFileSP error_sp = io_handler.GetErrorStreamFileSP(); ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); if (interpreter) { @@ -2396,9 +2402,10 @@ protected: std::string funct_name_str; if (interpreter->GenerateScriptAliasFunction(lines, funct_name_str)) { if (funct_name_str.empty()) { - error_sp->Printf("error: unable to obtain a function name, didn't " - "add python command.\n"); - error_sp->Flush(); + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf( + "error: unable to obtain a function name, didn't " + "add python command.\n"); } else { // everything should be fine now, let's add this alias @@ -2409,33 +2416,36 @@ protected: Status error = m_interpreter.AddUserCommand( m_cmd_name, command_obj_sp, m_overwrite); if (error.Fail()) { - error_sp->Printf("error: unable to add selected command: '%s'", - error.AsCString()); - error_sp->Flush(); + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf( + "error: unable to add selected command: '%s'", + error.AsCString()); } } else { llvm::Error llvm_error = m_container->LoadUserSubcommand( m_cmd_name, command_obj_sp, m_overwrite); if (llvm_error) { - error_sp->Printf("error: unable to add selected command: '%s'", - llvm::toString(std::move(llvm_error)).c_str()); - error_sp->Flush(); + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf( + "error: unable to add selected command: '%s'", + llvm::toString(std::move(llvm_error)).c_str()); } } } } else { - error_sp->Printf( + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf( "error: unable to create function, didn't add python command\n"); - error_sp->Flush(); } } else { - error_sp->Printf("error: empty function, didn't add python command\n"); - error_sp->Flush(); + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf( + "error: empty function, didn't add python command\n"); } } else { - error_sp->Printf( + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf( "error: script interpreter missing, didn't add python command\n"); - error_sp->Flush(); } io_handler.SetIsDone(true); -- cgit v1.1