Skip to content

Commit 55cc3a5

Browse files
committed
[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 d7b6704)
1 parent c77d202 commit 55cc3a5

28 files changed

+489
-370
lines changed

lldb/include/lldb/Core/Debugger.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -133,15 +133,15 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
133133

134134
lldb::FileSP GetInputFileSP() { return m_input_file_sp; }
135135

136-
lldb::StreamFileSP GetOutputStreamSP() { return m_output_stream_sp; }
136+
lldb::LockableStreamFileSP GetOutputStreamSP() { return m_output_stream_sp; }
137137

138-
lldb::StreamFileSP GetErrorStreamSP() { return m_error_stream_sp; }
138+
lldb::LockableStreamFileSP GetErrorStreamSP() { return m_error_stream_sp; }
139139

140140
File &GetInputFile() { return *m_input_file_sp; }
141141

142-
File &GetOutputFile() { return m_output_stream_sp->GetFile(); }
142+
File &GetOutputFile() { return m_output_stream_sp->GetUnlockedFile(); }
143143

144-
File &GetErrorFile() { return m_error_stream_sp->GetFile(); }
144+
File &GetErrorFile() { return m_error_stream_sp->GetUnlockedFile(); }
145145

146146
repro::DataRecorder *GetInputRecorder();
147147

@@ -202,8 +202,8 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
202202
// If any of the streams are not set, set them to the in/out/err stream of
203203
// the top most input reader to ensure they at least have something
204204
void AdoptTopIOHandlerFilesIfInvalid(lldb::FileSP &in,
205-
lldb::StreamFileSP &out,
206-
lldb::StreamFileSP &err);
205+
lldb::LockableStreamFileSP &out,
206+
lldb::LockableStreamFileSP &err);
207207

