Skip to content

Commit 387a378

Browse files
authored
Merge pull request #4136 from apple/jdevlieghere/rdar/82390061
rdar://82390061
2 parents 78d22a8 + 5418f63 commit 387a378

File tree

8 files changed

+81
-54
lines changed

8 files changed

+81
-54
lines changed

lldb/include/lldb/Core/IOHandler.h

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class Debugger;
3434
namespace repro {
3535
class DataRecorder;
3636
}
37-
}
37+
} // namespace lldb_private
3838

3939
namespace curses {
4040
class Application;
@@ -85,11 +85,11 @@ class IOHandler {
8585

8686
virtual void GotEOF() = 0;
8787

88-
virtual bool IsActive() { return m_active && !m_done; }
88+
bool IsActive() { return m_active && !m_done; }
8989

90-
virtual void SetIsDone(bool b) { m_done = b; }
90+
void SetIsDone(bool b) { m_done = b; }
9191

92-
virtual bool GetIsDone() { return m_done; }
92+
bool GetIsDone() { return m_done; }
9393

9494
Type GetType() const { return m_type; }
9595

@@ -163,16 +163,16 @@ class IOHandler {
163163

164164
void WaitForPop();
165165

166-
virtual void PrintAsync(Stream *stream, const char *s, size_t len) {
167-
stream->Write(s, len);
168-
stream->Flush();
169-
}
166+
virtual void PrintAsync(const char *s, size_t len, bool is_stdout);
167+
168+
std::recursive_mutex &GetOutputMutex() { return m_output_mutex; }
170169

171170
protected:
172171
Debugger &m_debugger;
173172
lldb::FileSP m_input_sp;
174173
lldb::StreamFileSP m_output_sp;
175174
lldb::StreamFileSP m_error_sp;
175+
std::recursive_mutex m_output_mutex;
176176
repro::DataRecorder *m_data_recorder;
177177
Predicate<bool> m_popped;
178178
Flags m_flags;
@@ -415,7 +415,7 @@ class IOHandlerEditline : public IOHandler {
415415

416416
uint32_t GetCurrentLineIndex() const;
417417

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

420420
private:
421421
#if LLDB_ENABLE_LIBEDIT
@@ -558,7 +558,7 @@ class IOHandlerStack {
558558
return m_repl_enabled;
559559
}
560560

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

563563
protected:
564564
void UpdateREPLIsActive() {

lldb/include/lldb/Host/Editline.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,8 @@ using namespace line_editor;
154154
class Editline {
155155
public:
156156
Editline(const char *editor_name, FILE *input_file, FILE *output_file,
157-
FILE *error_file, bool color_prompts);
157+
FILE *error_file, std::recursive_mutex &output_mutex,
158+
bool color_prompts);
158159

159160
~Editline();
160161

@@ -402,7 +403,7 @@ class Editline {
402403
std::string m_suggestion_ansi_suffix;
403404

404405
std::size_t m_previous_autosuggestion_size = 0;
405-
std::mutex m_output_mutex;
406+
std::recursive_mutex &m_output_mutex;
406407
};
407408
}
408409

lldb/include/lldb/Interpreter/CommandInterpreter.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -654,7 +654,8 @@ class CommandInterpreter : public Broadcaster,
654654
CommandObject::CommandMap &command_map);
655655

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

659660
bool EchoCommandNonInteractive(llvm::StringRef line,
660661
const Flags &io_handler_flags) const;

lldb/source/Core/Debugger.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1069,9 +1069,12 @@ bool Debugger::CheckTopIOHandlerTypes(IOHandler::Type top_type,
10691069
}
10701070

10711071
void Debugger::PrintAsync(const char *s, size_t len, bool is_stdout) {
1072-
lldb_private::StreamFile &stream =
1073-
is_stdout ? GetOutputStream() : GetErrorStream();
1074-
m_io_handler_stack.PrintAsync(&stream, s, len);
1072+
bool printed = m_io_handler_stack.PrintAsync(s, len, is_stdout);
1073+
if (!printed) {
1074+
lldb::StreamFileSP stream =
1075+
is_stdout ? m_output_stream_sp : m_error_stream_sp;
1076+
stream->Write(s, len);
1077+
}
10751078
}
10761079

10771080
ConstString Debugger::GetTopIOHandlerControlSequence(char ch) {

lldb/source/Core/IOHandler.cpp

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -122,14 +122,19 @@ void IOHandler::SetPopped(bool b) { m_popped.SetValue(b, eBroadcastOnChange); }
122122

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

125-
void IOHandlerStack::PrintAsync(Stream *stream, const char *s, size_t len) {
126-
if (stream) {
127-
std::lock_guard<std::recursive_mutex> guard(m_mutex);
128-
if (m_top)
129-
m_top->PrintAsync(stream, s, len);
130-
else
131-
stream->Write(s, len);
132-
}
125+
void IOHandler::PrintAsync(const char *s, size_t len, bool is_stdout) {
126+
std::lock_guard<std::recursive_mutex> guard(m_output_mutex);
127+
lldb::StreamFileSP stream = is_stdout ? m_output_sp : m_error_sp;
128+
stream->Write(s, len);
129+
stream->Flush();
130+
}
131+
132+
bool IOHandlerStack::PrintAsync(const char *s, size_t len, bool is_stdout) {
133+
std::lock_guard<std::recursive_mutex> guard(m_mutex);
134+
if (!m_top)
135+
return false;
136+
m_top->PrintAsync(s, len, is_stdout);
137+
return true;
133138
}
134139

135140
IOHandlerConfirm::IOHandlerConfirm(Debugger &debugger, llvm::StringRef prompt,
@@ -262,9 +267,9 @@ IOHandlerEditline::IOHandlerEditline(
262267
m_input_sp && m_input_sp->GetIsRealTerminal();
263268

264269
if (use_editline) {
265-
m_editline_up = std::make_unique<Editline>(editline_name, GetInputFILE(),
266-
GetOutputFILE(), GetErrorFILE(),
267-
m_color_prompts);
270+
m_editline_up = std::make_unique<Editline>(
271+
editline_name, GetInputFILE(), GetOutputFILE(), GetErrorFILE(),
272+
GetOutputMutex(), m_color_prompts);
268273
m_editline_up->SetIsInputCompleteCallback(
269274
[this](Editline *editline, StringList &lines) {
270275
return this->IsInputCompleteCallback(editline, lines);
@@ -615,11 +620,13 @@ void IOHandlerEditline::GotEOF() {
615620
#endif
616621
}
617622

618-
void IOHandlerEditline::PrintAsync(Stream *stream, const char *s, size_t len) {
623+
void IOHandlerEditline::PrintAsync(const char *s, size_t len, bool is_stdout) {
619624
#if LLDB_ENABLE_LIBEDIT
620-
if (m_editline_up)
621-
m_editline_up->PrintAsync(stream, s, len);
622-
else
625+
if (m_editline_up) {
626+
std::lock_guard<std::recursive_mutex> guard(m_output_mutex);
627+
lldb::StreamFileSP stream = is_stdout ? m_output_sp : m_error_sp;
628+
m_editline_up->PrintAsync(stream.get(), s, len);
629+
} else
623630
#endif
624631
{
625632
#ifdef _WIN32
@@ -636,11 +643,10 @@ void IOHandlerEditline::PrintAsync(Stream *stream, const char *s, size_t len) {
636643
SetConsoleCursorPosition(console_handle, coord);
637644
}
638645
#endif
639-
IOHandler::PrintAsync(stream, s, len);
646+
IOHandler::PrintAsync(s, len, is_stdout);
640647
#ifdef _WIN32
641648
if (prompt)
642-
IOHandler::PrintAsync(GetOutputStreamFileSP().get(), prompt,
643-
strlen(prompt));
649+
IOHandler::PrintAsync(prompt, strlen(prompt), is_stdout);
644650
#endif
645651
}
646652
}

lldb/source/Host/common/Editline.cpp

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1376,10 +1376,12 @@ Editline *Editline::InstanceFor(EditLine *editline) {
13761376
}
13771377

13781378
Editline::Editline(const char *editline_name, FILE *input_file,
1379-
FILE *output_file, FILE *error_file, bool color_prompts)
1379+
FILE *output_file, FILE *error_file,
1380+
std::recursive_mutex &output_mutex, bool color_prompts)
13801381
: m_editor_status(EditorStatus::Complete), m_color_prompts(color_prompts),
13811382
m_input_file(input_file), m_output_file(output_file),
1382-
m_error_file(error_file), m_input_connection(fileno(input_file), false) {
1383+
m_error_file(error_file), m_input_connection(fileno(input_file), false),
1384+
m_output_mutex(output_mutex) {
13831385
// Get a shared history instance
13841386
m_editor_name = (editline_name == nullptr) ? "lldb-tmp" : editline_name;
13851387
m_history_sp = EditlineHistory::GetHistory(m_editor_name);
@@ -1388,20 +1390,22 @@ Editline::Editline(const char *editline_name, FILE *input_file,
13881390
if (m_output_file) {
13891391
const int term_fd = fileno(m_output_file);
13901392
if (term_fd != -1) {
1391-
static std::mutex *g_init_terminal_fds_mutex_ptr = nullptr;
1393+
static std::recursive_mutex *g_init_terminal_fds_mutex_ptr = nullptr;
13921394
static std::set<int> *g_init_terminal_fds_ptr = nullptr;
13931395
static llvm::once_flag g_once_flag;
13941396
llvm::call_once(g_once_flag, [&]() {
13951397
g_init_terminal_fds_mutex_ptr =
1396-
new std::mutex(); // NOTE: Leak to avoid C++ destructor chain issues
1398+
new std::recursive_mutex(); // NOTE: Leak to avoid C++ destructor
1399+
// chain issues
13971400
g_init_terminal_fds_ptr = new std::set<int>(); // NOTE: Leak to avoid
13981401
// C++ destructor chain
13991402
// issues
14001403
});
14011404

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

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

14851489
bool Editline::Cancel() {
14861490
bool result = true;
1487-
std::lock_guard<std::mutex> guard(m_output_mutex);
1491+
std::lock_guard<std::recursive_mutex> guard(m_output_mutex);
14881492
if (m_editor_status == EditorStatus::Editing) {
14891493
MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockStart);
14901494
fprintf(m_output_file, ANSI_CLEAR_BELOW);
@@ -1499,7 +1503,7 @@ bool Editline::GetLine(std::string &line, bool &interrupted) {
14991503
m_input_lines = std::vector<EditLineStringType>();
15001504
m_input_lines.insert(m_input_lines.begin(), EditLineConstString(""));
15011505

1502-
std::lock_guard<std::mutex> guard(m_output_mutex);
1506+
std::lock_guard<std::recursive_mutex> guard(m_output_mutex);
15031507

15041508
lldbassert(m_editor_status != EditorStatus::Editing);
15051509
if (m_editor_status == EditorStatus::Interrupted) {
@@ -1544,7 +1548,7 @@ bool Editline::GetLines(int first_line_number, StringList &lines,
15441548
m_input_lines = std::vector<EditLineStringType>();
15451549
m_input_lines.insert(m_input_lines.begin(), EditLineConstString(""));
15461550

1547-
std::lock_guard<std::mutex> guard(m_output_mutex);
1551+
std::lock_guard<std::recursive_mutex> guard(m_output_mutex);
15481552
// Begin the line editing loop
15491553
DisplayInput();
15501554
SetCurrentLine(0);
@@ -1574,7 +1578,7 @@ bool Editline::GetLines(int first_line_number, StringList &lines,
15741578
}
15751579

15761580
void Editline::PrintAsync(Stream *stream, const char *s, size_t len) {
1577-
std::lock_guard<std::mutex> guard(m_output_mutex);
1581+
std::lock_guard<std::recursive_mutex> guard(m_output_mutex);
15781582
if (m_editor_status == EditorStatus::Editing) {
15791583
MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockStart);
15801584
fprintf(m_output_file, ANSI_CLEAR_BELOW);

lldb/source/Interpreter/CommandInterpreter.cpp

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2969,8 +2969,12 @@ bool CommandInterpreter::WasInterrupted() const {
29692969
return was_interrupted;
29702970
}
29712971

2972-
void CommandInterpreter::PrintCommandOutput(Stream &stream,
2973-
llvm::StringRef str) {
2972+
void CommandInterpreter::PrintCommandOutput(IOHandler &io_handler,
2973+
llvm::StringRef str,
2974+
bool is_stdout) {
2975+
2976+
lldb::StreamFileSP stream = is_stdout ? io_handler.GetOutputStreamFileSP()
2977+
: io_handler.GetErrorStreamFileSP();
29742978
// Split the output into lines and poll for interrupt requests
29752979
const char *data = str.data();
29762980
size_t size = str.size();
@@ -2983,14 +2987,19 @@ void CommandInterpreter::PrintCommandOutput(Stream &stream,
29832987
break;
29842988
}
29852989
}
2986-
chunk_size = stream.Write(data, chunk_size);
2990+
{
2991+
std::lock_guard<std::recursive_mutex> guard(io_handler.GetOutputMutex());
2992+
chunk_size = stream->Write(data, chunk_size);
2993+
}
29872994
lldbassert(size >= chunk_size);
29882995
data += chunk_size;
29892996
size -= chunk_size;
29902997
}
2991-
if (size > 0) {
2992-
stream.Printf("\n... Interrupted.\n");
2993-
}
2998+
2999+
std::lock_guard<std::recursive_mutex> guard(io_handler.GetOutputMutex());
3000+
if (size > 0)
3001+
stream->Printf("\n... Interrupted.\n");
3002+
stream->Flush();
29943003
}
29953004

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

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

30513062
if (!result.GetImmediateOutputStream()) {
30523063
llvm::StringRef output = result.GetOutputData();
3053-
PrintCommandOutput(*io_handler.GetOutputStreamFileSP(), output);
3064+
PrintCommandOutput(io_handler, output, true);
30543065
}
30553066

30563067
// Now emit the command error text from the command we just executed
30573068
if (!result.GetImmediateErrorStream()) {
30583069
llvm::StringRef error = result.GetErrorData();
3059-
PrintCommandOutput(*io_handler.GetErrorStreamFileSP(), error);
3070+
PrintCommandOutput(io_handler, error, false);
30603071
}
30613072
}
30623073

lldb/unittests/Editline/EditlineTest.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ class EditlineAdapter {
8484
bool IsInputComplete(lldb_private::Editline *editline,
8585
lldb_private::StringList &lines);
8686

87+
std::recursive_mutex output_mutex;
8788
std::unique_ptr<lldb_private::Editline> _editline_sp;
8889

8990
PseudoTerminal _pty;
@@ -118,7 +119,7 @@ EditlineAdapter::EditlineAdapter()
118119
// Create an Editline instance.
119120
_editline_sp.reset(new lldb_private::Editline(
120121
"gtest editor", *_el_secondary_file, *_el_secondary_file,
121-
*_el_secondary_file, false));
122+
*_el_secondary_file, output_mutex, false));
122123
_editline_sp->SetPrompt("> ");
123124

124125
// Hookup our input complete callback.

0 commit comments

Comments
 (0)