diff options
23 files changed, 472 insertions, 314 deletions
diff --git a/lldb/include/lldb/Core/Debugger.h b/lldb/include/lldb/Core/Debugger.h index 7f08f3d..9c8a962 100644 --- a/lldb/include/lldb/Core/Debugger.h +++ b/lldb/include/lldb/Core/Debugger.h @@ -131,13 +131,16 @@ public: void SetAsyncExecution(bool async); - File &GetInputFile() { return *m_input_file_sp; } - lldb::FileSP GetInputFileSP() { return m_input_file_sp; } + File &GetInputFile() { return *m_input_file_sp; } - lldb::FileSP GetOutputFileSP() { return m_output_stream_sp->GetFileSP(); } + lldb::FileSP GetOutputFileSP() { + return m_output_stream_sp->GetUnlockedFileSP(); + } - lldb::FileSP GetErrorFileSP() { return m_error_stream_sp->GetFileSP(); } + lldb::FileSP GetErrorFileSP() { + return m_error_stream_sp->GetUnlockedFileSP(); + } repro::DataRecorder *GetInputRecorder(); @@ -198,8 +201,8 @@ public: // If any of the streams are not set, set them to the in/out/err stream of // the top most input reader to ensure they at least have something void AdoptTopIOHandlerFilesIfInvalid(lldb::FileSP &in, - lldb::StreamFileSP &out, - lldb::StreamFileSP &err); + lldb::LockableStreamFileSP &out, + lldb::LockableStreamFileSP &err); /// Run the given IO handler and return immediately. void RunIOHandlerAsync(const lldb::IOHandlerSP &reader_sp, @@ -649,8 +652,8 @@ protected: /// should not be used directly. Use GetAsyncOutputStream and /// GetAsyncErrorStream instead. /// @{ - lldb::StreamFileSP GetOutputStreamSP() { return m_output_stream_sp; } - lldb::StreamFileSP GetErrorStreamSP() { return m_error_stream_sp; } + lldb::LockableStreamFileSP GetOutputStreamSP() { return m_output_stream_sp; } + lldb::LockableStreamFileSP GetErrorStreamSP() { return m_error_stream_sp; } /// @} void PushIOHandler(const lldb::IOHandlerSP &reader_sp, @@ -693,8 +696,9 @@ protected: // these should never be NULL lldb::FileSP m_input_file_sp; - lldb::StreamFileSP m_output_stream_sp; - lldb::StreamFileSP m_error_stream_sp; + lldb::LockableStreamFileSP m_output_stream_sp; + lldb::LockableStreamFileSP m_error_stream_sp; + LockableStreamFile::Mutex m_output_mutex; /// Used for shadowing the input file when capturing a reproducer. repro::DataRecorder *m_input_recorder; diff --git a/lldb/include/lldb/Core/IOHandler.h b/lldb/include/lldb/Core/IOHandler.h index d6ac1cc..fc0c676 100644 --- a/lldb/include/lldb/Core/IOHandler.h +++ b/lldb/include/lldb/Core/IOHandler.h @@ -53,8 +53,9 @@ public: IOHandler(Debugger &debugger, IOHandler::Type type); IOHandler(Debugger &debugger, IOHandler::Type type, - const lldb::FileSP &input_sp, const lldb::StreamFileSP &output_sp, - const lldb::StreamFileSP &error_sp, uint32_t flags); + const lldb::FileSP &input_sp, + const lldb::LockableStreamFileSP &output_sp, + const lldb::LockableStreamFileSP &error_sp, uint32_t flags); virtual ~IOHandler(); @@ -112,17 +113,11 @@ public: int GetErrorFD(); - FILE *GetInputFILE(); - - FILE *GetOutputFILE(); - - FILE *GetErrorFILE(); - lldb::FileSP GetInputFileSP(); - lldb::StreamFileSP GetOutputStreamFileSP(); + lldb::LockableStreamFileSP GetOutputStreamFileSP(); - lldb::StreamFileSP GetErrorStreamFileSP(); + lldb::LockableStreamFileSP GetErrorStreamFileSP(); Debugger &GetDebugger() { return m_debugger; } @@ -155,14 +150,11 @@ public: virtual void PrintAsync(const char *s, size_t len, bool is_stdout); - std::recursive_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::recursive_mutex m_output_mutex; + lldb::LockableStreamFileSP m_output_sp; + lldb::LockableStreamFileSP m_error_sp; Predicate<bool> m_popped; Flags m_flags; Type m_type; @@ -330,8 +322,8 @@ public: IOHandlerEditline(Debugger &debugger, IOHandler::Type type, const lldb::FileSP &input_sp, - const lldb::StreamFileSP &output_sp, - const lldb::StreamFileSP &error_sp, uint32_t flags, + const lldb::LockableStreamFileSP &output_sp, + const lldb::LockableStreamFileSP &error_sp, uint32_t flags, const char *editline_name, // Used for saving history files llvm::StringRef prompt, llvm::StringRef continuation_prompt, bool multi_line, bool color, @@ -345,9 +337,10 @@ public: IOHandlerDelegate &) = delete; IOHandlerEditline(Debugger &, IOHandler::Type, const lldb::FileSP &, - const lldb::StreamFileSP &, const lldb::StreamFileSP &, - uint32_t, const char *, const char *, const char *, bool, - bool, uint32_t, IOHandlerDelegate &) = delete; + const lldb::LockableStreamFileSP &, + const lldb::LockableStreamFileSP &, uint32_t, const char *, + const char *, const char *, bool, bool, uint32_t, + IOHandlerDelegate &) = delete; ~IOHandlerEditline() override; diff --git a/lldb/include/lldb/Host/Editline.h b/lldb/include/lldb/Host/Editline.h index 27b8638..8964d37 100644 --- a/lldb/include/lldb/Host/Editline.h +++ b/lldb/include/lldb/Host/Editline.h @@ -34,6 +34,7 @@ #include <sstream> #include <vector> +#include "lldb/Host/StreamFile.h" #include "lldb/lldb-private.h" #if !defined(_WIN32) && !defined(__ANDROID__) @@ -151,8 +152,9 @@ using namespace line_editor; /// facility. Both single- and multi-line editing are supported. class Editline { public: - Editline(const char *editor_name, FILE *input_file, FILE *output_file, - FILE *error_file, bool color, std::recursive_mutex &output_mutex); + Editline(const char *editor_name, FILE *input_file, + lldb::LockableStreamFileSP output_stream_sp, + lldb::LockableStreamFileSP error_stream_sp, bool color); ~Editline(); @@ -237,7 +239,8 @@ public: /// Prompts for and reads a multi-line batch of user input. bool GetLines(int first_line_number, StringList &lines, bool &interrupted); - void PrintAsync(Stream *stream, const char *s, size_t len); + void PrintAsync(lldb::LockableStreamFileSP stream_sp, const char *s, + size_t len); /// Convert the current input lines into a UTF8 StringList StringList GetInputAsStringList(int line_count = UINT32_MAX); @@ -392,8 +395,11 @@ private: volatile std::sig_atomic_t m_terminal_size_has_changed = 0; std::string m_editor_name; FILE *m_input_file; - FILE *m_output_file; - FILE *m_error_file; + lldb::LockableStreamFileSP m_output_stream_sp; + lldb::LockableStreamFileSP m_error_stream_sp; + + std::optional<LockedStreamFile> m_locked_output; + ConnectionFileDescriptor m_input_connection; IsInputCompleteCallbackType m_is_input_complete_callback; @@ -411,7 +417,6 @@ private: std::string m_suggestion_ansi_suffix; std::size_t m_previous_autosuggestion_size = 0; - std::recursive_mutex &m_output_mutex; }; } diff --git a/lldb/include/lldb/Host/File.h b/lldb/include/lldb/Host/File.h index 5ce53c9..9e2d0ab 100644 --- a/lldb/include/lldb/Host/File.h +++ b/lldb/include/lldb/Host/File.h @@ -377,6 +377,11 @@ private: class NativeFile : public File { public: + enum TransferOwnership : bool { + Owned = true, + Unowned = false, + }; + NativeFile() : m_descriptor(kInvalidDescriptor), m_stream(kInvalidStream) {} NativeFile(FILE *fh, bool transfer_ownership) diff --git a/lldb/include/lldb/Host/StreamFile.h b/lldb/include/lldb/Host/StreamFile.h index 2c96e13..e37661a 100644 --- a/lldb/include/lldb/Host/StreamFile.h +++ b/lldb/include/lldb/Host/StreamFile.h @@ -13,9 +13,12 @@ #include "lldb/Utility/Stream.h" #include "lldb/lldb-defines.h" #include "lldb/lldb-enumerations.h" +#include "lldb/lldb-forward.h" #include <cstdint> #include <cstdio> +#include <memory> +#include <mutex> namespace lldb_private { @@ -52,6 +55,55 @@ private: const StreamFile &operator=(const StreamFile &) = delete; }; +class LockableStreamFile; +class LockedStreamFile : public StreamFile { +public: + ~LockedStreamFile() { Flush(); } + + LockedStreamFile(LockedStreamFile &&other) + : StreamFile(other.m_file_sp), m_lock(std::move(other.m_lock)) {} + +private: + LockedStreamFile(std::shared_ptr<File> file, std::recursive_mutex &mutex) + : StreamFile(file), m_lock(mutex) {} + + friend class LockableStreamFile; + + std::unique_lock<std::recursive_mutex> m_lock; +}; + +class LockableStreamFile { +public: + using Mutex = std::recursive_mutex; + + LockableStreamFile(std::shared_ptr<StreamFile> stream_file_sp, Mutex &mutex) + : m_file_sp(stream_file_sp->GetFileSP()), m_mutex(mutex) {} + LockableStreamFile(StreamFile &stream_file, Mutex &mutex) + : m_file_sp(stream_file.GetFileSP()), m_mutex(mutex) {} + LockableStreamFile(FILE *fh, bool transfer_ownership, Mutex &mutex) + : m_file_sp(std::make_shared<NativeFile>(fh, transfer_ownership)), + m_mutex(mutex) {} + LockableStreamFile(std::shared_ptr<File> file_sp, Mutex &mutex) + : m_file_sp(file_sp), m_mutex(mutex) {} + + LockedStreamFile Lock() { return LockedStreamFile(m_file_sp, m_mutex); } + + /// Unsafe accessors to get the underlying File without a lock. Exists for + /// legacy reasons. + /// @{ + File &GetUnlockedFile() { return *m_file_sp; } + std::shared_ptr<File> GetUnlockedFileSP() { return m_file_sp; } + /// @} + +protected: + std::shared_ptr<File> m_file_sp; + Mutex &m_mutex; + +private: + LockableStreamFile(const LockableStreamFile &) = delete; + const LockableStreamFile &operator=(const LockableStreamFile &) = delete; +}; + } // namespace lldb_private #endif // LLDB_HOST_STREAMFILE_H diff --git a/lldb/include/lldb/Interpreter/ScriptInterpreter.h b/lldb/include/lldb/Interpreter/ScriptInterpreter.h index 2c2bd6f..c5aa199 100644 --- a/lldb/include/lldb/Interpreter/ScriptInterpreter.h +++ b/lldb/include/lldb/Interpreter/ScriptInterpreter.h @@ -116,8 +116,12 @@ public: ~ScriptInterpreterIORedirect(); lldb::FileSP GetInputFile() const { return m_input_file_sp; } - lldb::FileSP GetOutputFile() const { return m_output_file_sp->GetFileSP(); } - lldb::FileSP GetErrorFile() const { return m_error_file_sp->GetFileSP(); } + lldb::FileSP GetOutputFile() const { + return m_output_file_sp->GetUnlockedFileSP(); + } + lldb::FileSP GetErrorFile() const { + return m_error_file_sp->GetUnlockedFileSP(); + } /// Flush our output and error file handles. void Flush(); @@ -128,8 +132,9 @@ private: ScriptInterpreterIORedirect(Debugger &debugger, CommandReturnObject *result); lldb::FileSP m_input_file_sp; - lldb::StreamFileSP m_output_file_sp; - lldb::StreamFileSP m_error_file_sp; + lldb::LockableStreamFileSP m_output_file_sp; + lldb::LockableStreamFileSP m_error_file_sp; + LockableStreamFile::Mutex m_output_mutex; ThreadedCommunication m_communication; bool m_disconnect; }; @@ -478,7 +483,7 @@ public: dest.clear(); return false; } - + virtual StructuredData::ObjectSP GetOptionsForCommandObject(StructuredData::GenericSP cmd_obj_sp) { return {}; @@ -488,9 +493,9 @@ public: GetArgumentsForCommandObject(StructuredData::GenericSP cmd_obj_sp) { return {}; } - + virtual bool SetOptionValueForCommandObject( - StructuredData::GenericSP cmd_obj_sp, ExecutionContext *exe_ctx, + StructuredData::GenericSP cmd_obj_sp, ExecutionContext *exe_ctx, llvm::StringRef long_option, llvm::StringRef value) { return false; } diff --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h index fc7456a..cda55ef 100644 --- a/lldb/include/lldb/lldb-forward.h +++ b/lldb/include/lldb/lldb-forward.h @@ -215,6 +215,7 @@ class StoppointCallbackContext; class Stream; class StreamFile; class StreamString; +class LockableStreamFile; class StringList; class StringTableReader; class StructuredDataImpl; @@ -432,6 +433,7 @@ typedef std::unique_ptr<lldb_private::StackFrameRecognizerManager> typedef std::shared_ptr<lldb_private::StopInfo> StopInfoSP; typedef std::shared_ptr<lldb_private::Stream> StreamSP; typedef std::shared_ptr<lldb_private::StreamFile> StreamFileSP; +typedef std::shared_ptr<lldb_private::LockableStreamFile> LockableStreamFileSP; typedef std::shared_ptr<lldb_private::StringSummaryFormat> StringTypeSummaryImplSP; typedef std::unique_ptr<lldb_private::StructuredDataImpl> StructuredDataImplUP; diff --git a/lldb/source/Commands/CommandObjectBreakpointCommand.cpp b/lldb/source/Commands/CommandObjectBreakpointCommand.cpp index ac2db59..a913ed5 100644 --- a/lldb/source/Commands/CommandObjectBreakpointCommand.cpp +++ b/lldb/source/Commands/CommandObjectBreakpointCommand.cpp @@ -193,10 +193,12 @@ are no syntax errors may indicate that a function was declared but never called. Options *GetOptions() override { return &m_all_options; } void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { - StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); - if (output_sp && interactive) { - output_sp->PutCString(g_reader_instructions); - output_sp->Flush(); + if (interactive) { + if (lldb::LockableStreamFileSP output_sp = + io_handler.GetOutputStreamFileSP()) { + LockedStreamFile locked_stream = output_sp->Lock(); + locked_stream.PutCString(g_reader_instructions); + } } } 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/<regex>/<subst>/'.\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/<regex>/<subst>/'.\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); diff --git a/lldb/source/Commands/CommandObjectExpression.cpp b/lldb/source/Commands/CommandObjectExpression.cpp index 18526c4..a95dea6 100644 --- a/lldb/source/Commands/CommandObjectExpression.cpp +++ b/lldb/source/Commands/CommandObjectExpression.cpp @@ -12,6 +12,7 @@ #include "lldb/Expression/REPL.h" #include "lldb/Expression/UserExpression.h" #include "lldb/Host/OptionParser.h" +#include "lldb/Host/StreamFile.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandOptionArgumentTable.h" #include "lldb/Interpreter/CommandReturnObject.h" @@ -22,6 +23,7 @@ #include "lldb/Target/Target.h" #include "lldb/Utility/DiagnosticsRendering.h" #include "lldb/lldb-enumerations.h" +#include "lldb/lldb-forward.h" #include "lldb/lldb-private-enumerations.h" using namespace lldb; @@ -544,11 +546,10 @@ void CommandObjectExpression::GetMultilineExpression() { 1, // Show line numbers starting at 1 *this)); - StreamFileSP output_sp = io_handler_sp->GetOutputStreamFileSP(); - if (output_sp) { - output_sp->PutCString( + if (LockableStreamFileSP output_sp = io_handler_sp->GetOutputStreamFileSP()) { + LockedStreamFile locked_stream = output_sp->Lock(); + locked_stream.PutCString( "Enter expressions, then terminate with an empty line to evaluate:\n"); - output_sp->Flush(); } debugger.RunIOHandlerAsync(io_handler_sp); } diff --git a/lldb/source/Commands/CommandObjectTarget.cpp b/lldb/source/Commands/CommandObjectTarget.cpp index 71ddc8d..bd9470b 100644 --- a/lldb/source/Commands/CommandObjectTarget.cpp +++ b/lldb/source/Commands/CommandObjectTarget.cpp @@ -57,6 +57,7 @@ #include "lldb/Utility/Timer.h" #include "lldb/ValueObject/ValueObjectVariable.h" #include "lldb/lldb-enumerations.h" +#include "lldb/lldb-forward.h" #include "lldb/lldb-private-enumerations.h" #include "clang/Frontend/CompilerInstance.h" @@ -4923,11 +4924,13 @@ Filter Options: protected: void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { - StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); - if (output_sp && interactive) { - output_sp->PutCString( - "Enter your stop hook command(s). Type 'DONE' to end.\n"); - output_sp->Flush(); + if (interactive) { + if (lldb::LockableStreamFileSP output_sp = + io_handler.GetOutputStreamFileSP()) { + LockedStreamFile locked_stream = output_sp->Lock(); + locked_stream.PutCString( + "Enter your stop hook command(s). Type 'DONE' to end.\n"); + } } } @@ -4935,12 +4938,12 @@ protected: std::string &line) override { if (m_stop_hook_sp) { if (line.empty()) { - StreamFileSP error_sp(io_handler.GetErrorStreamFileSP()); - if (error_sp) { - error_sp->Printf("error: stop hook #%" PRIu64 - " aborted, no commands.\n", - m_stop_hook_sp->GetID()); - error_sp->Flush(); + if (lldb::LockableStreamFileSP error_sp = + io_handler.GetErrorStreamFileSP()) { + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf("error: stop hook #%" PRIu64 + " aborted, no commands.\n", + m_stop_hook_sp->GetID()); } GetTarget().UndoCreateStopHook(m_stop_hook_sp->GetID()); } else { @@ -4949,11 +4952,11 @@ protected: static_cast<Target::StopHookCommandLine *>(m_stop_hook_sp.get()); hook_ptr->SetActionFromString(line); - StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); - if (output_sp) { - output_sp->Printf("Stop hook #%" PRIu64 " added.\n", - m_stop_hook_sp->GetID()); - output_sp->Flush(); + if (lldb::LockableStreamFileSP output_sp = + io_handler.GetOutputStreamFileSP()) { + LockedStreamFile locked_stream = output_sp->Lock(); + locked_stream.Printf("Stop hook #%" PRIu64 " added.\n", + m_stop_hook_sp->GetID()); } } m_stop_hook_sp.reset(); diff --git a/lldb/source/Commands/CommandObjectType.cpp b/lldb/source/Commands/CommandObjectType.cpp index e4c6e37..41630b6 100644 --- a/lldb/source/Commands/CommandObjectType.cpp +++ b/lldb/source/Commands/CommandObjectType.cpp @@ -14,6 +14,7 @@ #include "lldb/DataFormatters/FormatClasses.h" #include "lldb/Host/Config.h" #include "lldb/Host/OptionParser.h" +#include "lldb/Host/StreamFile.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandObject.h" #include "lldb/Interpreter/CommandOptionArgumentTable.h" @@ -32,6 +33,7 @@ #include "lldb/Utility/ConstString.h" #include "lldb/Utility/RegularExpression.h" #include "lldb/Utility/StringList.h" +#include "lldb/lldb-forward.h" #include "llvm/ADT/STLExtras.h" @@ -167,16 +169,17 @@ public: "for\n" " internal_dict: an LLDB support object not to be used\"\"\"\n"; - StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); - if (output_sp && interactive) { - output_sp->PutCString(g_summary_addreader_instructions); - output_sp->Flush(); + if (interactive) { + if (LockableStreamFileSP output_sp = io_handler.GetOutputStreamFileSP()) { + LockedStreamFile locked_stream = output_sp->Lock(); + locked_stream.PutCString(g_summary_addreader_instructions); + } } } void IOHandlerInputComplete(IOHandler &io_handler, std::string &data) override { - StreamFileSP error_sp = io_handler.GetErrorStreamFileSP(); + LockableStreamFileSP error_sp = io_handler.GetErrorStreamFileSP(); #if LLDB_ENABLE_PYTHON ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); @@ -197,9 +200,10 @@ public: if (interpreter->GenerateTypeScriptFunction(lines, funct_name_str)) { if (funct_name_str.empty()) { - error_sp->Printf("unable to obtain a valid function name from " - "the script interpreter.\n"); - error_sp->Flush(); + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf( + "unable to obtain a valid function name from " + "the script interpreter.\n"); } else { // now I have a valid function name, let's add this as script // for every type in the list @@ -216,8 +220,8 @@ public: options->m_match_type, options->m_category, &error); if (error.Fail()) { - error_sp->Printf("error: %s", error.AsCString()); - error_sp->Flush(); + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf("error: %s", error.AsCString()); } } @@ -228,41 +232,42 @@ public: CommandObjectTypeSummaryAdd::AddNamedSummary( options->m_name, script_format, &error); if (error.Fail()) { - error_sp->Printf("error: %s", error.AsCString()); - error_sp->Flush(); + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf("error: %s", error.AsCString()); } } else { - error_sp->Printf("error: %s", error.AsCString()); - error_sp->Flush(); + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf("error: %s", error.AsCString()); } } else { if (error.AsCString()) { - error_sp->Printf("error: %s", error.AsCString()); - error_sp->Flush(); + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf("error: %s", error.AsCString()); } } } } else { - error_sp->Printf("error: unable to generate a function.\n"); - error_sp->Flush(); + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf("error: unable to generate a function.\n"); } } else { - error_sp->Printf("error: no script interpreter.\n"); - error_sp->Flush(); + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf("error: no script interpreter.\n"); } } else { - error_sp->Printf("error: internal synchronization information " - "missing or invalid.\n"); - error_sp->Flush(); + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf("error: internal synchronization information " + "missing or invalid.\n"); } } 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(); } #endif io_handler.SetIsDone(true); @@ -404,16 +409,17 @@ protected: } void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { - StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); - if (output_sp && interactive) { - output_sp->PutCString(g_synth_addreader_instructions); - output_sp->Flush(); + if (interactive) { + if (LockableStreamFileSP output_sp = io_handler.GetOutputStreamFileSP()) { + LockedStreamFile locked_stream = output_sp->Lock(); + locked_stream.PutCString(g_synth_addreader_instructions); + } } } void IOHandlerInputComplete(IOHandler &io_handler, std::string &data) override { - StreamFileSP error_sp = io_handler.GetErrorStreamFileSP(); + LockableStreamFileSP error_sp = io_handler.GetErrorStreamFileSP(); #if LLDB_ENABLE_PYTHON ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); @@ -433,9 +439,10 @@ protected: std::string class_name_str; if (interpreter->GenerateTypeSynthClass(lines, class_name_str)) { if (class_name_str.empty()) { - error_sp->Printf( + + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf( "error: unable to obtain a proper name for the class.\n"); - error_sp->Flush(); } else { // everything should be fine now, let's add the synth provider // class @@ -459,37 +466,39 @@ protected: if (AddSynth(ConstString(type_name), synth_provider, options->m_match_type, options->m_category, &error)) { - error_sp->Printf("error: %s\n", error.AsCString()); - error_sp->Flush(); + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf("error: %s\n", error.AsCString()); break; } } else { - error_sp->Printf("error: invalid type name.\n"); - error_sp->Flush(); + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf("error: invalid type name.\n"); break; } } } } else { - error_sp->Printf("error: unable to generate a class.\n"); - error_sp->Flush(); + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf("error: unable to generate a class.\n"); } } else { - error_sp->Printf("error: no script interpreter.\n"); - error_sp->Flush(); + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf("error: no script interpreter.\n"); } } else { - error_sp->Printf("error: internal synchronization data missing.\n"); - error_sp->Flush(); + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf( + "error: internal synchronization data missing.\n"); } } 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(); } #endif @@ -952,8 +961,8 @@ protected: class CommandObjectTypeFormatDelete : public CommandObjectTypeFormatterDelete { public: CommandObjectTypeFormatDelete(CommandInterpreter &interpreter) - : CommandObjectTypeFormatterDelete( - interpreter, eFormatCategoryItemFormat) {} + : CommandObjectTypeFormatterDelete(interpreter, + eFormatCategoryItemFormat) {} ~CommandObjectTypeFormatDelete() override = default; }; @@ -1603,8 +1612,8 @@ bool CommandObjectTypeSummaryAdd::AddSummary(ConstString type_name, class CommandObjectTypeSummaryDelete : public CommandObjectTypeFormatterDelete { public: CommandObjectTypeSummaryDelete(CommandInterpreter &interpreter) - : CommandObjectTypeFormatterDelete( - interpreter, eFormatCategoryItemSummary) {} + : CommandObjectTypeFormatterDelete(interpreter, + eFormatCategoryItemSummary) {} ~CommandObjectTypeSummaryDelete() override = default; @@ -2070,8 +2079,8 @@ public: class CommandObjectTypeFilterDelete : public CommandObjectTypeFormatterDelete { public: CommandObjectTypeFilterDelete(CommandInterpreter &interpreter) - : CommandObjectTypeFormatterDelete( - interpreter, eFormatCategoryItemFilter) {} + : CommandObjectTypeFormatterDelete(interpreter, + eFormatCategoryItemFilter) {} ~CommandObjectTypeFilterDelete() override = default; }; @@ -2081,13 +2090,12 @@ public: class CommandObjectTypeSynthDelete : public CommandObjectTypeFormatterDelete { public: CommandObjectTypeSynthDelete(CommandInterpreter &interpreter) - : CommandObjectTypeFormatterDelete( - interpreter, eFormatCategoryItemSynth) {} + : CommandObjectTypeFormatterDelete(interpreter, + eFormatCategoryItemSynth) {} ~CommandObjectTypeSynthDelete() override = default; }; - // CommandObjectTypeFilterClear class CommandObjectTypeFilterClear : public CommandObjectTypeFormatterClear { diff --git a/lldb/source/Commands/CommandObjectWatchpointCommand.cpp b/lldb/source/Commands/CommandObjectWatchpointCommand.cpp index ab1a2b3..507ef3f 100644 --- a/lldb/source/Commands/CommandObjectWatchpointCommand.cpp +++ b/lldb/source/Commands/CommandObjectWatchpointCommand.cpp @@ -14,11 +14,13 @@ #include "lldb/Breakpoint/Watchpoint.h" #include "lldb/Core/IOHandler.h" #include "lldb/Host/OptionParser.h" +#include "lldb/Host/StreamFile.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandOptionArgumentTable.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Interpreter/OptionArgParser.h" #include "lldb/Target/Target.h" +#include "lldb/lldb-forward.h" using namespace lldb; using namespace lldb_private; @@ -170,11 +172,13 @@ are no syntax errors may indicate that a function was declared but never called. Options *GetOptions() override { return &m_options; } void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { - StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); - if (output_sp && interactive) { - output_sp->PutCString( - "Enter your debugger command(s). Type 'DONE' to end.\n"); - output_sp->Flush(); + if (interactive) { + if (lldb::LockableStreamFileSP output_sp = + io_handler.GetOutputStreamFileSP()) { + LockedStreamFile locked_stream = output_sp->Lock(); + locked_stream.PutCString( + "Enter your debugger command(s). Type 'DONE' to end.\n"); + } } } diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index 8b7814d..242ef1c 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -873,9 +873,11 @@ llvm::StringRef Debugger::GetStaticBroadcasterClass() { Debugger::Debugger(lldb::LogOutputCallback log_callback, void *baton) : UserID(g_unique_id++), Properties(std::make_shared<OptionValueProperties>()), - m_input_file_sp(std::make_shared<NativeFile>(stdin, false)), - m_output_stream_sp(std::make_shared<StreamFile>(stdout, false)), - m_error_stream_sp(std::make_shared<StreamFile>(stderr, false)), + m_input_file_sp(std::make_shared<NativeFile>(stdin, NativeFile::Unowned)), + m_output_stream_sp(std::make_shared<LockableStreamFile>( + stdout, NativeFile::Unowned, m_output_mutex)), + m_error_stream_sp(std::make_shared<LockableStreamFile>( + stderr, NativeFile::Unowned, m_output_mutex)), m_input_recorder(nullptr), m_broadcaster_manager_sp(BroadcasterManager::MakeBroadcasterManager()), m_terminal_state(), m_target_list(*this), m_platform_list(), @@ -1083,12 +1085,14 @@ void Debugger::SetInputFile(FileSP file_sp) { void Debugger::SetOutputFile(FileSP file_sp) { assert(file_sp && file_sp->IsValid()); - m_output_stream_sp = std::make_shared<StreamFile>(file_sp); + m_output_stream_sp = + std::make_shared<LockableStreamFile>(file_sp, m_output_mutex); } void Debugger::SetErrorFile(FileSP file_sp) { assert(file_sp && file_sp->IsValid()); - m_error_stream_sp = std::make_shared<StreamFile>(file_sp); + m_error_stream_sp = + std::make_shared<LockableStreamFile>(file_sp, m_output_mutex); } void Debugger::SaveInputTerminalState() { @@ -1198,9 +1202,10 @@ bool Debugger::CheckTopIOHandlerTypes(IOHandler::Type top_type, void Debugger::PrintAsync(const char *s, size_t len, bool is_stdout) { bool printed = m_io_handler_stack.PrintAsync(s, len, is_stdout); if (!printed) { - lldb::StreamFileSP stream = + LockableStreamFileSP stream_sp = is_stdout ? m_output_stream_sp : m_error_stream_sp; - stream->Write(s, len); + LockedStreamFile locked_stream = stream_sp->Lock(); + locked_stream.Write(s, len); } } @@ -1225,8 +1230,9 @@ void Debugger::RunIOHandlerAsync(const IOHandlerSP &reader_sp, PushIOHandler(reader_sp, cancel_top_handler); } -void Debugger::AdoptTopIOHandlerFilesIfInvalid(FileSP &in, StreamFileSP &out, - StreamFileSP &err) { +void Debugger::AdoptTopIOHandlerFilesIfInvalid(FileSP &in, + LockableStreamFileSP &out, + LockableStreamFileSP &err) { // Before an IOHandler runs, it must have in/out/err streams. This function // is called when one ore more of the streams are nullptr. We use the top // input reader's in/out/err streams, or fall back to the debugger file @@ -1242,27 +1248,29 @@ void Debugger::AdoptTopIOHandlerFilesIfInvalid(FileSP &in, StreamFileSP &out, in = GetInputFileSP(); // If there is nothing, use stdin if (!in) - in = std::make_shared<NativeFile>(stdin, false); + in = std::make_shared<NativeFile>(stdin, NativeFile::Unowned); } // If no STDOUT has been set, then set it appropriately - if (!out || !out->GetFile().IsValid()) { + if (!out || !out->GetUnlockedFile().IsValid()) { if (top_reader_sp) out = top_reader_sp->GetOutputStreamFileSP(); else out = GetOutputStreamSP(); // If there is nothing, use stdout if (!out) - out = std::make_shared<StreamFile>(stdout, false); + out = std::make_shared<LockableStreamFile>(stdout, NativeFile::Unowned, + m_output_mutex); } // If no STDERR has been set, then set it appropriately - if (!err || !err->GetFile().IsValid()) { + if (!err || !err->GetUnlockedFile().IsValid()) { if (top_reader_sp) err = top_reader_sp->GetErrorStreamFileSP(); else err = GetErrorStreamSP(); // If there is nothing, use stderr if (!err) - err = std::make_shared<StreamFile>(stderr, false); + err = std::make_shared<LockableStreamFile>(stderr, NativeFile::Unowned, + m_output_mutex); } } diff --git a/lldb/source/Core/IOHandler.cpp b/lldb/source/Core/IOHandler.cpp index ca06b52..98d1475 100644 --- a/lldb/source/Core/IOHandler.cpp +++ b/lldb/source/Core/IOHandler.cpp @@ -54,17 +54,17 @@ using llvm::StringRef; IOHandler::IOHandler(Debugger &debugger, IOHandler::Type type) : IOHandler(debugger, type, - FileSP(), // Adopt STDIN from top input reader - StreamFileSP(), // Adopt STDOUT from top input reader - StreamFileSP(), // Adopt STDERR from top input reader - 0 // Flags + FileSP(), // Adopt STDIN from top input reader + LockableStreamFileSP(), // Adopt STDOUT from top input reader + LockableStreamFileSP(), // Adopt STDERR from top input reader + 0 // Flags ) {} IOHandler::IOHandler(Debugger &debugger, IOHandler::Type type, const lldb::FileSP &input_sp, - const lldb::StreamFileSP &output_sp, - const lldb::StreamFileSP &error_sp, uint32_t flags) + const lldb::LockableStreamFileSP &output_sp, + const lldb::LockableStreamFileSP &error_sp, uint32_t flags) : m_debugger(debugger), m_input_sp(input_sp), m_output_sp(output_sp), m_error_sp(error_sp), m_popped(false), m_flags(flags), m_type(type), m_user_data(nullptr), m_done(false), m_active(false) { @@ -81,30 +81,18 @@ int IOHandler::GetInputFD() { } int IOHandler::GetOutputFD() { - return (m_output_sp ? m_output_sp->GetFile().GetDescriptor() : -1); + return (m_output_sp ? m_output_sp->GetUnlockedFile().GetDescriptor() : -1); } int IOHandler::GetErrorFD() { - return (m_error_sp ? m_error_sp->GetFile().GetDescriptor() : -1); -} - -FILE *IOHandler::GetInputFILE() { - return (m_input_sp ? m_input_sp->GetStream() : nullptr); -} - -FILE *IOHandler::GetOutputFILE() { - return (m_output_sp ? m_output_sp->GetFile().GetStream() : nullptr); -} - -FILE *IOHandler::GetErrorFILE() { - return (m_error_sp ? m_error_sp->GetFile().GetStream() : nullptr); + return (m_error_sp ? m_error_sp->GetUnlockedFile().GetDescriptor() : -1); } FileSP IOHandler::GetInputFileSP() { return m_input_sp; } -StreamFileSP IOHandler::GetOutputStreamFileSP() { return m_output_sp; } +LockableStreamFileSP IOHandler::GetOutputStreamFileSP() { return m_output_sp; } -StreamFileSP IOHandler::GetErrorStreamFileSP() { return m_error_sp; } +LockableStreamFileSP IOHandler::GetErrorStreamFileSP() { return m_error_sp; } bool IOHandler::GetIsInteractive() { return GetInputFileSP() ? GetInputFileSP()->GetIsInteractive() : false; @@ -119,10 +107,9 @@ 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<std::recursive_mutex> guard(m_output_mutex); - lldb::StreamFileSP stream = is_stdout ? m_output_sp : m_error_sp; - stream->Write(s, len); - stream->Flush(); + lldb::LockableStreamFileSP stream_sp = is_stdout ? m_output_sp : m_error_sp; + LockedStreamFile locked_Stream = stream_sp->Lock(); + locked_Stream.Write(s, len); } bool IOHandlerStack::PrintAsync(const char *s, size_t len, bool is_stdout) { @@ -228,19 +215,20 @@ IOHandlerEditline::IOHandlerEditline( llvm::StringRef prompt, llvm::StringRef continuation_prompt, bool multi_line, bool color, uint32_t line_number_start, IOHandlerDelegate &delegate) - : IOHandlerEditline(debugger, type, - FileSP(), // Inherit input from top input reader - StreamFileSP(), // Inherit output from top input reader - StreamFileSP(), // Inherit error from top input reader - 0, // Flags - editline_name, // Used for saving history files - prompt, continuation_prompt, multi_line, color, - line_number_start, delegate) {} + : IOHandlerEditline( + debugger, type, + FileSP(), // Inherit input from top input reader + LockableStreamFileSP(), // Inherit output from top input reader + LockableStreamFileSP(), // Inherit error from top input reader + 0, // Flags + editline_name, // Used for saving history files + prompt, continuation_prompt, multi_line, color, line_number_start, + delegate) {} IOHandlerEditline::IOHandlerEditline( Debugger &debugger, IOHandler::Type type, const lldb::FileSP &input_sp, - const lldb::StreamFileSP &output_sp, const lldb::StreamFileSP &error_sp, - uint32_t flags, + const lldb::LockableStreamFileSP &output_sp, + const lldb::LockableStreamFileSP &error_sp, uint32_t flags, const char *editline_name, // Used for saving history files llvm::StringRef prompt, llvm::StringRef continuation_prompt, bool multi_line, bool color, uint32_t line_number_start, @@ -256,15 +244,12 @@ IOHandlerEditline::IOHandlerEditline( SetPrompt(prompt); #if LLDB_ENABLE_LIBEDIT - bool use_editline = false; - - use_editline = GetInputFILE() && GetOutputFILE() && GetErrorFILE() && - m_input_sp && m_input_sp->GetIsRealTerminal(); - + const bool use_editline = m_input_sp && m_output_sp && m_error_sp && + m_input_sp->GetIsRealTerminal(); if (use_editline) { - m_editline_up = std::make_unique<Editline>(editline_name, GetInputFILE(), - GetOutputFILE(), GetErrorFILE(), - m_color, GetOutputMutex()); + m_editline_up = std::make_unique<Editline>( + editline_name, m_input_sp ? m_input_sp->GetStream() : nullptr, + m_output_sp, m_error_sp, m_color); m_editline_up->SetIsInputCompleteCallback( [this](Editline *editline, StringList &lines) { return this->IsInputCompleteCallback(editline, lines); @@ -366,8 +351,8 @@ bool IOHandlerEditline::GetLine(std::string &line, bool &interrupted) { if (prompt && prompt[0]) { if (m_output_sp) { - m_output_sp->Printf("%s", prompt); - m_output_sp->Flush(); + LockedStreamFile locked_stream = m_output_sp->Lock(); + locked_stream.Printf("%s", prompt); } } } @@ -380,7 +365,7 @@ bool IOHandlerEditline::GetLine(std::string &line, bool &interrupted) { return false; } - FILE *in = GetInputFILE(); + FILE *in = m_input_sp ? m_input_sp->GetStream() : nullptr; char buffer[256]; if (!got_line && !in && m_input_sp) { @@ -545,9 +530,10 @@ bool IOHandlerEditline::GetLines(StringList &lines, bool &interrupted) { std::string line; if (m_base_line_number > 0 && GetIsInteractive()) { if (m_output_sp) { - m_output_sp->Printf("%u%s", - m_base_line_number + (uint32_t)lines.GetSize(), - GetPrompt() == nullptr ? " " : ""); + LockedStreamFile locked_stream = m_output_sp->Lock(); + locked_stream.Printf("%u%s", + m_base_line_number + (uint32_t)lines.GetSize(), + GetPrompt() == nullptr ? " " : ""); } } @@ -630,9 +616,8 @@ 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<std::recursive_mutex> guard(m_output_mutex); - lldb::StreamFileSP stream = is_stdout ? m_output_sp : m_error_sp; - m_editline_up->PrintAsync(stream.get(), s, len); + lldb::LockableStreamFileSP stream_sp = is_stdout ? m_output_sp : m_error_sp; + m_editline_up->PrintAsync(stream_sp, s, len); } else #endif { diff --git a/lldb/source/Core/IOHandlerCursesGUI.cpp b/lldb/source/Core/IOHandlerCursesGUI.cpp index c5eed0c..ee6e847 100644 --- a/lldb/source/Core/IOHandlerCursesGUI.cpp +++ b/lldb/source/Core/IOHandlerCursesGUI.cpp @@ -7576,7 +7576,9 @@ IOHandlerCursesGUI::IOHandlerCursesGUI(Debugger &debugger) void IOHandlerCursesGUI::Activate() { IOHandler::Activate(); if (!m_app_up) { - m_app_up = std::make_unique<Application>(GetInputFILE(), GetOutputFILE()); + m_app_up = std::make_unique<Application>( + m_input_sp ? m_input_sp->GetStream() : nullptr, + m_output_sp ? m_input_sp->GetStream() : nullptr); // This is both a window and a menu delegate std::shared_ptr<ApplicationDelegate> app_delegate_sp( diff --git a/lldb/source/Expression/REPL.cpp b/lldb/source/Expression/REPL.cpp index 4b53537..e5377d3 100644 --- a/lldb/source/Expression/REPL.cpp +++ b/lldb/source/Expression/REPL.cpp @@ -103,8 +103,8 @@ void REPL::IOHandlerActivated(IOHandler &io_handler, bool interactive) { lldb::ProcessSP process_sp = m_target.GetProcessSP(); if (process_sp && process_sp->IsAlive()) return; - lldb::StreamFileSP error_sp(io_handler.GetErrorStreamFileSP()); - error_sp->Printf("REPL requires a running target process.\n"); + LockedStreamFile locked_stream = io_handler.GetErrorStreamFileSP()->Lock(); + locked_stream.Printf("REPL requires a running target process.\n"); io_handler.SetIsDone(true); } @@ -219,8 +219,10 @@ static bool ReadCode(const std::string &path, std::string &code, } void REPL::IOHandlerInputComplete(IOHandler &io_handler, std::string &code) { - lldb::StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); - lldb::StreamFileSP error_sp(io_handler.GetErrorStreamFileSP()); + lldb::StreamFileSP output_sp = std::make_shared<StreamFile>( + io_handler.GetOutputStreamFileSP()->GetUnlockedFileSP()); + lldb::StreamFileSP error_sp = std::make_shared<StreamFile>( + io_handler.GetErrorStreamFileSP()->GetUnlockedFileSP()); bool extra_line = false; bool did_quit = false; diff --git a/lldb/source/Host/common/Editline.cpp b/lldb/source/Host/common/Editline.cpp index 73da1d84..5f7a8b0 100644 --- a/lldb/source/Host/common/Editline.cpp +++ b/lldb/source/Host/common/Editline.cpp @@ -14,6 +14,7 @@ #include "lldb/Host/Editline.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" +#include "lldb/Host/StreamFile.h" #include "lldb/Utility/AnsiTerminal.h" #include "lldb/Utility/CompletionRequest.h" #include "lldb/Utility/FileSpec.h" @@ -23,6 +24,7 @@ #include "lldb/Utility/StreamString.h" #include "lldb/Utility/StringList.h" #include "lldb/Utility/Timeout.h" +#include "lldb/lldb-forward.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/FileSystem.h" @@ -77,6 +79,19 @@ using namespace lldb_private::line_editor; #endif // #if LLDB_EDITLINE_USE_WCHAR +template <typename T> class ScopedOptional { +public: + template <typename... Args> + ScopedOptional(std::optional<T> &optional, Args &&...args) + : m_optional(optional) { + m_optional.emplace(std::forward<Args>(args)...); + } + ~ScopedOptional() { m_optional.reset(); } + +private: + std::optional<T> &m_optional; +}; + bool IsOnlySpaces(const EditLineStringType &content) { for (wchar_t ch : content) { if (ch != EditLineCharType(' ')) @@ -389,11 +404,13 @@ void Editline::MoveCursor(CursorLocation from, CursorLocation to) { (int)((info->cursor - info->buffer) + GetPromptWidth()); int editline_cursor_row = editline_cursor_position / m_terminal_width; + LockedStreamFile locked_stream = m_output_stream_sp->Lock(); + // Determine relative starting and ending lines int fromLine = GetLineIndexForLocation(from, editline_cursor_row); int toLine = GetLineIndexForLocation(to, editline_cursor_row); if (toLine != fromLine) { - fprintf(m_output_file, + fprintf(locked_stream.GetFile().GetStream(), (toLine > fromLine) ? ANSI_DOWN_N_ROWS : ANSI_UP_N_ROWS, std::abs(toLine - fromLine)); } @@ -409,21 +426,23 @@ void Editline::MoveCursor(CursorLocation from, CursorLocation to) { 80) + 1; } - fprintf(m_output_file, ANSI_SET_COLUMN_N, toColumn); + fprintf(locked_stream.GetFile().GetStream(), ANSI_SET_COLUMN_N, toColumn); } void Editline::DisplayInput(int firstIndex) { - fprintf(m_output_file, ANSI_SET_COLUMN_N ANSI_CLEAR_BELOW, 1); + LockedStreamFile locked_stream = m_output_stream_sp->Lock(); + fprintf(locked_stream.GetFile().GetStream(), + ANSI_SET_COLUMN_N ANSI_CLEAR_BELOW, 1); int line_count = (int)m_input_lines.size(); for (int index = firstIndex; index < line_count; index++) { - fprintf(m_output_file, + fprintf(locked_stream.GetFile().GetStream(), "%s" "%s" "%s" EditLineStringFormatSpec " ", m_prompt_ansi_prefix.c_str(), PromptForIndex(index).c_str(), m_prompt_ansi_suffix.c_str(), m_input_lines[index].c_str()); if (index < line_count - 1) - fprintf(m_output_file, "\n"); + fprintf(locked_stream.GetFile().GetStream(), "\n"); } } @@ -535,8 +554,10 @@ int Editline::GetCharacter(EditLineGetCharType *c) { // Paint a ANSI formatted version of the desired prompt over the version // libedit draws. (will only be requested if colors are supported) if (m_needs_prompt_repaint) { + ScopedOptional<LockedStreamFile> scope(m_locked_output, + m_output_stream_sp->Lock()); MoveCursor(CursorLocation::EditingCursor, CursorLocation::EditingPrompt); - fprintf(m_output_file, + fprintf(m_locked_output->GetFile().GetStream(), "%s" "%s" "%s", @@ -574,10 +595,10 @@ int Editline::GetCharacter(EditLineGetCharType *c) { // 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(); + m_locked_output.reset(); int read_count = m_input_connection.Read(&ch, 1, std::nullopt, status, nullptr); - m_output_mutex.lock(); + m_locked_output.emplace(m_output_stream_sp->Lock()); if (m_editor_status == EditorStatus::Interrupted) { while (read_count > 0 && status == lldb::eConnectionStatusSuccess) read_count = @@ -700,12 +721,14 @@ unsigned char Editline::EndOrAddLineCommand(int ch) { } } MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockEnd); - fprintf(m_output_file, "\n"); + LockedStreamFile locked_stream = m_output_stream_sp->Lock(); + fprintf(locked_stream.GetFile().GetStream(), "\n"); m_editor_status = EditorStatus::Complete; return CC_NEWLINE; } unsigned char Editline::DeleteNextCharCommand(int ch) { + LockedStreamFile locked_stream = m_output_stream_sp->Lock(); LineInfoW *info = const_cast<LineInfoW *>(el_wline(m_editline)); // Just delete the next character normally if possible @@ -719,7 +742,7 @@ unsigned char Editline::DeleteNextCharCommand(int ch) { // line is empty, in which case it is treated as EOF if (m_current_line_index == m_input_lines.size() - 1) { if (ch == 4 && info->buffer == info->lastchar) { - fprintf(m_output_file, "^D\n"); + fprintf(locked_stream.GetFile().GetStream(), "^D\n"); m_editor_status = EditorStatus::EndOfInput; return CC_EOF; } @@ -767,7 +790,8 @@ unsigned char Editline::DeletePreviousCharCommand(int ch) { priorLine + m_input_lines[m_current_line_index]; // Repaint from the new line down - fprintf(m_output_file, ANSI_UP_N_ROWS ANSI_SET_COLUMN_N, + LockedStreamFile locked_stream = m_output_stream_sp->Lock(); + fprintf(locked_stream.GetFile().GetStream(), ANSI_UP_N_ROWS ANSI_SET_COLUMN_N, CountRowsForLine(priorLine), 1); DisplayInput(m_current_line_index); @@ -785,17 +809,19 @@ unsigned char Editline::PreviousLineCommand(int ch) { return RecallHistory(HistoryOperation::Older); } + LockedStreamFile locked_stream = m_output_stream_sp->Lock(); + // Start from a known location MoveCursor(CursorLocation::EditingCursor, CursorLocation::EditingPrompt); // Treat moving up from a blank last line as a deletion of that line if (m_current_line_index == m_input_lines.size() - 1 && IsOnlySpaces()) { m_input_lines.erase(m_input_lines.begin() + m_current_line_index); - fprintf(m_output_file, ANSI_CLEAR_BELOW); + fprintf(locked_stream.GetFile().GetStream(), ANSI_CLEAR_BELOW); } SetCurrentLine(m_current_line_index - 1); - fprintf(m_output_file, ANSI_UP_N_ROWS ANSI_SET_COLUMN_N, + fprintf(locked_stream.GetFile().GetStream(), ANSI_UP_N_ROWS ANSI_SET_COLUMN_N, CountRowsForLine(m_input_lines[m_current_line_index]), 1); return CC_NEWLINE; } @@ -829,9 +855,11 @@ unsigned char Editline::NextLineCommand(int ch) { const LineInfoW *info = el_wline(m_editline); int cursor_position = (int)((info->cursor - info->buffer) + GetPromptWidth()); int cursor_row = cursor_position / m_terminal_width; + + LockedStreamFile locked_stream = m_output_stream_sp->Lock(); for (int line_count = 0; line_count < m_current_line_rows - cursor_row; line_count++) { - fprintf(m_output_file, "\n"); + fprintf(locked_stream.GetFile().GetStream(), "\n"); } return CC_NEWLINE; } @@ -1031,7 +1059,9 @@ void Editline::DisplayCompletions( Editline &editline, llvm::ArrayRef<CompletionResult::Completion> results) { assert(!results.empty()); - fprintf(editline.m_output_file, + LockedStreamFile locked_stream = editline.m_output_stream_sp->Lock(); + + fprintf(locked_stream.GetFile().GetStream(), "\n" ANSI_CLEAR_BELOW "Available completions:\n"); /// Account for the current line, the line showing "Available completions" @@ -1049,15 +1079,15 @@ void Editline::DisplayCompletions( size_t cur_pos = 0; while (cur_pos < results.size()) { - cur_pos += - PrintCompletion(editline.m_output_file, results.slice(cur_pos), max_len, - editline.GetTerminalWidth(), - all ? std::nullopt : std::optional<size_t>(page_size)); + cur_pos += PrintCompletion( + locked_stream.GetFile().GetStream(), results.slice(cur_pos), max_len, + editline.GetTerminalWidth(), + all ? std::nullopt : std::optional<size_t>(page_size)); if (cur_pos >= results.size()) break; - fprintf(editline.m_output_file, "More (Y/n/a): "); + fprintf(locked_stream.GetFile().GetStream(), "More (Y/n/a): "); // The type for the output and the type for the parameter are different, // to allow interoperability with older versions of libedit. The container // for the reply must be as wide as what our implementation is using, @@ -1069,11 +1099,11 @@ void Editline::DisplayCompletions( // Check for a ^C or other interruption. if (editline.m_editor_status == EditorStatus::Interrupted) { editline.m_editor_status = EditorStatus::Editing; - fprintf(editline.m_output_file, "^C\n"); + fprintf(locked_stream.GetFile().GetStream(), "^C\n"); break; } - fprintf(editline.m_output_file, "\n"); + fprintf(locked_stream.GetFile().GetStream(), "\n"); if (got_char == -1 || reply == 'n') break; if (reply == 'a') @@ -1182,17 +1212,18 @@ unsigned char Editline::TypedCharacter(int ch) { line_info->lastchar - line_info->buffer); if (std::optional<std::string> to_add = m_suggestion_callback(line)) { + LockedStreamFile locked_stream = m_output_stream_sp->Lock(); std::string to_add_color = m_suggestion_ansi_prefix + to_add.value() + m_suggestion_ansi_suffix; - fputs(typed.c_str(), m_output_file); - fputs(to_add_color.c_str(), m_output_file); + fputs(typed.c_str(), locked_stream.GetFile().GetStream()); + fputs(to_add_color.c_str(), locked_stream.GetFile().GetStream()); size_t new_autosuggestion_size = line.size() + to_add->length(); // Print spaces to hide any remains of a previous longer autosuggestion. if (new_autosuggestion_size < m_previous_autosuggestion_size) { size_t spaces_to_print = m_previous_autosuggestion_size - new_autosuggestion_size; std::string spaces = std::string(spaces_to_print, ' '); - fputs(spaces.c_str(), m_output_file); + fputs(spaces.c_str(), locked_stream.GetFile().GetStream()); } m_previous_autosuggestion_size = new_autosuggestion_size; @@ -1201,7 +1232,7 @@ unsigned char Editline::TypedCharacter(int ch) { int editline_cursor_row = editline_cursor_position / m_terminal_width; int toColumn = editline_cursor_position - (editline_cursor_row * m_terminal_width); - fprintf(m_output_file, ANSI_SET_COLUMN_N, toColumn); + fprintf(locked_stream.GetFile().GetStream(), ANSI_SET_COLUMN_N, toColumn); return CC_REFRESH; } @@ -1236,13 +1267,17 @@ void Editline::ConfigureEditor(bool multiline) { el_end(m_editline); } - m_editline = - el_init(m_editor_name.c_str(), m_input_file, m_output_file, m_error_file); + LockedStreamFile locked_output_stream = m_output_stream_sp->Lock(); + LockedStreamFile locked_error_stream = m_output_stream_sp->Lock(); + m_editline = el_init(m_editor_name.c_str(), m_input_file, + locked_output_stream.GetFile().GetStream(), + locked_error_stream.GetFile().GetStream()); ApplyTerminalSizeChange(); if (m_history_sp && m_history_sp->IsValid()) { if (!m_history_sp->Load()) { - fputs("Could not load history file\n.", m_output_file); + fputs("Could not load history file\n.", + locked_output_stream.GetFile().GetStream()); } el_wset(m_editline, EL_HIST, history, m_history_sp->GetHistoryPtr()); } @@ -1473,12 +1508,12 @@ Editline *Editline::InstanceFor(EditLine *editline) { } Editline::Editline(const char *editline_name, FILE *input_file, - FILE *output_file, FILE *error_file, bool color, - std::recursive_mutex &output_mutex) + lldb::LockableStreamFileSP output_stream_sp, + lldb::LockableStreamFileSP error_stream_sp, bool color) : m_editor_status(EditorStatus::Complete), m_input_file(input_file), - m_output_file(output_file), m_error_file(error_file), - m_input_connection(fileno(input_file), false), m_color(color), - m_output_mutex(output_mutex) { + m_output_stream_sp(output_stream_sp), m_error_stream_sp(error_stream_sp), + m_input_connection(fileno(input_file), false), m_color(color) { + assert(output_stream_sp && error_stream_sp); // Get a shared history instance m_editor_name = (editline_name == nullptr) ? "lldb-tmp" : editline_name; m_history_sp = EditlineHistory::GetHistory(m_editor_name); @@ -1552,9 +1587,9 @@ uint32_t Editline::GetCurrentLine() { return m_current_line_index; } bool Editline::Interrupt() { bool result = true; - std::lock_guard<std::recursive_mutex> guard(m_output_mutex); + LockedStreamFile locked_stream = m_output_stream_sp->Lock(); if (m_editor_status == EditorStatus::Editing) { - fprintf(m_output_file, "^C\n"); + fprintf(locked_stream.GetFile().GetStream(), "^C\n"); result = m_input_connection.InterruptRead(); } m_editor_status = EditorStatus::Interrupted; @@ -1563,10 +1598,10 @@ bool Editline::Interrupt() { bool Editline::Cancel() { bool result = true; - std::lock_guard<std::recursive_mutex> guard(m_output_mutex); + LockedStreamFile locked_stream = m_output_stream_sp->Lock(); if (m_editor_status == EditorStatus::Editing) { MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockStart); - fprintf(m_output_file, ANSI_CLEAR_BELOW); + fprintf(locked_stream.GetFile().GetStream(), ANSI_CLEAR_BELOW); result = m_input_connection.InterruptRead(); } m_editor_status = EditorStatus::Interrupted; @@ -1578,7 +1613,8 @@ bool Editline::GetLine(std::string &line, bool &interrupted) { m_input_lines = std::vector<EditLineStringType>(); m_input_lines.insert(m_input_lines.begin(), EditLineConstString("")); - std::lock_guard<std::recursive_mutex> guard(m_output_mutex); + ScopedOptional<LockedStreamFile> scope(m_locked_output, + m_output_stream_sp->Lock()); lldbassert(m_editor_status != EditorStatus::Editing); if (m_editor_status == EditorStatus::Interrupted) { @@ -1598,7 +1634,7 @@ bool Editline::GetLine(std::string &line, bool &interrupted) { interrupted = m_editor_status == EditorStatus::Interrupted; if (!interrupted) { if (input == nullptr) { - fprintf(m_output_file, "\n"); + fprintf(m_locked_output->GetFile().GetStream(), "\n"); m_editor_status = EditorStatus::EndOfInput; } else { m_history_sp->Enter(input); @@ -1623,7 +1659,9 @@ bool Editline::GetLines(int first_line_number, StringList &lines, m_input_lines = std::vector<EditLineStringType>(); m_input_lines.insert(m_input_lines.begin(), EditLineConstString("")); - std::lock_guard<std::recursive_mutex> guard(m_output_mutex); + ScopedOptional<LockedStreamFile> scope(m_locked_output, + m_output_stream_sp->Lock()); + // Begin the line editing loop DisplayInput(); SetCurrentLine(0); @@ -1652,15 +1690,15 @@ bool Editline::GetLines(int first_line_number, StringList &lines, return m_editor_status != EditorStatus::EndOfInput; } -void Editline::PrintAsync(Stream *stream, const char *s, size_t len) { - std::lock_guard<std::recursive_mutex> guard(m_output_mutex); +void Editline::PrintAsync(lldb::LockableStreamFileSP stream_sp, const char *s, + size_t len) { + LockedStreamFile locked_stream = m_output_stream_sp->Lock(); if (m_editor_status == EditorStatus::Editing) { SaveEditedLine(); MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockStart); - fprintf(m_output_file, ANSI_CLEAR_BELOW); + fprintf(locked_stream.GetFile().GetStream(), ANSI_CLEAR_BELOW); } - stream->Write(s, len); - stream->Flush(); + locked_stream.Write(s, len); if (m_editor_status == EditorStatus::Editing) { DisplayInput(); MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingCursor); diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp index 5346d5a..c363f200 100644 --- a/lldb/source/Interpreter/CommandInterpreter.cpp +++ b/lldb/source/Interpreter/CommandInterpreter.cpp @@ -57,6 +57,7 @@ #include "lldb/Utility/Timer.h" #include "lldb/Host/Config.h" +#include "lldb/lldb-forward.h" #if LLDB_ENABLE_LIBEDIT #include "lldb/Host/Editline.h" #endif @@ -2843,7 +2844,7 @@ void CommandInterpreter::HandleCommandsFromFile( // Used for inheriting the right settings when "command source" might // have nested "command source" commands - lldb::StreamFileSP empty_stream_sp; + lldb::LockableStreamFileSP empty_stream_sp; m_command_source_flags.push_back(flags); IOHandlerSP io_handler_sp(new IOHandlerEditline( debugger, IOHandler::Type::CommandInterpreter, input_file_sp, @@ -3100,25 +3101,26 @@ void CommandInterpreter::PrintCommandOutput(IOHandler &io_handler, llvm::StringRef str, bool is_stdout) { - lldb::StreamFileSP stream = is_stdout ? io_handler.GetOutputStreamFileSP() - : io_handler.GetErrorStreamFileSP(); + lldb::LockableStreamFileSP stream = is_stdout + ? io_handler.GetOutputStreamFileSP() + : io_handler.GetErrorStreamFileSP(); // Split the output into lines and poll for interrupt requests bool had_output = !str.empty(); while (!str.empty()) { llvm::StringRef line; std::tie(line, str) = str.split('\n'); { - std::lock_guard<std::recursive_mutex> guard(io_handler.GetOutputMutex()); - stream->Write(line.data(), line.size()); - stream->Write("\n", 1); + LockedStreamFile stream_file = stream->Lock(); + stream_file.Write(line.data(), line.size()); + stream_file.Write("\n", 1); } } - std::lock_guard<std::recursive_mutex> guard(io_handler.GetOutputMutex()); + LockedStreamFile stream_file = stream->Lock(); if (had_output && INTERRUPT_REQUESTED(GetDebugger(), "Interrupted dumping command output")) - stream->Printf("\n... Interrupted.\n"); - stream->Flush(); + stream_file.Printf("\n... Interrupted.\n"); + stream_file.Flush(); } bool CommandInterpreter::EchoCommandNonInteractive( @@ -3160,9 +3162,9 @@ void CommandInterpreter::IOHandlerInputComplete(IOHandler &io_handler, // 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())) { - std::lock_guard<std::recursive_mutex> guard(io_handler.GetOutputMutex()); - io_handler.GetOutputStreamFileSP()->Printf( - "%s%s\n", io_handler.GetPrompt(), line.c_str()); + LockedStreamFile locked_stream = + io_handler.GetOutputStreamFileSP()->Lock(); + locked_stream.Printf("%s%s\n", io_handler.GetPrompt(), line.c_str()); } } diff --git a/lldb/source/Interpreter/ScriptInterpreter.cpp b/lldb/source/Interpreter/ScriptInterpreter.cpp index a392d57..4424b6c 100644 --- a/lldb/source/Interpreter/ScriptInterpreter.cpp +++ b/lldb/source/Interpreter/ScriptInterpreter.cpp @@ -206,7 +206,8 @@ ScriptInterpreterIORedirect::Create(bool enable_io, Debugger &debugger, ScriptInterpreterIORedirect::ScriptInterpreterIORedirect( std::unique_ptr<File> input, std::unique_ptr<File> output) : m_input_file_sp(std::move(input)), - m_output_file_sp(std::make_shared<StreamFile>(std::move(output))), + m_output_file_sp(std::make_shared<LockableStreamFile>(std::move(output), + m_output_mutex)), m_error_file_sp(m_output_file_sp), m_communication("lldb.ScriptInterpreterIORedirect.comm"), m_disconnect(false) {} @@ -240,7 +241,9 @@ ScriptInterpreterIORedirect::ScriptInterpreterIORedirect( m_disconnect = true; FILE *outfile_handle = fdopen(pipe.ReleaseWriteFileDescriptor(), "w"); - m_output_file_sp = std::make_shared<StreamFile>(outfile_handle, true); + m_output_file_sp = std::make_shared<LockableStreamFile>( + std::make_shared<StreamFile>(outfile_handle, NativeFile::Owned), + m_output_mutex); m_error_file_sp = m_output_file_sp; if (outfile_handle) ::setbuf(outfile_handle, nullptr); @@ -257,9 +260,9 @@ ScriptInterpreterIORedirect::ScriptInterpreterIORedirect( void ScriptInterpreterIORedirect::Flush() { if (m_output_file_sp) - m_output_file_sp->Flush(); + m_output_file_sp->Lock().Flush(); if (m_error_file_sp) - m_error_file_sp->Flush(); + m_error_file_sp->Lock().Flush(); } ScriptInterpreterIORedirect::~ScriptInterpreterIORedirect() { @@ -273,7 +276,7 @@ ScriptInterpreterIORedirect::~ScriptInterpreterIORedirect() { // Close the write end of the pipe since we are done with our one line // script. This should cause the read thread that output_comm is using to // exit. - m_output_file_sp->GetFile().Close(); + m_output_file_sp->GetUnlockedFile().Close(); // The close above should cause this thread to exit when it gets to the end // of file, so let it get all its data. m_communication.JoinReadThread(); diff --git a/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp b/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp index 6d028e3..191863a 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp +++ b/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp @@ -17,6 +17,7 @@ #include "lldb/Utility/Stream.h" #include "lldb/Utility/StringList.h" #include "lldb/Utility/Timer.h" +#include "lldb/lldb-forward.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/FormatAdapters.h" #include <memory> @@ -76,8 +77,13 @@ public: } if (instructions == nullptr) return; - if (interactive) - *io_handler.GetOutputStreamFileSP() << instructions; + if (interactive) { + if (lldb::LockableStreamFileSP output_sp = + io_handler.GetOutputStreamFileSP()) { + LockedStreamFile locked_stream = output_sp->Lock(); + locked_stream << instructions; + } + } } bool IOHandlerIsInputComplete(IOHandler &io_handler, @@ -112,8 +118,11 @@ public: for (BreakpointOptions &bp_options : *bp_options_vec) { Status error = m_script_interpreter.SetBreakpointCommandCallback( bp_options, data.c_str(), /*is_callback=*/false); - if (error.Fail()) - *io_handler.GetErrorStreamFileSP() << error.AsCString() << '\n'; + if (error.Fail()) { + LockedStreamFile locked_stream = + io_handler.GetErrorStreamFileSP()->Lock(); + locked_stream << error.AsCString() << '\n'; + } } io_handler.SetIsDone(true); } break; @@ -130,8 +139,11 @@ public: io_handler.SetIsDone(true); return; } - if (llvm::Error error = m_script_interpreter.GetLua().Run(data)) - *io_handler.GetErrorStreamFileSP() << toString(std::move(error)); + if (llvm::Error error = m_script_interpreter.GetLua().Run(data)) { + LockedStreamFile locked_stream = + io_handler.GetErrorStreamFileSP()->Lock(); + locked_stream << toString(std::move(error)); + } break; } } diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp index 9ea5b95..2b92bea 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp @@ -7,7 +7,10 @@ //===----------------------------------------------------------------------===// #include "lldb/Host/Config.h" +#include "lldb/Host/StreamFile.h" #include "lldb/lldb-enumerations.h" +#include "lldb/lldb-forward.h" +#include <locale> #if LLDB_ENABLE_PYTHON @@ -489,11 +492,11 @@ def function (frame, bp_loc, internal_dict): break; } - if (instructions) { - StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); - if (output_sp && interactive) { - output_sp->PutCString(instructions); - output_sp->Flush(); + if (instructions && interactive) { + if (LockableStreamFileSP stream_sp = io_handler.GetOutputStreamFileSP()) { + LockedStreamFile locked_stream = stream_sp->Lock(); + locked_stream.PutCString(instructions); + locked_stream.Flush(); } } } @@ -527,10 +530,9 @@ void ScriptInterpreterPythonImpl::IOHandlerInputComplete(IOHandler &io_handler, bp_options.SetCallback( ScriptInterpreterPythonImpl::BreakpointCallbackFunction, baton_sp); } else if (!batch_mode) { - StreamFileSP error_sp = io_handler.GetErrorStreamFileSP(); - if (error_sp) { - error_sp->Printf("Warning: No command attached to breakpoint.\n"); - error_sp->Flush(); + if (LockableStreamFileSP error_sp = io_handler.GetErrorStreamFileSP()) { + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf("Warning: No command attached to breakpoint.\n"); } } } @@ -550,10 +552,9 @@ void ScriptInterpreterPythonImpl::IOHandlerInputComplete(IOHandler &io_handler, wp_options->SetCallback( ScriptInterpreterPythonImpl::WatchpointCallbackFunction, baton_sp); } else if (!batch_mode) { - StreamFileSP error_sp = io_handler.GetErrorStreamFileSP(); - if (error_sp) { - error_sp->Printf("Warning: No command attached to breakpoint.\n"); - error_sp->Flush(); + if (LockableStreamFileSP error_sp = io_handler.GetErrorStreamFileSP()) { + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf("Warning: No command attached to breakpoint.\n"); } } m_active_io_handler = eIOHandlerNone; @@ -680,7 +681,7 @@ bool ScriptInterpreterPythonImpl::EnterSession(uint16_t on_entry_flags, PythonDictionary &sys_module_dict = GetSysModuleDictionary(); if (sys_module_dict.IsValid()) { lldb::FileSP top_in_sp; - lldb::StreamFileSP top_out_sp, top_err_sp; + lldb::LockableStreamFileSP top_out_sp, top_err_sp; if (!in_sp || !out_sp || !err_sp || !*in_sp || !*out_sp || !*err_sp) m_debugger.AdoptTopIOHandlerFilesIfInvalid(top_in_sp, top_out_sp, top_err_sp); @@ -696,12 +697,14 @@ bool ScriptInterpreterPythonImpl::EnterSession(uint16_t on_entry_flags, if (!SetStdHandle(out_sp, "stdout", m_saved_stdout, "w")) { if (top_out_sp) - SetStdHandle(top_out_sp->GetFileSP(), "stdout", m_saved_stdout, "w"); + SetStdHandle(top_out_sp->GetUnlockedFileSP(), "stdout", m_saved_stdout, + "w"); } if (!SetStdHandle(err_sp, "stderr", m_saved_stderr, "w")) { if (top_err_sp) - SetStdHandle(top_err_sp->GetFileSP(), "stderr", m_saved_stderr, "w"); + SetStdHandle(top_err_sp->GetUnlockedFileSP(), "stderr", m_saved_stderr, + "w"); } } diff --git a/lldb/unittests/Editline/EditlineTest.cpp b/lldb/unittests/Editline/EditlineTest.cpp index 1327b58..6c5a0c9 100644 --- a/lldb/unittests/Editline/EditlineTest.cpp +++ b/lldb/unittests/Editline/EditlineTest.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "lldb/Host/Config.h" +#include "lldb/Host/File.h" #if LLDB_ENABLE_LIBEDIT @@ -25,6 +26,7 @@ #include "lldb/Host/FileSystem.h" #include "lldb/Host/Pipe.h" #include "lldb/Host/PseudoTerminal.h" +#include "lldb/Host/StreamFile.h" #include "lldb/Utility/Status.h" #include "lldb/Utility/StringList.h" @@ -115,10 +117,17 @@ EditlineAdapter::EditlineAdapter() if (*_el_secondary_file == nullptr) return; + lldb::LockableStreamFileSP output_stream_sp = + std::make_shared<LockableStreamFile>(*_el_secondary_file, + NativeFile::Unowned, output_mutex); + lldb::LockableStreamFileSP error_stream_sp = + std::make_shared<LockableStreamFile>(*_el_secondary_file, + NativeFile::Unowned, output_mutex); + // Create an Editline instance. _editline_sp.reset(new lldb_private::Editline( - "gtest editor", *_el_secondary_file, *_el_secondary_file, - *_el_secondary_file, /*color=*/false, output_mutex)); + "gtest editor", *_el_secondary_file, output_stream_sp, error_stream_sp, + /*color=*/false)); _editline_sp->SetPrompt("> "); // Hookup our input complete callback. |