208208
/// Run the given IO handler and return immediately.
209209
void RunIOHandlerAsync(const lldb::IOHandlerSP &reader_sp,
@@ -689,8 +689,8 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
689689

690690
// these should never be NULL
691691
lldb::FileSP m_input_file_sp;
692-
lldb::StreamFileSP m_output_stream_sp;
693-
lldb::StreamFileSP m_error_stream_sp;
692+
lldb::LockableStreamFileSP m_output_stream_sp;
693+
lldb::LockableStreamFileSP m_error_stream_sp;
694694

695695
/// Used for shadowing the input file when capturing a reproducer.
696696
repro::DataRecorder *m_input_recorder;

lldb/include/lldb/Core/IOHandler.h

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,9 @@ class IOHandler {
5858
IOHandler(Debugger &debugger, IOHandler::Type type);
5959

6060
IOHandler(Debugger &debugger, IOHandler::Type type,
61-
const lldb::FileSP &input_sp, const lldb::StreamFileSP &output_sp,
62-
const lldb::StreamFileSP &error_sp, uint32_t flags);
61+
const lldb::FileSP &input_sp,
62+
const lldb::LockableStreamFileSP &output_sp,
63+
const lldb::LockableStreamFileSP &error_sp, uint32_t flags);
6364

6465
virtual ~IOHandler();
6566

@@ -117,17 +118,11 @@ class IOHandler {
117118

118119
int GetErrorFD();
119120

120-
FILE *GetInputFILE();
121-
122-
FILE *GetOutputFILE();
123-
124-
FILE *GetErrorFILE();
125-
126121
lldb::FileSP GetInputFileSP();
127122

128-
lldb::StreamFileSP GetOutputStreamFileSP();
123+
lldb::LockableStreamFileSP GetOutputStreamFileSP();
129124

130-
lldb::StreamFileSP GetErrorStreamFileSP();
125+
lldb::LockableStreamFileSP GetErrorStreamFileSP();
131126

132127
Debugger &GetDebugger() { return m_debugger; }
133128

@@ -160,14 +155,11 @@ class IOHandler {
160155

161156
virtual void PrintAsync(const char *s, size_t len, bool is_stdout);
162157

163-
std::recursive_mutex &GetOutputMutex() { return m_output_mutex; }
164-
165158
protected:
166159
Debugger &m_debugger;
167160
lldb::FileSP m_input_sp;
168-
lldb::StreamFileSP m_output_sp;
169-
lldb::StreamFileSP m_error_sp;
170-
std::recursive_mutex m_output_mutex;
161+
lldb::LockableStreamFileSP m_output_sp;
162+
lldb::LockableStreamFileSP m_error_sp;
171163
Predicate<bool> m_popped;
172164
Flags m_flags;
173165
Type m_type;
@@ -335,8 +327,8 @@ class IOHandlerEditline : public IOHandler {
335327

336328
IOHandlerEditline(Debugger &debugger, IOHandler::Type type,
337329
const lldb::FileSP &input_sp,
338-
const lldb::StreamFileSP &output_sp,
339-
const lldb::StreamFileSP &error_sp, uint32_t flags,
330+
const lldb::LockableStreamFileSP &output_sp,
331+
const lldb::LockableStreamFileSP &error_sp, uint32_t flags,
340332
const char *editline_name, // Used for saving history files
341333
llvm::StringRef prompt, llvm::StringRef continuation_prompt,
342334
bool multi_line, bool color,
@@ -350,9 +342,10 @@ class IOHandlerEditline : public IOHandler {
350342
IOHandlerDelegate &) = delete;
351343

352344
IOHandlerEditline(Debugger &, IOHandler::Type, const lldb::FileSP &,
353-
const lldb::StreamFileSP &, const lldb::StreamFileSP &,
354-
uint32_t, const char *, const char *, const char *, bool,
355-
bool, uint32_t, IOHandlerDelegate &) = delete;
345+
const lldb::LockableStreamFileSP &,
346+
const lldb::LockableStreamFileSP &, uint32_t, const char *,
347+
const char *, const char *, bool, bool, uint32_t,
348+
IOHandlerDelegate &) = delete;
356349

357350
~IOHandlerEditline() override;
358351

lldb/include/lldb/Host/Editline.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include <sstream>
3535
#include <vector>
3636

37+
#include "lldb/Host/StreamFile.h"
3738
#include "lldb/lldb-private.h"
3839

3940
#if !defined(_WIN32) && !defined(__ANDROID__)
@@ -151,8 +152,9 @@ using namespace line_editor;
151152
/// facility. Both single- and multi-line editing are supported.
152153
class Editline {
153154
public:
154-
Editline(const char *editor_name, FILE *input_file, FILE *output_file,
155-
FILE *error_file, bool color, std::recursive_mutex &output_mutex);
155+
Editline(const char *editor_name, FILE *input_file,
156+
lldb::LockableStreamFileSP output_stream_sp,
157+
lldb::LockableStreamFileSP error_stream_sp, bool color);
156158

157159
~Editline();
158160

@@ -237,7 +239,8 @@ class Editline {
237239
/// Prompts for and reads a multi-line batch of user input.
238240
bool GetLines(int first_line_number, StringList &lines, bool &interrupted);
239241

240-
void PrintAsync(Stream *stream, const char *s, size_t len);
242+
void PrintAsync(lldb::LockableStreamFileSP stream_sp, const char *s,
243+
size_t len);
241244

242245
/// Convert the current input lines into a UTF8 StringList
243246
StringList GetInputAsStringList(int line_count = UINT32_MAX);
@@ -392,8 +395,8 @@ class Editline {
392395
volatile std::sig_atomic_t m_terminal_size_has_changed = 0;
393396
std::string m_editor_name;
394397
FILE *m_input_file;
395-
FILE *m_output_file;
396-
FILE *m_error_file;
398+
lldb::LockableStreamFileSP m_output_stream_sp;
399+
lldb::LockableStreamFileSP m_error_stream_sp;
397400
ConnectionFileDescriptor m_input_connection;
398401

399402
IsInputCompleteCallbackType m_is_input_complete_callback;
@@ -411,7 +414,6 @@ class Editline {
411414
std::string m_suggestion_ansi_suffix;
412415

413416
std::size_t m_previous_autosuggestion_size = 0;
414-
std::recursive_mutex &m_output_mutex;
415417
};
416418
}
417419

lldb/include/lldb/Host/StreamFile.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,11 @@
1313
#include "lldb/Utility/Stream.h"
1414
#include "lldb/lldb-defines.h"
1515
#include "lldb/lldb-enumerations.h"
16+
#include "lldb/lldb-forward.h"
1617

1718
#include <cstdint>
1819
#include <cstdio>
20+
#include <memory>
1921

2022
namespace lldb_private {
2123

@@ -52,6 +54,50 @@ class StreamFile : public Stream {
5254
const StreamFile &operator=(const StreamFile &) = delete;
5355
};
5456

57+
class LockableStreamFile;
58+
class LockedStreamFile : public StreamFile {
59+
public:
60+
~LockedStreamFile() { Flush(); }
61+
62+
private:
63+
LockedStreamFile(std::shared_ptr<File> file, std::recursive_mutex &mutex)
64+
: StreamFile(file), m_guard(mutex) {}
65+
66+
friend class LockableStreamFile;
67+
68+
std::lock_guard<std::recursive_mutex> m_guard;
69+
};
70+
71+
class LockableStreamFile {
72+
public:
73+
LockableStreamFile(std::shared_ptr<StreamFile> stream_file_sp)
74+
: m_file_sp(stream_file_sp->GetFileSP()) {}
75+
LockableStreamFile(StreamFile &stream_file)
76+
: m_file_sp(stream_file.GetFileSP()) {}
77+
LockableStreamFile(FILE *fh, bool transfer_ownership)
78+
: m_file_sp(std::make_shared<NativeFile>(fh, transfer_ownership)) {}
79+
LockableStreamFile(std::shared_ptr<File> file_sp) : m_file_sp(file_sp) {}
80+
81+
LockedStreamFile Lock() { return LockedStreamFile(m_file_sp, m_mutex); }
82+
83+
/// Unsafe accessors to get the underlying File without a lock. Exists for
84+
/// legacy reasons.
85+
/// @{
86+
File &GetUnlockedFile() { return *m_file_sp; }
87+
std::shared_ptr<File> GetUnlockedFileSP() { return m_file_sp; }
88+
/// @}
89+
90+
std::recursive_mutex &GetMutex() { return m_mutex; }
91+
92+
protected:
93+
std::shared_ptr<File> m_file_sp;
94+
std::recursive_mutex m_mutex;
95+
96+
private:
97+
LockableStreamFile(const LockableStreamFile &) = delete;
98+
const LockableStreamFile &operator=(const LockableStreamFile &) = delete;
99+
};
100+
55101
} // namespace lldb_private
56102

57103
#endif // LLDB_HOST_STREAMFILE_H

lldb/include/lldb/Interpreter/ScriptInterpreter.h

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,12 @@ class ScriptInterpreterIORedirect {
116116
~ScriptInterpreterIORedirect();
117117

118118
lldb::FileSP GetInputFile() const { return m_input_file_sp; }
119-
lldb::FileSP GetOutputFile() const { return m_output_file_sp->GetFileSP(); }
120-
lldb::FileSP GetErrorFile() const { return m_error_file_sp->GetFileSP(); }
119+
lldb::FileSP GetOutputFile() const {
120+
return m_output_file_sp->GetUnlockedFileSP();
121+
}
122+
lldb::FileSP GetErrorFile() const {
123+
return m_error_file_sp->GetUnlockedFileSP();
124+
}
121125

122126
/// Flush our output and error file handles.
123127
void Flush();
@@ -128,8 +132,8 @@ class ScriptInterpreterIORedirect {
128132
ScriptInterpreterIORedirect(Debugger &debugger, CommandReturnObject *result);
129133

130134
lldb::FileSP m_input_file_sp;
131-
lldb::StreamFileSP m_output_file_sp;
132-
lldb::StreamFileSP m_error_file_sp;
135+
lldb::LockableStreamFileSP m_output_file_sp;
136+
lldb::LockableStreamFileSP m_error_file_sp;
133137
ThreadedCommunication m_communication;
134138
bool m_disconnect;
135139
};
@@ -478,7 +482,7 @@ class ScriptInterpreter : public PluginInterface {
478482
dest.clear();
479483
return false;
480484
}
481-
485+
482486
virtual StructuredData::ObjectSP
483487
GetOptionsForCommandObject(StructuredData::GenericSP cmd_obj_sp) {
484488
return {};
@@ -488,9 +492,9 @@ class ScriptInterpreter : public PluginInterface {
488492
GetArgumentsForCommandObject(StructuredData::GenericSP cmd_obj_sp) {
489493
return {};
490494
}
491-
495+
492496
virtual bool SetOptionValueForCommandObject(
493-
StructuredData::GenericSP cmd_obj_sp, ExecutionContext *exe_ctx,
497+
StructuredData::GenericSP cmd_obj_sp, ExecutionContext *exe_ctx,
494498
llvm::StringRef long_option, llvm::StringRef value) {
495499
return false;
496500
}

lldb/include/lldb/Target/ThreadPlanTracer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ class ThreadPlanTracer {
5656
Process &m_process;
5757
lldb::tid_t m_tid;
5858

59-
Stream *GetLogStream();
59+
lldb::StreamSP GetLogStream();
6060

6161
virtual void Log();
6262

lldb/include/lldb/lldb-forward.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ class StoppointCallbackContext;
215215
class Stream;
216216
class StreamFile;
217217
class StreamString;
218+
class LockableStreamFile;
218219
class StringList;
219220
class StringTableReader;
220221
class StructuredDataImpl;
@@ -432,6 +433,7 @@ typedef std::unique_ptr<lldb_private::StackFrameRecognizerManager>
432433
typedef std::shared_ptr<lldb_private::StopInfo> StopInfoSP;
433434
typedef std::shared_ptr<lldb_private::Stream> StreamSP;
434435
typedef std::shared_ptr<lldb_private::StreamFile> StreamFileSP;
436+
typedef std::shared_ptr<lldb_private::LockableStreamFile> LockableStreamFileSP;
435437
typedef std::shared_ptr<lldb_private::StringSummaryFormat>
436438
StringTypeSummaryImplSP;
437439
typedef std::unique_ptr<lldb_private::StructuredDataImpl> StructuredDataImplUP;

lldb/source/API/SBDebugger.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -509,30 +509,30 @@ SBFile SBDebugger::GetInputFile() {
509509
FILE *SBDebugger::GetOutputFileHandle() {
510510
LLDB_INSTRUMENT_VA(this);
511511
if (m_opaque_sp)
512-
return m_opaque_sp->GetOutputStreamSP()->GetFile().GetStream();
512+
return m_opaque_sp->GetOutputStreamSP()->GetUnlockedFile().GetStream();
513513
return nullptr;
514514
}
515515

516516
SBFile SBDebugger::GetOutputFile() {
517517
LLDB_INSTRUMENT_VA(this);
518518
if (m_opaque_sp)
519-
return SBFile(m_opaque_sp->GetOutputStreamSP()->GetFileSP());
519+
return SBFile(m_opaque_sp->GetOutputStreamSP()->GetUnlockedFileSP());
520520
return SBFile();
521521
}
522522

523523
FILE *SBDebugger::GetErrorFileHandle() {
524524
LLDB_INSTRUMENT_VA(this);
525525

526526
if (m_opaque_sp)
527-
return m_opaque_sp->GetErrorStreamSP()->GetFile().GetStream();
527+
return m_opaque_sp->GetErrorStreamSP()->GetUnlockedFile().GetStream();
528528
return nullptr;
529529
}
530530

531531
SBFile SBDebugger::GetErrorFile() {
532532
LLDB_INSTRUMENT_VA(this);
533533
SBFile file;
534534
if (m_opaque_sp)
535-
return SBFile(m_opaque_sp->GetErrorStreamSP()->GetFileSP());
535+
return SBFile(m_opaque_sp->GetErrorStreamSP()->GetUnlockedFileSP());
536536
return SBFile();
537537
}
538538

@@ -573,8 +573,8 @@ void SBDebugger::HandleCommand(const char *command) {
573573

574574
sb_interpreter.HandleCommand(command, result, false);
575575

576-
result.PutError(m_opaque_sp->GetErrorStreamSP()->GetFileSP());
577-
result.PutOutput(m_opaque_sp->GetOutputStreamSP()->GetFileSP());
576+
result.PutError(m_opaque_sp->GetErrorStreamSP()->GetUnlockedFileSP());
577+
result.PutOutput(m_opaque_sp->GetOutputStreamSP()->GetUnlockedFileSP());
578578

579579
if (!m_opaque_sp->GetAsyncExecution()) {
580580
SBProcess process(GetCommandInterpreter().GetProcess());

lldb/source/Commands/CommandObjectBreakpointCommand.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -193,10 +193,12 @@ are no syntax errors may indicate that a function was declared but never called.
193193
Options *GetOptions() override { return &m_all_options; }
194194

195195
void IOHandlerActivated(IOHandler &io_handler, bool interactive) override {
196-
StreamFileSP output_sp(io_handler.GetOutputStreamFileSP());
197-
if (output_sp && interactive) {
198-
output_sp->PutCString(g_reader_instructions);
199-
output_sp->Flush();
196+
if (interactive) {
197+
if (lldb::LockableStreamFileSP output_sp =
198+
io_handler.GetOutputStreamFileSP()) {
199+
LockedStreamFile locked_stream = output_sp->Lock();
200+
locked_stream.PutCString(g_reader_instructions);
201+
}
200202
}
201203
}
202204

0 commit comments

Comments
 (0)