[Lldb-commits] [lldb] 58279d1 - [lldb] Synchronize the debuggers output & error streams
via lldb-commits
lldb-commits at lists.llvm.org
Wed Feb 19 20:32:04 PST 2025
Author: Jonas Devlieghere
Date: 2025-02-19T20:32:00-08:00
New Revision: 58279d1ee1b567e8ca793d6d1eb6e0f1d5e7279e
URL: https://github.com/llvm/llvm-project/commit/58279d1ee1b567e8ca793d6d1eb6e0f1d5e7279e
DIFF: https://github.com/llvm/llvm-project/commit/58279d1ee1b567e8ca793d6d1eb6e0f1d5e7279e.diff
LOG: [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.
Added:
Modified:
lldb/include/lldb/Core/Debugger.h
lldb/include/lldb/Core/IOHandler.h
lldb/include/lldb/Host/Editline.h
lldb/include/lldb/Host/File.h
lldb/include/lldb/Host/StreamFile.h
lldb/include/lldb/Interpreter/ScriptInterpreter.h
lldb/include/lldb/lldb-forward.h
lldb/source/Commands/CommandObjectBreakpointCommand.cpp
lldb/source/Commands/CommandObjectCommands.cpp
lldb/source/Commands/CommandObjectExpression.cpp
lldb/source/Commands/CommandObjectTarget.cpp
lldb/source/Commands/CommandObjectType.cpp
lldb/source/Commands/CommandObjectWatchpointCommand.cpp
lldb/source/Core/Debugger.cpp
lldb/source/Core/IOHandler.cpp
lldb/source/Core/IOHandlerCursesGUI.cpp
lldb/source/Expression/REPL.cpp
lldb/source/Host/common/Editline.cpp
lldb/source/Interpreter/CommandInterpreter.cpp
lldb/source/Interpreter/ScriptInterpreter.cpp
lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp
lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
lldb/unittests/Editline/EditlineTest.cpp
Removed:
################################################################################
diff --git a/lldb/include/lldb/Core/Debugger.h b/lldb/include/lldb/Core/Debugger.h
index 7f08f3dd26106..9c8a9623fe689 100644
--- a/lldb/include/lldb/Core/Debugger.h
+++ b/lldb/include/lldb/Core/Debugger.h
@@ -131,13 +131,16 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
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 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
// 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 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
/// 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 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
// 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 d6ac1cc8b5a14..fc0c676883b4a 100644
--- a/lldb/include/lldb/Core/IOHandler.h
+++ b/lldb/include/lldb/Core/IOHandler.h
@@ -53,8 +53,9 @@ class IOHandler {
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 @@ class IOHandler {
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 @@ class IOHandler {
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 @@ class IOHandlerEditline : public IOHandler {
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 @@ class IOHandlerEditline : public IOHandler {
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 27b863870090c..8964d37be8823 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 @@ class Editline {
/// 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 @@ class Editline {
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 @@ class Editline {
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 5ce53c93b1b91..9e2d0abe0b1af 100644
--- a/lldb/include/lldb/Host/File.h
+++ b/lldb/include/lldb/Host/File.h
@@ -377,6 +377,11 @@ class File : public IOObject {
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 2c96e13565a00..e37661a9938c0 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 @@ class StreamFile : public Stream {
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 2c2bd6f232e09..c5aa19959aa61 100644
--- a/lldb/include/lldb/Interpreter/ScriptInterpreter.h
+++ b/lldb/include/lldb/Interpreter/ScriptInterpreter.h
@@ -116,8 +116,12 @@ class ScriptInterpreterIORedirect {
~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 @@ class ScriptInterpreterIORedirect {
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 @@ class ScriptInterpreter : public PluginInterface {
dest.clear();
return false;
}
-
+
virtual StructuredData::ObjectSP
GetOptionsForCommandObject(StructuredData::GenericSP cmd_obj_sp) {
return {};
@@ -488,9 +493,9 @@ class ScriptInterpreter : public PluginInterface {
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 fc7456a4b9a32..cda55ef06e549 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 ac2db5973effa..a913ed5fa12b3 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 f069b2feb5cb7..dd841cb5cb4cc 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 @@ class CommandObjectCommandsScriptAdd : public CommandObjectParsed,
};
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 @@ class CommandObjectCommandsScriptAdd : public CommandObjectParsed,
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 @@ class CommandObjectCommandsScriptAdd : public CommandObjectParsed,
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 18526c4de2cb0..a95dea63720ac 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 71ddc8d933e1e..bd9470b804949 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 @@ Filter Options:
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 @@ Filter Options:
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 e4c6e374446e8..41630b61c2f0e 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 @@ class CommandObjectTypeSummaryAdd : public CommandObjectParsed,
"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 @@ class CommandObjectTypeSummaryAdd : public CommandObjectParsed,
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 @@ class CommandObjectTypeSummaryAdd : public CommandObjectParsed,
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 @@ class CommandObjectTypeSummaryAdd : public CommandObjectParsed,
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 @@ class CommandObjectTypeSynthAdd : public CommandObjectParsed,
}
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 @@ class CommandObjectTypeSynthAdd : public CommandObjectParsed,
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 @@ class CommandObjectTypeSynthAdd : public CommandObjectParsed,
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 @@ class CommandObjectTypeFormatterClear : public CommandObjectParsed {
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 @@ class CommandObjectTypeSynthList
class CommandObjectTypeFilterDelete : public CommandObjectTypeFormatterDelete {
public:
CommandObjectTypeFilterDelete(CommandInterpreter &interpreter)
- : CommandObjectTypeFormatterDelete(
- interpreter, eFormatCategoryItemFilter) {}
+ : CommandObjectTypeFormatterDelete(interpreter,
+ eFormatCategoryItemFilter) {}
~CommandObjectTypeFilterDelete() override = default;
};
@@ -2081,13 +2090,12 @@ class CommandObjectTypeFilterDelete : public CommandObjectTypeFormatterDelete {
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 ab1a2b390936c..507ef3fbe4759 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 8b7814d434ee9..242ef1c8a4596 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 ca06b52b874db..98d14758f1987 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 c5eed0c0b4089..ee6e847cdb688 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 4b53537e50e62..e5377d3114af3 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 73da1d8481618..5f7a8b0190a1d 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
diff erent,
// 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 5346d5a2d162a..c363f20081f9e 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 a392d5777a021..4424b6c894356 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 6d028e324ee4e..191863ae25d7b 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 @@ class IOHandlerLuaInterpreter : public IOHandlerDelegate,
}
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 @@ class IOHandlerLuaInterpreter : public IOHandlerDelegate,
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 @@ class IOHandlerLuaInterpreter : public IOHandlerDelegate,
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 9ea5b95a3d803..2b92beaf6c5ef 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 1327b587e7c3d..6c5a0c907a33e 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.
More information about the lldb-commits
mailing list