Skip to content

Commit c45c55d

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 0671891 commit c45c55d

22 files changed

+423
-312
lines changed

lldb/include/lldb/Core/Debugger.h

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -131,13 +131,12 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
131131

132132
void SetAsyncExecution(bool async);
133133

134-
File &GetInputFile() { return *m_input_file_sp; }
135-
136134
lldb::FileSP GetInputFileSP() { return m_input_file_sp; }
135+
File &GetInputFile() { return *m_input_file_sp; }
137136

138-
lldb::FileSP GetOutputFileSP() { return m_output_stream_sp->GetFileSP(); }
137+
lldb::FileSP GetOutputFileSP() { return m_output_stream_sp->GetUnlockedFileSP(); }
139138

140-
lldb::FileSP GetErrorFileSP() { return m_error_stream_sp->GetFileSP(); }
139+
lldb::FileSP GetErrorFileSP() { return m_error_stream_sp->GetUnlockedFileSP(); }
141140

142141
repro::DataRecorder *GetInputRecorder();
143142

@@ -198,8 +197,8 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
198197
// If any of the streams are not set, set them to the in/out/err stream of
199198
// the top most input reader to ensure they at least have something
200199
void AdoptTopIOHandlerFilesIfInvalid(lldb::FileSP &in,
201-
lldb::StreamFileSP &out,
202-
lldb::StreamFileSP &err);
200+
lldb::LockableStreamFileSP &out,
201+
lldb::LockableStreamFileSP &err);
203202

204203
/// Run the given IO handler and return immediately.
205204
void RunIOHandlerAsync(const lldb::IOHandlerSP &reader_sp,
@@ -649,8 +648,8 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
649648
/// should not be used directly. Use GetAsyncOutputStream and
650649
/// GetAsyncErrorStream instead.
651650
/// @{
652-
lldb::StreamFileSP GetOutputStreamSP() { return m_output_stream_sp; }
653-
lldb::StreamFileSP GetErrorStreamSP() { return m_error_stream_sp; }
651+
lldb::LockableStreamFileSP GetOutputStreamSP() { return m_output_stream_sp; }
652+
lldb::LockableStreamFileSP GetErrorStreamSP() { return m_error_stream_sp; }
654653
/// @}
655654

656655
void PushIOHandler(const lldb::IOHandlerSP &reader_sp,
@@ -693,8 +692,8 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
693692

694693
// these should never be NULL
695694
lldb::FileSP m_input_file_sp;
696-
lldb::StreamFileSP m_output_stream_sp;
697-
lldb::StreamFileSP m_error_stream_sp;
695+
lldb::LockableStreamFileSP m_output_stream_sp;
696+
lldb::LockableStreamFileSP m_error_stream_sp;
698697

699698
/// Used for shadowing the input file when capturing a reproducer.
700699
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
@@ -53,8 +53,9 @@ class IOHandler {
5353
IOHandler(Debugger &debugger, IOHandler::Type type);
5454

5555
IOHandler(Debugger &debugger, IOHandler::Type type,
56-
const lldb::FileSP &input_sp, const lldb::StreamFileSP &output_sp,
57-
const lldb::StreamFileSP &error_sp, uint32_t flags);
56+
const lldb::FileSP &input_sp,
57+
const lldb::LockableStreamFileSP &output_sp,
58+
const lldb::LockableStreamFileSP &error_sp, uint32_t flags);
5859

5960
virtual ~IOHandler();
6061

@@ -112,17 +113,11 @@ class IOHandler {
112113

113114
int GetErrorFD();
114115

115-
FILE *GetInputFILE();
116-
117-
FILE *GetOutputFILE();
118-
119-
FILE *GetErrorFILE();
120-
121116
lldb::FileSP GetInputFileSP();
122117

123-
lldb::StreamFileSP GetOutputStreamFileSP();
118+
lldb::LockableStreamFileSP GetOutputStreamFileSP();
124119

125-
lldb::StreamFileSP GetErrorStreamFileSP();
120+
lldb::LockableStreamFileSP GetErrorStreamFileSP();
126121

127122
Debugger &GetDebugger() { return m_debugger; }
128123

@@ -155,14 +150,11 @@ class IOHandler {
155150

156151
virtual void PrintAsync(const char *s, size_t len, bool is_stdout);
157152

158-
std::recursive_mutex &GetOutputMutex() { return m_output_mutex; }
159-
160153
protected:
161154
Debugger &m_debugger;
162155
lldb::FileSP m_input_sp;
163-
lldb::StreamFileSP m_output_sp;
164-
lldb::StreamFileSP m_error_sp;
165-
std::recursive_mutex m_output_mutex;
156+
lldb::LockableStreamFileSP m_output_sp;
157+
lldb::LockableStreamFileSP m_error_sp;
166158
Predicate<bool> m_popped;
167159
Flags m_flags;
168160
Type m_type;
@@ -330,8 +322,8 @@ class IOHandlerEditline : public IOHandler {
330322

331323
IOHandlerEditline(Debugger &debugger, IOHandler::Type type,
332324
const lldb::FileSP &input_sp,
333-
const lldb::StreamFileSP &output_sp,
334-
const lldb::StreamFileSP &error_sp, uint32_t flags,
325+
const lldb::LockableStreamFileSP &output_sp,
326+
const lldb::LockableStreamFileSP &error_sp, uint32_t flags,
335327
const char *editline_name, // Used for saving history files
336328
llvm::StringRef prompt, llvm::StringRef continuation_prompt,
337329
bool multi_line, bool color,
@@ -345,9 +337,10 @@ class IOHandlerEditline : public IOHandler {
345337
IOHandlerDelegate &) = delete;
346338

347339
IOHandlerEditline(Debugger &, IOHandler::Type, const lldb::FileSP &,
348-
const lldb::StreamFileSP &, const lldb::StreamFileSP &,
349-
uint32_t, const char *, const char *, const char *, bool,
350-
bool, uint32_t, IOHandlerDelegate &) = delete;
340+
const lldb::LockableStreamFileSP &,
341+
const lldb::LockableStreamFileSP &, uint32_t, const char *,
342+
const char *, const char *, bool, bool, uint32_t,
343+
IOHandlerDelegate &) = delete;
351344

352345
~IOHandlerEditline() override;
353346

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/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/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)