[Lldb-commits] [lldb] [lldb] Synchronize the debugger's stdout and stderr streams (PR #126630)
Jonas Devlieghere via lldb-commits
lldb-commits at lists.llvm.org
Tue Feb 18 21:07:05 PST 2025
https://github.com/JDevlieghere updated https://github.com/llvm/llvm-project/pull/126630
>From 0671891112526a02f708432d10fa416901fe1c8d Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jonas at devlieghere.com>
Date: Tue, 18 Feb 2025 10:34:05 -0800
Subject: [PATCH 1/4] [lldb] Make GetOutputStreamSP and GetErrorStreamSP
protected
This makes GetOutputStreamSP and GetErrorStreamSP protected members of
Debugger. Users who want to print to the debugger's stream should use
GetAsyncOutputStreamSP and GetAsyncErrorStreamSP instead and the few
remaining stragglers have been migrated.
---
lldb/include/lldb/Core/Debugger.h | 20 ++++++----
lldb/include/lldb/Target/ThreadPlanTracer.h | 2 +-
lldb/source/API/SBDebugger.cpp | 12 +++---
lldb/source/Commands/CommandObjectGUI.cpp | 8 ++--
lldb/source/Commands/CommandObjectLog.cpp | 3 +-
lldb/source/Core/Debugger.cpp | 8 ++--
.../source/Interpreter/CommandInterpreter.cpp | 4 +-
lldb/source/Interpreter/ScriptInterpreter.cpp | 4 +-
.../DynamicLoaderDarwinKernel.cpp | 9 +++--
.../UBSan/InstrumentationRuntimeUBSan.cpp | 2 -
.../Utility/ReportRetriever.cpp | 4 +-
.../Lua/ScriptInterpreterLua.cpp | 4 +-
lldb/source/Target/ThreadPlanTracer.cpp | 39 ++++++++++---------
13 files changed, 62 insertions(+), 57 deletions(-)
diff --git a/lldb/include/lldb/Core/Debugger.h b/lldb/include/lldb/Core/Debugger.h
index d7751ca045bb2..7f08f3dd26106 100644
--- a/lldb/include/lldb/Core/Debugger.h
+++ b/lldb/include/lldb/Core/Debugger.h
@@ -131,17 +131,13 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
void SetAsyncExecution(bool async);
- lldb::FileSP GetInputFileSP() { return m_input_file_sp; }
-
- lldb::StreamFileSP GetOutputStreamSP() { return m_output_stream_sp; }
-
- lldb::StreamFileSP GetErrorStreamSP() { return m_error_stream_sp; }
-
File &GetInputFile() { return *m_input_file_sp; }
- File &GetOutputFile() { return m_output_stream_sp->GetFile(); }
+ lldb::FileSP GetInputFileSP() { return m_input_file_sp; }
+
+ lldb::FileSP GetOutputFileSP() { return m_output_stream_sp->GetFileSP(); }
- File &GetErrorFile() { return m_error_stream_sp->GetFile(); }
+ lldb::FileSP GetErrorFileSP() { return m_error_stream_sp->GetFileSP(); }
repro::DataRecorder *GetInputRecorder();
@@ -649,6 +645,14 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
void PrintProgress(const ProgressEventData &data);
+ /// Except for Debugger and IOHandler, GetOutputStreamSP and GetErrorStreamSP
+ /// 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; }
+ /// @}
+
void PushIOHandler(const lldb::IOHandlerSP &reader_sp,
bool cancel_top_handler = true);
diff --git a/lldb/include/lldb/Target/ThreadPlanTracer.h b/lldb/include/lldb/Target/ThreadPlanTracer.h
index a6fd2f031dc22..7c45e213f94f1 100644
--- a/lldb/include/lldb/Target/ThreadPlanTracer.h
+++ b/lldb/include/lldb/Target/ThreadPlanTracer.h
@@ -56,7 +56,7 @@ class ThreadPlanTracer {
Process &m_process;
lldb::tid_t m_tid;
- Stream *GetLogStream();
+ lldb::StreamSP GetLogStreamSP();
virtual void Log();
diff --git a/lldb/source/API/SBDebugger.cpp b/lldb/source/API/SBDebugger.cpp
index bf19d2ff8333c..e646b09e05852 100644
--- a/lldb/source/API/SBDebugger.cpp
+++ b/lldb/source/API/SBDebugger.cpp
@@ -509,14 +509,14 @@ SBFile SBDebugger::GetInputFile() {
FILE *SBDebugger::GetOutputFileHandle() {
LLDB_INSTRUMENT_VA(this);
if (m_opaque_sp)
- return m_opaque_sp->GetOutputStreamSP()->GetFile().GetStream();
+ return m_opaque_sp->GetOutputFileSP()->GetStream();
return nullptr;
}
SBFile SBDebugger::GetOutputFile() {
LLDB_INSTRUMENT_VA(this);
if (m_opaque_sp)
- return SBFile(m_opaque_sp->GetOutputStreamSP()->GetFileSP());
+ return SBFile(m_opaque_sp->GetOutputFileSP());
return SBFile();
}
@@ -524,7 +524,7 @@ FILE *SBDebugger::GetErrorFileHandle() {
LLDB_INSTRUMENT_VA(this);
if (m_opaque_sp)
- return m_opaque_sp->GetErrorStreamSP()->GetFile().GetStream();
+ return m_opaque_sp->GetErrorFileSP()->GetStream();
return nullptr;
}
@@ -532,7 +532,7 @@ SBFile SBDebugger::GetErrorFile() {
LLDB_INSTRUMENT_VA(this);
SBFile file;
if (m_opaque_sp)
- return SBFile(m_opaque_sp->GetErrorStreamSP()->GetFileSP());
+ return SBFile(m_opaque_sp->GetErrorFileSP());
return SBFile();
}
@@ -573,8 +573,8 @@ void SBDebugger::HandleCommand(const char *command) {
sb_interpreter.HandleCommand(command, result, false);
- result.PutError(m_opaque_sp->GetErrorStreamSP()->GetFileSP());
- result.PutOutput(m_opaque_sp->GetOutputStreamSP()->GetFileSP());
+ result.PutError(m_opaque_sp->GetErrorFileSP());
+ result.PutOutput(m_opaque_sp->GetOutputFileSP());
if (!m_opaque_sp->GetAsyncExecution()) {
SBProcess process(GetCommandInterpreter().GetProcess());
diff --git a/lldb/source/Commands/CommandObjectGUI.cpp b/lldb/source/Commands/CommandObjectGUI.cpp
index b56e49b073b03..8630171bae9d1 100644
--- a/lldb/source/Commands/CommandObjectGUI.cpp
+++ b/lldb/source/Commands/CommandObjectGUI.cpp
@@ -28,10 +28,10 @@ void CommandObjectGUI::DoExecute(Args &args, CommandReturnObject &result) {
#if LLDB_ENABLE_CURSES
Debugger &debugger = GetDebugger();
- File &input = debugger.GetInputFile();
- File &output = debugger.GetOutputFile();
- if (input.GetStream() && output.GetStream() && input.GetIsRealTerminal() &&
- input.GetIsInteractive()) {
+ FileSP input_sp = debugger.GetInputFileSP();
+ FileSP output_sp = debugger.GetOutputFileSP();
+ if (input_sp->GetStream() && output_sp->GetStream() &&
+ input_sp->GetIsRealTerminal() && input_sp->GetIsInteractive()) {
IOHandlerSP io_handler_sp(new IOHandlerCursesGUI(debugger));
if (io_handler_sp)
debugger.RunIOHandlerAsync(io_handler_sp);
diff --git a/lldb/source/Commands/CommandObjectLog.cpp b/lldb/source/Commands/CommandObjectLog.cpp
index 5fb2dfaab8de0..17efae189b05e 100644
--- a/lldb/source/Commands/CommandObjectLog.cpp
+++ b/lldb/source/Commands/CommandObjectLog.cpp
@@ -394,7 +394,8 @@ class CommandObjectLogDump : public CommandObjectParsed {
(*file)->GetDescriptor(), /*shouldClose=*/true);
} else {
stream_up = std::make_unique<llvm::raw_fd_ostream>(
- GetDebugger().GetOutputFile().GetDescriptor(), /*shouldClose=*/false);
+ GetDebugger().GetOutputFileSP()->GetDescriptor(),
+ /*shouldClose=*/false);
}
const std::string channel = std::string(args[0].ref());
diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp
index 18569e155b517..18cdec4e0af73 100644
--- a/lldb/source/Core/Debugger.cpp
+++ b/lldb/source/Core/Debugger.cpp
@@ -947,7 +947,7 @@ Debugger::Debugger(lldb::LogOutputCallback log_callback, void *baton)
if (term && !strcmp(term, "dumb"))
SetUseColor(false);
// Turn off use-color if we don't write to a terminal with color support.
- if (!GetOutputFile().GetIsTerminalWithColors())
+ if (!GetOutputFileSP()->GetIsTerminalWithColors())
SetUseColor(false);
if (Diagnostics::Enabled()) {
@@ -1678,7 +1678,7 @@ bool Debugger::EnableLog(llvm::StringRef channel,
LLDB_LOG_OPTION_PREPEND_TIMESTAMP | LLDB_LOG_OPTION_PREPEND_THREAD_NAME;
} else if (log_file.empty()) {
log_handler_sp =
- CreateLogHandler(log_handler_kind, GetOutputFile().GetDescriptor(),
+ CreateLogHandler(log_handler_kind, GetOutputFileSP()->GetDescriptor(),
/*should_close=*/false, buffer_size);
} else {
auto pos = m_stream_handlers.find(log_file);
@@ -2111,8 +2111,8 @@ void Debugger::HandleProgressEvent(const lldb::EventSP &event_sp) {
// Determine whether the current output file is an interactive terminal with
// color support. We assume that if we support ANSI escape codes we support
// vt100 escape codes.
- File &file = GetOutputFile();
- if (!file.GetIsInteractive() || !file.GetIsTerminalWithColors())
+ FileSP file_sp = GetOutputFileSP();
+ if (!file_sp->GetIsInteractive() || !file_sp->GetIsTerminalWithColors())
return;
StreamSP output = GetAsyncOutputStream();
diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp
index acdec84a1689b..5346d5a2d162a 100644
--- a/lldb/source/Interpreter/CommandInterpreter.cpp
+++ b/lldb/source/Interpreter/CommandInterpreter.cpp
@@ -2837,8 +2837,8 @@ void CommandInterpreter::HandleCommandsFromFile(
}
if (flags & eHandleCommandFlagPrintResult) {
- debugger.GetOutputFile().Printf("Executing commands in '%s'.\n",
- cmd_file_path.c_str());
+ debugger.GetOutputFileSP()->Printf("Executing commands in '%s'.\n",
+ cmd_file_path.c_str());
}
// Used for inheriting the right settings when "command source" might
diff --git a/lldb/source/Interpreter/ScriptInterpreter.cpp b/lldb/source/Interpreter/ScriptInterpreter.cpp
index 8d10e5de01225..a392d5777a021 100644
--- a/lldb/source/Interpreter/ScriptInterpreter.cpp
+++ b/lldb/source/Interpreter/ScriptInterpreter.cpp
@@ -245,8 +245,8 @@ ScriptInterpreterIORedirect::ScriptInterpreterIORedirect(
if (outfile_handle)
::setbuf(outfile_handle, nullptr);
- result->SetImmediateOutputFile(debugger.GetOutputStreamSP()->GetFileSP());
- result->SetImmediateErrorFile(debugger.GetErrorStreamSP()->GetFileSP());
+ result->SetImmediateOutputFile(debugger.GetOutputFileSP());
+ result->SetImmediateErrorFile(debugger.GetErrorFileSP());
}
}
diff --git a/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp b/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp
index cff44b588e26e..1d4cda6c046b7 100644
--- a/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp
+++ b/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp
@@ -1193,7 +1193,7 @@ bool DynamicLoaderDarwinKernel::ReadKextSummaryHeader() {
m_kext_summary_header.version = data.GetU32(&offset);
if (m_kext_summary_header.version > 128) {
lldb::StreamSP s =
- m_process->GetTarget().GetDebugger().GetOutputStreamSP();
+ m_process->GetTarget().GetDebugger().GetAsyncOutputStream();
s->Printf("WARNING: Unable to read kext summary header, got "
"improbable version number %u\n",
m_kext_summary_header.version);
@@ -1208,7 +1208,7 @@ bool DynamicLoaderDarwinKernel::ReadKextSummaryHeader() {
// If we get an improbably large entry_size, we're probably
// getting bad memory.
lldb::StreamSP s =
- m_process->GetTarget().GetDebugger().GetOutputStreamSP();
+ m_process->GetTarget().GetDebugger().GetAsyncOutputStream();
s->Printf("WARNING: Unable to read kext summary header, got "
"improbable entry_size %u\n",
m_kext_summary_header.entry_size);
@@ -1226,7 +1226,7 @@ bool DynamicLoaderDarwinKernel::ReadKextSummaryHeader() {
// If we get an improbably large number of kexts, we're probably
// getting bad memory.
lldb::StreamSP s =
- m_process->GetTarget().GetDebugger().GetOutputStreamSP();
+ m_process->GetTarget().GetDebugger().GetAsyncOutputStream();
s->Printf("WARNING: Unable to read kext summary header, got "
"improbable number of kexts %u\n",
m_kext_summary_header.entry_count);
@@ -1330,7 +1330,8 @@ bool DynamicLoaderDarwinKernel::ParseKextSummaries(
number_of_old_kexts_being_removed == 0)
return true;
- lldb::StreamSP s = m_process->GetTarget().GetDebugger().GetOutputStreamSP();
+ lldb::StreamSP s =
+ m_process->GetTarget().GetDebugger().GetAsyncOutputStream();
if (load_kexts) {
if (number_of_new_kexts_being_added > 0 &&
number_of_old_kexts_being_removed > 0) {
diff --git a/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp b/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp
index 8c2700cf21de9..c2db3540a797b 100644
--- a/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp
+++ b/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp
@@ -116,8 +116,6 @@ StructuredData::ObjectSP InstrumentationRuntimeUBSan::RetrieveReportData(
if (!frame_sp)
return StructuredData::ObjectSP();
- StreamFileSP Stream = target.GetDebugger().GetOutputStreamSP();
-
EvaluateExpressionOptions options;
options.SetUnwindOnError(true);
options.SetTryAllThreads(true);
diff --git a/lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.cpp b/lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.cpp
index 74e0fa7d49f82..d61c59776eee6 100644
--- a/lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.cpp
+++ b/lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.cpp
@@ -210,8 +210,8 @@ bool ReportRetriever::NotifyBreakpointHit(ProcessSP process_sp,
InstrumentationRuntimeStopInfo::CreateStopReasonWithInstrumentationData(
*thread_sp, description, report));
- if (StreamFileSP stream_sp = StreamFileSP(
- process_sp->GetTarget().GetDebugger().GetOutputStreamSP()))
+ if (StreamSP stream_sp =
+ process_sp->GetTarget().GetDebugger().GetAsyncOutputStream())
stream_sp->Printf("AddressSanitizer report breakpoint hit. Use 'thread "
"info -s' to get extended information about the "
"report.\n");
diff --git a/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp b/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp
index 7e8eee9f5aa4f..6d028e324ee4e 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp
@@ -45,8 +45,8 @@ class IOHandlerLuaInterpreter : public IOHandlerDelegate,
m_script_interpreter(script_interpreter),
m_active_io_handler(active_io_handler) {
llvm::cantFail(m_script_interpreter.GetLua().ChangeIO(
- debugger.GetOutputFile().GetStream(),
- debugger.GetErrorFile().GetStream()));
+ debugger.GetOutputFileSP()->GetStream(),
+ debugger.GetErrorFileSP()->GetStream()));
llvm::cantFail(m_script_interpreter.EnterSession(debugger.GetID()));
}
diff --git a/lldb/source/Target/ThreadPlanTracer.cpp b/lldb/source/Target/ThreadPlanTracer.cpp
index a119bf8589279..ab63cc7f6c223 100644
--- a/lldb/source/Target/ThreadPlanTracer.cpp
+++ b/lldb/source/Target/ThreadPlanTracer.cpp
@@ -27,6 +27,7 @@
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/State.h"
+#include "lldb/lldb-forward.h"
using namespace lldb;
using namespace lldb_private;
@@ -41,13 +42,13 @@ ThreadPlanTracer::ThreadPlanTracer(Thread &thread)
: m_process(*thread.GetProcess().get()), m_tid(thread.GetID()),
m_enabled(false), m_stream_sp(), m_thread(nullptr) {}
-Stream *ThreadPlanTracer::GetLogStream() {
+StreamSP ThreadPlanTracer::GetLogStreamSP() {
if (m_stream_sp)
- return m_stream_sp.get();
+ return m_stream_sp;
else {
TargetSP target_sp(GetThread().CalculateTarget());
if (target_sp)
- return target_sp->GetDebugger().GetOutputStreamSP().get();
+ return target_sp->GetDebugger().GetAsyncOutputStream();
}
return nullptr;
}
@@ -65,12 +66,11 @@ void ThreadPlanTracer::Log() {
bool show_frame_index = false;
bool show_fullpaths = false;
- Stream *stream = GetLogStream();
- if (stream) {
- GetThread().GetStackFrameAtIndex(0)->Dump(stream, show_frame_index,
+ if (StreamSP stream_sp = GetLogStreamSP()) {
+ GetThread().GetStackFrameAtIndex(0)->Dump(stream_sp.get(), show_frame_index,
show_fullpaths);
- stream->Printf("\n");
- stream->Flush();
+ stream_sp->Printf("\n");
+ stream_sp->Flush();
}
}
@@ -129,9 +129,9 @@ void ThreadPlanAssemblyTracer::TracingStarted() {
void ThreadPlanAssemblyTracer::TracingEnded() { m_register_values.clear(); }
void ThreadPlanAssemblyTracer::Log() {
- Stream *stream = GetLogStream();
+ StreamSP stream_sp = GetLogStreamSP();
- if (!stream)
+ if (!stream_sp)
return;
RegisterContext *reg_ctx = GetThread().GetRegisterContext().get();
@@ -142,9 +142,10 @@ void ThreadPlanAssemblyTracer::Log() {
uint8_t buffer[16] = {0}; // Must be big enough for any single instruction
addr_valid = m_process.GetTarget().ResolveLoadAddress(pc, pc_addr);
- pc_addr.Dump(stream, &GetThread(), Address::DumpStyleResolvedDescription,
+ pc_addr.Dump(stream_sp.get(), &GetThread(),
+ Address::DumpStyleResolvedDescription,
Address::DumpStyleModuleWithFileAddress);
- stream->PutCString(" ");
+ stream_sp->PutCString(" ");
Disassembler *disassembler = GetDisassembler();
if (disassembler) {
@@ -175,7 +176,7 @@ void ThreadPlanAssemblyTracer::Log() {
instruction_list.GetInstructionAtIndex(0).get();
const FormatEntity::Entry *disassemble_format =
m_process.GetTarget().GetDebugger().GetDisassemblyFormat();
- instruction->Dump(stream, max_opcode_byte_size, show_address,
+ instruction->Dump(stream_sp.get(), max_opcode_byte_size, show_address,
show_bytes, show_control_flow_kind, nullptr, nullptr,
nullptr, disassemble_format, 0);
}
@@ -198,12 +199,12 @@ void ThreadPlanAssemblyTracer::Log() {
if (abi->GetArgumentValues(GetThread(), value_list)) {
for (int arg_index = 0; arg_index < num_args; ++arg_index) {
- stream->Printf(
+ stream_sp->Printf(
"\n\targ[%d]=%llx", arg_index,
value_list.GetValueAtIndex(arg_index)->GetScalar().ULongLong());
if (arg_index + 1 < num_args)
- stream->PutCString(", ");
+ stream_sp->PutCString(", ");
}
}
}
@@ -222,14 +223,14 @@ void ThreadPlanAssemblyTracer::Log() {
if (m_register_values[reg_num].GetType() == RegisterValue::eTypeInvalid ||
reg_value != m_register_values[reg_num]) {
if (reg_value.GetType() != RegisterValue::eTypeInvalid) {
- stream->PutCString("\n\t");
- DumpRegisterValue(reg_value, *stream, *reg_info, true, false,
+ stream_sp->PutCString("\n\t");
+ DumpRegisterValue(reg_value, *stream_sp, *reg_info, true, false,
eFormatDefault);
}
}
m_register_values[reg_num] = reg_value;
}
}
- stream->EOL();
- stream->Flush();
+ stream_sp->EOL();
+ stream_sp->Flush();
}
>From c45c55d6bbde8d595423258a4d796249f3444ddd Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jonas at devlieghere.com>
Date: Tue, 11 Feb 2025 19:54:35 -0800
Subject: [PATCH 2/4] [lldb] Synchronize the debugger's stdout and stderr
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.
(cherry picked from commit d7b670430b918af5ab1501293c35158870955dc9)
---
lldb/include/lldb/Core/Debugger.h | 19 ++-
lldb/include/lldb/Core/IOHandler.h | 33 ++---
lldb/include/lldb/Host/Editline.h | 14 +-
lldb/include/lldb/Host/StreamFile.h | 46 +++++++
.../lldb/Interpreter/ScriptInterpreter.h | 18 ++-
lldb/include/lldb/lldb-forward.h | 2 +
.../CommandObjectBreakpointCommand.cpp | 10 +-
.../source/Commands/CommandObjectCommands.cpp | 62 +++++----
.../Commands/CommandObjectExpression.cpp | 9 +-
lldb/source/Commands/CommandObjectTarget.cpp | 35 ++---
lldb/source/Commands/CommandObjectType.cpp | 122 ++++++++++--------
.../CommandObjectWatchpointCommand.cpp | 14 +-
lldb/source/Core/Debugger.cpp | 26 ++--
lldb/source/Core/IOHandler.cpp | 91 ++++++-------
lldb/source/Core/IOHandlerCursesGUI.cpp | 4 +-
lldb/source/Expression/REPL.cpp | 10 +-
lldb/source/Host/common/Editline.cpp | 114 +++++++++-------
.../source/Interpreter/CommandInterpreter.cpp | 26 ++--
lldb/source/Interpreter/ScriptInterpreter.cpp | 11 +-
.../Lua/ScriptInterpreterLua.cpp | 24 +++-
.../Python/ScriptInterpreterPython.cpp | 35 ++---
lldb/unittests/Editline/EditlineTest.cpp | 10 +-
22 files changed, 423 insertions(+), 312 deletions(-)
diff --git a/lldb/include/lldb/Core/Debugger.h b/lldb/include/lldb/Core/Debugger.h
index 7f08f3dd26106..4c08a1315cdcc 100644
--- a/lldb/include/lldb/Core/Debugger.h
+++ b/lldb/include/lldb/Core/Debugger.h
@@ -131,13 +131,12 @@ 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 +197,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 +648,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 +692,8 @@ 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;
/// 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..ac3bef0e26c7d 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,8 @@ 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;
ConnectionFileDescriptor m_input_connection;
IsInputCompleteCallbackType m_is_input_complete_callback;
@@ -411,7 +414,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/StreamFile.h b/lldb/include/lldb/Host/StreamFile.h
index 2c96e13565a00..9df98a406a458 100644
--- a/lldb/include/lldb/Host/StreamFile.h
+++ b/lldb/include/lldb/Host/StreamFile.h
@@ -13,9 +13,11 @@
#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>
namespace lldb_private {
@@ -52,6 +54,50 @@ class StreamFile : public Stream {
const StreamFile &operator=(const StreamFile &) = delete;
};
+class LockableStreamFile;
+class LockedStreamFile : public StreamFile {
+public:
+ ~LockedStreamFile() { Flush(); }
+
+private:
+ LockedStreamFile(std::shared_ptr<File> file, std::recursive_mutex &mutex)
+ : StreamFile(file), m_guard(mutex) {}
+
+ friend class LockableStreamFile;
+
+ std::lock_guard<std::recursive_mutex> m_guard;
+};
+
+class LockableStreamFile {
+public:
+ LockableStreamFile(std::shared_ptr<StreamFile> stream_file_sp)
+ : m_file_sp(stream_file_sp->GetFileSP()) {}
+ LockableStreamFile(StreamFile &stream_file)
+ : m_file_sp(stream_file.GetFileSP()) {}
+ LockableStreamFile(FILE *fh, bool transfer_ownership)
+ : m_file_sp(std::make_shared<NativeFile>(fh, transfer_ownership)) {}
+ LockableStreamFile(std::shared_ptr<File> file_sp) : m_file_sp(file_sp) {}
+
+ 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; }
+ /// @}
+
+ std::recursive_mutex &GetMutex() { return m_mutex; }
+
+protected:
+ std::shared_ptr<File> m_file_sp;
+ std::recursive_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..8ae9dc0b72019 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,8 @@ 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;
ThreadedCommunication m_communication;
bool m_disconnect;
};
@@ -478,7 +482,7 @@ class ScriptInterpreter : public PluginInterface {
dest.clear();
return false;
}
-
+
virtual StructuredData::ObjectSP
GetOptionsForCommandObject(StructuredData::GenericSP cmd_obj_sp) {
return {};
@@ -488,9 +492,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 7e26381c92405..77f4f636033d0 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;
@@ -542,11 +544,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 da50fe04fa2b6..b95eaa6bc56ef 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"
@@ -4918,11 +4919,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");
+ }
}
}
@@ -4930,12 +4933,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 {
@@ -4944,11 +4947,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 18cdec4e0af73..f18132a685030 100644
--- a/lldb/source/Core/Debugger.cpp
+++ b/lldb/source/Core/Debugger.cpp
@@ -874,8 +874,8 @@ 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_output_stream_sp(std::make_shared<LockableStreamFile>(stdout, false)),
+ m_error_stream_sp(std::make_shared<LockableStreamFile>(stderr, false)),
m_input_recorder(nullptr),
m_broadcaster_manager_sp(BroadcasterManager::MakeBroadcasterManager()),
m_terminal_state(), m_target_list(*this), m_platform_list(),
@@ -1083,12 +1083,12 @@ 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);
}
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);
}
void Debugger::SaveInputTerminalState() {
@@ -1198,9 +1198,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 +1226,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
@@ -1245,24 +1247,24 @@ void Debugger::AdoptTopIOHandlerFilesIfInvalid(FileSP &in, StreamFileSP &out,
in = std::make_shared<NativeFile>(stdin, false);
}
// 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, false);
}
// 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, false);
}
}
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..49480b4098723 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"
@@ -389,11 +391,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 +413,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 +541,9 @@ 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) {
+ LockedStreamFile locked_stream = m_output_stream_sp->Lock();
MoveCursor(CursorLocation::EditingCursor, CursorLocation::EditingPrompt);
- fprintf(m_output_file,
+ fprintf(locked_stream.GetFile().GetStream(),
"%s"
"%s"
"%s",
@@ -574,10 +581,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_output_stream_sp->GetMutex().unlock();
int read_count =
m_input_connection.Read(&ch, 1, std::nullopt, status, nullptr);
- m_output_mutex.lock();
+ m_output_stream_sp->GetMutex().lock();
if (m_editor_status == EditorStatus::Interrupted) {
while (read_count > 0 && status == lldb::eConnectionStatusSuccess)
read_count =
@@ -700,12 +707,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 +728,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 +776,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 +795,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 +841,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 +1045,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 +1065,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 +1085,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 +1198,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 +1218,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 +1253,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 +1494,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 +1573,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 +1584,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 +1599,7 @@ 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);
+ LockedStreamFile locked_stream = m_output_stream_sp->Lock();
lldbassert(m_editor_status != EditorStatus::Editing);
if (m_editor_status == EditorStatus::Interrupted) {
@@ -1598,7 +1619,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(locked_stream.GetFile().GetStream(), "\n");
m_editor_status = EditorStatus::EndOfInput;
} else {
m_history_sp->Enter(input);
@@ -1623,7 +1644,8 @@ 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);
+ LockedStreamFile locked_stream = m_output_stream_sp->Lock();
+
// Begin the line editing loop
DisplayInput();
SetCurrentLine(0);
@@ -1652,15 +1674,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..ce13611e949f3 100644
--- a/lldb/source/Interpreter/ScriptInterpreter.cpp
+++ b/lldb/source/Interpreter/ScriptInterpreter.cpp
@@ -206,7 +206,7 @@ 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_error_file_sp(m_output_file_sp),
m_communication("lldb.ScriptInterpreterIORedirect.comm"),
m_disconnect(false) {}
@@ -240,7 +240,8 @@ 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, true));
m_error_file_sp = m_output_file_sp;
if (outfile_handle)
::setbuf(outfile_handle, nullptr);
@@ -257,9 +258,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 +274,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..96be7931c54eb 100644
--- a/lldb/unittests/Editline/EditlineTest.cpp
+++ b/lldb/unittests/Editline/EditlineTest.cpp
@@ -25,6 +25,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 +116,15 @@ EditlineAdapter::EditlineAdapter()
if (*_el_secondary_file == nullptr)
return;
+ lldb::LockableStreamFileSP output_stream_sp =
+ std::make_shared<LockableStreamFile>(*_el_secondary_file, false);
+ lldb::LockableStreamFileSP error_stream_sp =
+ std::make_shared<LockableStreamFile>(*_el_secondary_file, false);
+
// 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.
>From 979abb70d4be927324d551043fe06c2492583382 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jonas at devlieghere.com>
Date: Fri, 14 Feb 2025 13:25:07 -0800
Subject: [PATCH 3/4] Tie stdout and stderr together
---
lldb/include/lldb/Core/Debugger.h | 1 +
lldb/include/lldb/Host/File.h | 5 ++++
lldb/include/lldb/Host/StreamFile.h | 23 +++++++++++--------
.../lldb/Interpreter/ScriptInterpreter.h | 1 +
lldb/source/Core/Debugger.cpp | 22 +++++++++++-------
lldb/source/Interpreter/ScriptInterpreter.cpp | 6 +++--
lldb/unittests/Editline/EditlineTest.cpp | 7 ++++--
7 files changed, 44 insertions(+), 21 deletions(-)
diff --git a/lldb/include/lldb/Core/Debugger.h b/lldb/include/lldb/Core/Debugger.h
index 4c08a1315cdcc..bbb06cb9c504d 100644
--- a/lldb/include/lldb/Core/Debugger.h
+++ b/lldb/include/lldb/Core/Debugger.h
@@ -694,6 +694,7 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
lldb::FileSP m_input_file_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/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 9df98a406a458..82d4136e723cd 100644
--- a/lldb/include/lldb/Host/StreamFile.h
+++ b/lldb/include/lldb/Host/StreamFile.h
@@ -18,6 +18,7 @@
#include <cstdint>
#include <cstdio>
#include <memory>
+#include <mutex>
namespace lldb_private {
@@ -70,13 +71,17 @@ class LockedStreamFile : public StreamFile {
class LockableStreamFile {
public:
- LockableStreamFile(std::shared_ptr<StreamFile> stream_file_sp)
- : m_file_sp(stream_file_sp->GetFileSP()) {}
- LockableStreamFile(StreamFile &stream_file)
- : m_file_sp(stream_file.GetFileSP()) {}
- LockableStreamFile(FILE *fh, bool transfer_ownership)
- : m_file_sp(std::make_shared<NativeFile>(fh, transfer_ownership)) {}
- LockableStreamFile(std::shared_ptr<File> file_sp) : m_file_sp(file_sp) {}
+ 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); }
@@ -87,11 +92,11 @@ class LockableStreamFile {
std::shared_ptr<File> GetUnlockedFileSP() { return m_file_sp; }
/// @}
- std::recursive_mutex &GetMutex() { return m_mutex; }
+ Mutex &GetMutex() { return m_mutex; }
protected:
std::shared_ptr<File> m_file_sp;
- std::recursive_mutex m_mutex;
+ Mutex &m_mutex;
private:
LockableStreamFile(const LockableStreamFile &) = delete;
diff --git a/lldb/include/lldb/Interpreter/ScriptInterpreter.h b/lldb/include/lldb/Interpreter/ScriptInterpreter.h
index 8ae9dc0b72019..c5aa19959aa61 100644
--- a/lldb/include/lldb/Interpreter/ScriptInterpreter.h
+++ b/lldb/include/lldb/Interpreter/ScriptInterpreter.h
@@ -134,6 +134,7 @@ class ScriptInterpreterIORedirect {
lldb::FileSP m_input_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;
};
diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp
index f18132a685030..7d668177f0573 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<LockableStreamFile>(stdout, false)),
- m_error_stream_sp(std::make_shared<LockableStreamFile>(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<LockableStreamFile>(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<LockableStreamFile>(file_sp);
+ m_error_stream_sp =
+ std::make_shared<LockableStreamFile>(file_sp, m_output_mutex);
}
void Debugger::SaveInputTerminalState() {
@@ -1244,7 +1248,7 @@ void Debugger::AdoptTopIOHandlerFilesIfInvalid(FileSP &in,
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->GetUnlockedFile().IsValid()) {
@@ -1254,7 +1258,8 @@ void Debugger::AdoptTopIOHandlerFilesIfInvalid(FileSP &in,
out = GetOutputStreamSP();
// If there is nothing, use stdout
if (!out)
- out = std::make_shared<LockableStreamFile>(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->GetUnlockedFile().IsValid()) {
@@ -1264,7 +1269,8 @@ void Debugger::AdoptTopIOHandlerFilesIfInvalid(FileSP &in,
err = GetErrorStreamSP();
// If there is nothing, use stderr
if (!err)
- err = std::make_shared<LockableStreamFile>(stderr, false);
+ err = std::make_shared<LockableStreamFile>(stderr, NativeFile::Unowned,
+ m_output_mutex);
}
}
diff --git a/lldb/source/Interpreter/ScriptInterpreter.cpp b/lldb/source/Interpreter/ScriptInterpreter.cpp
index ce13611e949f3..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<LockableStreamFile>(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) {}
@@ -241,7 +242,8 @@ ScriptInterpreterIORedirect::ScriptInterpreterIORedirect(
FILE *outfile_handle = fdopen(pipe.ReleaseWriteFileDescriptor(), "w");
m_output_file_sp = std::make_shared<LockableStreamFile>(
- std::make_shared<StreamFile>(outfile_handle, true));
+ 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);
diff --git a/lldb/unittests/Editline/EditlineTest.cpp b/lldb/unittests/Editline/EditlineTest.cpp
index 96be7931c54eb..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
@@ -117,9 +118,11 @@ EditlineAdapter::EditlineAdapter()
return;
lldb::LockableStreamFileSP output_stream_sp =
- std::make_shared<LockableStreamFile>(*_el_secondary_file, false);
+ std::make_shared<LockableStreamFile>(*_el_secondary_file,
+ NativeFile::Unowned, output_mutex);
lldb::LockableStreamFileSP error_stream_sp =
- std::make_shared<LockableStreamFile>(*_el_secondary_file, false);
+ std::make_shared<LockableStreamFile>(*_el_secondary_file,
+ NativeFile::Unowned, output_mutex);
// Create an Editline instance.
_editline_sp.reset(new lldb_private::Editline(
>From 4c7990f8e2424a6dbb9954df071f4fc91c93d067 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jonas at devlieghere.com>
Date: Mon, 17 Feb 2025 11:29:07 -0800
Subject: [PATCH 4/4] Use std::optional<LockedStream> to avoid exposing mutex
---
lldb/include/lldb/Host/Editline.h | 3 +++
lldb/include/lldb/Host/StreamFile.h | 9 +++++----
lldb/source/Host/common/Editline.cpp | 30 +++++++++++++++++++++-------
3 files changed, 31 insertions(+), 11 deletions(-)
diff --git a/lldb/include/lldb/Host/Editline.h b/lldb/include/lldb/Host/Editline.h
index ac3bef0e26c7d..8964d37be8823 100644
--- a/lldb/include/lldb/Host/Editline.h
+++ b/lldb/include/lldb/Host/Editline.h
@@ -397,6 +397,9 @@ class Editline {
FILE *m_input_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;
diff --git a/lldb/include/lldb/Host/StreamFile.h b/lldb/include/lldb/Host/StreamFile.h
index 82d4136e723cd..e37661a9938c0 100644
--- a/lldb/include/lldb/Host/StreamFile.h
+++ b/lldb/include/lldb/Host/StreamFile.h
@@ -60,13 +60,16 @@ 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_guard(mutex) {}
+ : StreamFile(file), m_lock(mutex) {}
friend class LockableStreamFile;
- std::lock_guard<std::recursive_mutex> m_guard;
+ std::unique_lock<std::recursive_mutex> m_lock;
};
class LockableStreamFile {
@@ -92,8 +95,6 @@ class LockableStreamFile {
std::shared_ptr<File> GetUnlockedFileSP() { return m_file_sp; }
/// @}
- Mutex &GetMutex() { return m_mutex; }
-
protected:
std::shared_ptr<File> m_file_sp;
Mutex &m_mutex;
diff --git a/lldb/source/Host/common/Editline.cpp b/lldb/source/Host/common/Editline.cpp
index 49480b4098723..5f7a8b0190a1d 100644
--- a/lldb/source/Host/common/Editline.cpp
+++ b/lldb/source/Host/common/Editline.cpp
@@ -79,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(' '))
@@ -541,9 +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) {
- LockedStreamFile locked_stream = m_output_stream_sp->Lock();
+ ScopedOptional<LockedStreamFile> scope(m_locked_output,
+ m_output_stream_sp->Lock());
MoveCursor(CursorLocation::EditingCursor, CursorLocation::EditingPrompt);
- fprintf(locked_stream.GetFile().GetStream(),
+ fprintf(m_locked_output->GetFile().GetStream(),
"%s"
"%s"
"%s",
@@ -581,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_stream_sp->GetMutex().unlock();
+ m_locked_output.reset();
int read_count =
m_input_connection.Read(&ch, 1, std::nullopt, status, nullptr);
- m_output_stream_sp->GetMutex().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 =
@@ -1599,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(""));
- LockedStreamFile locked_stream = m_output_stream_sp->Lock();
+ ScopedOptional<LockedStreamFile> scope(m_locked_output,
+ m_output_stream_sp->Lock());
lldbassert(m_editor_status != EditorStatus::Editing);
if (m_editor_status == EditorStatus::Interrupted) {
@@ -1619,7 +1634,7 @@ bool Editline::GetLine(std::string &line, bool &interrupted) {
interrupted = m_editor_status == EditorStatus::Interrupted;
if (!interrupted) {
if (input == nullptr) {
- fprintf(locked_stream.GetFile().GetStream(), "\n");
+ fprintf(m_locked_output->GetFile().GetStream(), "\n");
m_editor_status = EditorStatus::EndOfInput;
} else {
m_history_sp->Enter(input);
@@ -1644,7 +1659,8 @@ bool Editline::GetLines(int first_line_number, StringList &lines,
m_input_lines = std::vector<EditLineStringType>();
m_input_lines.insert(m_input_lines.begin(), EditLineConstString(""));
- LockedStreamFile locked_stream = m_output_stream_sp->Lock();
+ ScopedOptional<LockedStreamFile> scope(m_locked_output,
+ m_output_stream_sp->Lock());
// Begin the line editing loop
DisplayInput();
More information about the lldb-commits
mailing list