Skip to content

rdar://82390061 #4136

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions lldb/include/lldb/Core/IOHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class Debugger;
namespace repro {
class DataRecorder;
}
}
} // namespace lldb_private

namespace curses {
class Application;
Expand Down Expand Up @@ -85,11 +85,11 @@ class IOHandler {

virtual void GotEOF() = 0;

virtual bool IsActive() { return m_active && !m_done; }
bool IsActive() { return m_active && !m_done; }

virtual void SetIsDone(bool b) { m_done = b; }
void SetIsDone(bool b) { m_done = b; }

virtual bool GetIsDone() { return m_done; }
bool GetIsDone() { return m_done; }

Type GetType() const { return m_type; }

Expand Down Expand Up @@ -163,16 +163,16 @@ class IOHandler {

void WaitForPop();

virtual void PrintAsync(Stream *stream, const char *s, size_t len) {
stream->Write(s, len);
stream->Flush();
}
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;
repro::DataRecorder *m_data_recorder;
Predicate<bool> m_popped;
Flags m_flags;
Expand Down Expand Up @@ -415,7 +415,7 @@ class IOHandlerEditline : public IOHandler {

uint32_t GetCurrentLineIndex() const;

void PrintAsync(Stream *stream, const char *s, size_t len) override;
void PrintAsync(const char *s, size_t len, bool is_stdout) override;

private:
#if LLDB_ENABLE_LIBEDIT
Expand Down Expand Up @@ -558,7 +558,7 @@ class IOHandlerStack {
return m_repl_enabled;
}

void PrintAsync(Stream *stream, const char *s, size_t len);
bool PrintAsync(const char *s, size_t len, bool is_stdout);

protected:
void UpdateREPLIsActive() {
Expand Down
5 changes: 3 additions & 2 deletions lldb/include/lldb/Host/Editline.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,8 @@ using namespace line_editor;
class Editline {
public:
Editline(const char *editor_name, FILE *input_file, FILE *output_file,
FILE *error_file, bool color_prompts);
FILE *error_file, std::recursive_mutex &output_mutex,
bool color_prompts);

~Editline();

Expand Down Expand Up @@ -402,7 +403,7 @@ class Editline {
std::string m_suggestion_ansi_suffix;

std::size_t m_previous_autosuggestion_size = 0;
std::mutex m_output_mutex;
std::recursive_mutex &m_output_mutex;
};
}

Expand Down
3 changes: 2 additions & 1 deletion lldb/include/lldb/Interpreter/CommandInterpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -654,7 +654,8 @@ class CommandInterpreter : public Broadcaster,
CommandObject::CommandMap &command_map);

// An interruptible wrapper around the stream output
void PrintCommandOutput(Stream &stream, llvm::StringRef str);
void PrintCommandOutput(IOHandler &io_handler, llvm::StringRef str,
bool is_stdout);

bool EchoCommandNonInteractive(llvm::StringRef line,
const Flags &io_handler_flags) const;
Expand Down
9 changes: 6 additions & 3 deletions lldb/source/Core/Debugger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1069,9 +1069,12 @@ bool Debugger::CheckTopIOHandlerTypes(IOHandler::Type top_type,
}

void Debugger::PrintAsync(const char *s, size_t len, bool is_stdout) {
lldb_private::StreamFile &stream =
is_stdout ? GetOutputStream() : GetErrorStream();
m_io_handler_stack.PrintAsync(&stream, s, len);
bool printed = m_io_handler_stack.PrintAsync(s, len, is_stdout);
if (!printed) {
lldb::StreamFileSP stream =
is_stdout ? m_output_stream_sp : m_error_stream_sp;
stream->Write(s, len);
}
}

ConstString Debugger::GetTopIOHandlerControlSequence(char ch) {
Expand Down
42 changes: 24 additions & 18 deletions lldb/source/Core/IOHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,14 +122,19 @@ void IOHandler::SetPopped(bool b) { m_popped.SetValue(b, eBroadcastOnChange); }

void IOHandler::WaitForPop() { m_popped.WaitForValueEqualTo(true); }

void IOHandlerStack::PrintAsync(Stream *stream, const char *s, size_t len) {
if (stream) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
if (m_top)
m_top->PrintAsync(stream, s, len);
else
stream->Write(s, len);
}
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();
}

bool IOHandlerStack::PrintAsync(const char *s, size_t len, bool is_stdout) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
if (!m_top)
return false;
m_top->PrintAsync(s, len, is_stdout);
return true;
}

IOHandlerConfirm::IOHandlerConfirm(Debugger &debugger, llvm::StringRef prompt,
Expand Down Expand Up @@ -262,9 +267,9 @@ IOHandlerEditline::IOHandlerEditline(
m_input_sp && m_input_sp->GetIsRealTerminal();

if (use_editline) {
m_editline_up = std::make_unique<Editline>(editline_name, GetInputFILE(),
GetOutputFILE(), GetErrorFILE(),
m_color_prompts);
m_editline_up = std::make_unique<Editline>(
editline_name, GetInputFILE(), GetOutputFILE(), GetErrorFILE(),
GetOutputMutex(), m_color_prompts);
m_editline_up->SetIsInputCompleteCallback(
[this](Editline *editline, StringList &lines) {
return this->IsInputCompleteCallback(editline, lines);
Expand Down Expand Up @@ -615,11 +620,13 @@ void IOHandlerEditline::GotEOF() {
#endif
}

void IOHandlerEditline::PrintAsync(Stream *stream, const char *s, size_t len) {
void IOHandlerEditline::PrintAsync(const char *s, size_t len, bool is_stdout) {
#if LLDB_ENABLE_LIBEDIT
if (m_editline_up)
m_editline_up->PrintAsync(stream, s, len);
else
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);
} else
#endif
{
#ifdef _WIN32
Expand All @@ -636,11 +643,10 @@ void IOHandlerEditline::PrintAsync(Stream *stream, const char *s, size_t len) {
SetConsoleCursorPosition(console_handle, coord);
}
#endif
IOHandler::PrintAsync(stream, s, len);
IOHandler::PrintAsync(s, len, is_stdout);
#ifdef _WIN32
if (prompt)
IOHandler::PrintAsync(GetOutputStreamFileSP().get(), prompt,
strlen(prompt));
IOHandler::PrintAsync(prompt, strlen(prompt), is_stdout);
#endif
}
}
24 changes: 14 additions & 10 deletions lldb/source/Host/common/Editline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1376,10 +1376,12 @@ Editline *Editline::InstanceFor(EditLine *editline) {
}

Editline::Editline(const char *editline_name, FILE *input_file,
FILE *output_file, FILE *error_file, bool color_prompts)
FILE *output_file, FILE *error_file,
std::recursive_mutex &output_mutex, bool color_prompts)
: m_editor_status(EditorStatus::Complete), m_color_prompts(color_prompts),
m_input_file(input_file), m_output_file(output_file),
m_error_file(error_file), m_input_connection(fileno(input_file), false) {
m_error_file(error_file), m_input_connection(fileno(input_file), false),
m_output_mutex(output_mutex) {
// Get a shared history instance
m_editor_name = (editline_name == nullptr) ? "lldb-tmp" : editline_name;
m_history_sp = EditlineHistory::GetHistory(m_editor_name);
Expand All @@ -1388,20 +1390,22 @@ Editline::Editline(const char *editline_name, FILE *input_file,
if (m_output_file) {
const int term_fd = fileno(m_output_file);
if (term_fd != -1) {
static std::mutex *g_init_terminal_fds_mutex_ptr = nullptr;
static std::recursive_mutex *g_init_terminal_fds_mutex_ptr = nullptr;
static std::set<int> *g_init_terminal_fds_ptr = nullptr;
static llvm::once_flag g_once_flag;
llvm::call_once(g_once_flag, [&]() {
g_init_terminal_fds_mutex_ptr =
new std::mutex(); // NOTE: Leak to avoid C++ destructor chain issues
new std::recursive_mutex(); // NOTE: Leak to avoid C++ destructor
// chain issues
g_init_terminal_fds_ptr = new std::set<int>(); // NOTE: Leak to avoid
// C++ destructor chain
// issues
});

// We must make sure to initialize the terminal a given file descriptor
// only once. If we do this multiple times, we start leaking memory.
std::lock_guard<std::mutex> guard(*g_init_terminal_fds_mutex_ptr);
std::lock_guard<std::recursive_mutex> guard(
*g_init_terminal_fds_mutex_ptr);
if (g_init_terminal_fds_ptr->find(term_fd) ==
g_init_terminal_fds_ptr->end()) {
g_init_terminal_fds_ptr->insert(term_fd);
Expand Down Expand Up @@ -1473,7 +1477,7 @@ uint32_t Editline::GetCurrentLine() { return m_current_line_index; }

bool Editline::Interrupt() {
bool result = true;
std::lock_guard<std::mutex> guard(m_output_mutex);
std::lock_guard<std::recursive_mutex> guard(m_output_mutex);
if (m_editor_status == EditorStatus::Editing) {
fprintf(m_output_file, "^C\n");
result = m_input_connection.InterruptRead();
Expand All @@ -1484,7 +1488,7 @@ bool Editline::Interrupt() {

bool Editline::Cancel() {
bool result = true;
std::lock_guard<std::mutex> guard(m_output_mutex);
std::lock_guard<std::recursive_mutex> guard(m_output_mutex);
if (m_editor_status == EditorStatus::Editing) {
MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockStart);
fprintf(m_output_file, ANSI_CLEAR_BELOW);
Expand All @@ -1499,7 +1503,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::mutex> guard(m_output_mutex);
std::lock_guard<std::recursive_mutex> guard(m_output_mutex);

lldbassert(m_editor_status != EditorStatus::Editing);
if (m_editor_status == EditorStatus::Interrupted) {
Expand Down Expand Up @@ -1544,7 +1548,7 @@ 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::mutex> guard(m_output_mutex);
std::lock_guard<std::recursive_mutex> guard(m_output_mutex);
// Begin the line editing loop
DisplayInput();
SetCurrentLine(0);
Expand Down Expand Up @@ -1574,7 +1578,7 @@ bool Editline::GetLines(int first_line_number, StringList &lines,
}

void Editline::PrintAsync(Stream *stream, const char *s, size_t len) {
std::lock_guard<std::mutex> guard(m_output_mutex);
std::lock_guard<std::recursive_mutex> guard(m_output_mutex);
if (m_editor_status == EditorStatus::Editing) {
MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockStart);
fprintf(m_output_file, ANSI_CLEAR_BELOW);
Expand Down
29 changes: 20 additions & 9 deletions lldb/source/Interpreter/CommandInterpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2969,8 +2969,12 @@ bool CommandInterpreter::WasInterrupted() const {
return was_interrupted;
}

void CommandInterpreter::PrintCommandOutput(Stream &stream,
llvm::StringRef str) {
void CommandInterpreter::PrintCommandOutput(IOHandler &io_handler,
llvm::StringRef str,
bool is_stdout) {

lldb::StreamFileSP stream = is_stdout ? io_handler.GetOutputStreamFileSP()
: io_handler.GetErrorStreamFileSP();
// Split the output into lines and poll for interrupt requests
const char *data = str.data();
size_t size = str.size();
Expand All @@ -2983,14 +2987,19 @@ void CommandInterpreter::PrintCommandOutput(Stream &stream,
break;
}
}
chunk_size = stream.Write(data, chunk_size);
{
std::lock_guard<std::recursive_mutex> guard(io_handler.GetOutputMutex());
chunk_size = stream->Write(data, chunk_size);
}
lldbassert(size >= chunk_size);
data += chunk_size;
size -= chunk_size;
}
if (size > 0) {
stream.Printf("\n... Interrupted.\n");
}

std::lock_guard<std::recursive_mutex> guard(io_handler.GetOutputMutex());
if (size > 0)
stream->Printf("\n... Interrupted.\n");
stream->Flush();
}

bool CommandInterpreter::EchoCommandNonInteractive(
Expand Down Expand Up @@ -3026,9 +3035,11 @@ void CommandInterpreter::IOHandlerInputComplete(IOHandler &io_handler,
// When using a non-interactive file handle (like when sourcing commands
// from a file) we need to echo the command out so we don't just see the
// command output and no command...
if (EchoCommandNonInteractive(line, io_handler.GetFlags()))
if (EchoCommandNonInteractive(line, io_handler.GetFlags())) {
std::lock_guard<std::recursive_mutex> guard(io_handler.GetOutputMutex());
io_handler.GetOutputStreamFileSP()->Printf(
"%s%s\n", io_handler.GetPrompt(), line.c_str());
}
}

StartHandlingCommand();
Expand All @@ -3050,13 +3061,13 @@ void CommandInterpreter::IOHandlerInputComplete(IOHandler &io_handler,

if (!result.GetImmediateOutputStream()) {
llvm::StringRef output = result.GetOutputData();
PrintCommandOutput(*io_handler.GetOutputStreamFileSP(), output);
PrintCommandOutput(io_handler, output, true);
}

// Now emit the command error text from the command we just executed
if (!result.GetImmediateErrorStream()) {
llvm::StringRef error = result.GetErrorData();
PrintCommandOutput(*io_handler.GetErrorStreamFileSP(), error);
PrintCommandOutput(io_handler, error, false);
}
}

Expand Down
3 changes: 2 additions & 1 deletion lldb/unittests/Editline/EditlineTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ class EditlineAdapter {
bool IsInputComplete(lldb_private::Editline *editline,
lldb_private::StringList &lines);

std::recursive_mutex output_mutex;
std::unique_ptr<lldb_private::Editline> _editline_sp;

PseudoTerminal _pty;
Expand Down Expand Up @@ -118,7 +119,7 @@ EditlineAdapter::EditlineAdapter()
// Create an Editline instance.
_editline_sp.reset(new lldb_private::Editline(
"gtest editor", *_el_secondary_file, *_el_secondary_file,
*_el_secondary_file, false));
*_el_secondary_file, output_mutex, false));
_editline_sp->SetPrompt("> ");

// Hookup our input complete callback.
Expand Down