Skip to content

Commit e52baa8

Browse files
authored
Merge pull request #10368 from swiftlang/cherrypick-output-error-stream-locking
Cherrypick commits to synchronize the debugger output and error stream
2 parents c5dd0ec + 988195d commit e52baa8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+786
-599
lines changed

lldb/include/lldb/Core/Debugger.h

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -132,20 +132,15 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
132132
void SetAsyncExecution(bool async);
133133

134134
lldb::FileSP GetInputFileSP() { return m_input_file_sp; }
135-
136-
lldb::StreamFileSP GetOutputStreamSP() { return m_output_stream_sp; }
137-
138-
lldb::StreamFileSP GetErrorStreamSP() { return m_error_stream_sp; }
139-
140135
File &GetInputFile() { return *m_input_file_sp; }
141136

142-
File &GetOutputFile() { return m_output_stream_sp->GetFile(); }
143-
144-
File &GetErrorFile() { return m_error_stream_sp->GetFile(); }
145-
146-
StreamFile &GetOutputStream() { return *m_output_stream_sp; }
137+
lldb::FileSP GetOutputFileSP() {
138+
return m_output_stream_sp->GetUnlockedFileSP();
139+
}
147140

148-
StreamFile &GetErrorStream() { return *m_error_stream_sp; }
141+
lldb::FileSP GetErrorFileSP() {
142+
return m_error_stream_sp->GetUnlockedFileSP();
143+
}
149144

150145
repro::DataRecorder *GetInputRecorder();
151146

@@ -161,9 +156,9 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
161156

162157
void RestoreInputTerminalState();
163158

164-
lldb::StreamSP GetAsyncOutputStream();
159+
lldb::StreamUP GetAsyncOutputStream();
165160

166-
lldb::StreamSP GetAsyncErrorStream();
161+
lldb::StreamUP GetAsyncErrorStream();
167162

168163
CommandInterpreter &GetCommandInterpreter() {
169164
assert(m_command_interpreter_up.get());
@@ -206,8 +201,8 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
206201
// If any of the streams are not set, set them to the in/out/err stream of
207202
// the top most input reader to ensure they at least have something
208203
void AdoptTopIOHandlerFilesIfInvalid(lldb::FileSP &in,
209-
lldb::StreamFileSP &out,
210-
lldb::StreamFileSP &err);
204+
lldb::LockableStreamFileSP &out,
205+
lldb::LockableStreamFileSP &err);
211206

212207
/// Run the given IO handler and return immediately.
213208
void RunIOHandlerAsync(const lldb::IOHandlerSP &reader_sp,
@@ -662,6 +657,14 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
662657

663658
void PrintProgress(const ProgressEventData &data);
664659

660+
/// Except for Debugger and IOHandler, GetOutputStreamSP and GetErrorStreamSP
661+
/// should not be used directly. Use GetAsyncOutputStream and
662+
/// GetAsyncErrorStream instead.
663+
/// @{
664+
lldb::LockableStreamFileSP GetOutputStreamSP() { return m_output_stream_sp; }
665+
lldb::LockableStreamFileSP GetErrorStreamSP() { return m_error_stream_sp; }
666+
/// @}
667+
665668
void PushIOHandler(const lldb::IOHandlerSP &reader_sp,
666669
bool cancel_top_handler = true);
667670

@@ -702,8 +705,9 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
702705

703706
// these should never be NULL
704707
lldb::FileSP m_input_file_sp;
705-
lldb::StreamFileSP m_output_stream_sp;
706-
lldb::StreamFileSP m_error_stream_sp;
708+
lldb::LockableStreamFileSP m_output_stream_sp;
709+
lldb::LockableStreamFileSP m_error_stream_sp;
710+
LockableStreamFile::Mutex m_output_mutex;
707711

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

lldb/include/lldb/Core/IOHandler.h

Lines changed: 13 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,6 @@ namespace lldb_private {
3232
class Debugger;
3333
} // namespace lldb_private
3434

35-
namespace curses {
36-
class Application;
37-
typedef std::unique_ptr<Application> ApplicationAP;
38-
} // namespace curses
39-
4035
namespace lldb_private {
4136

4237
class IOHandler {
@@ -58,8 +53,9 @@ class IOHandler {
5853
IOHandler(Debugger &debugger, IOHandler::Type type);
5954

6055
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);
56+
const lldb::FileSP &input_sp,
57+
const lldb::LockableStreamFileSP &output_sp,
58+
const lldb::LockableStreamFileSP &error_sp, uint32_t flags);
6359

6460
virtual ~IOHandler();
6561

@@ -117,17 +113,11 @@ class IOHandler {
117113

118114
int GetErrorFD();
119115

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

128-
lldb::StreamFileSP GetOutputStreamFileSP();
118+
lldb::LockableStreamFileSP GetOutputStreamFileSP();
129119

130-
lldb::StreamFileSP GetErrorStreamFileSP();
120+
lldb::LockableStreamFileSP GetErrorStreamFileSP();
131121

132122
Debugger &GetDebugger() { return m_debugger; }
133123

@@ -160,14 +150,11 @@ class IOHandler {
160150

161151
virtual void PrintAsync(const char *s, size_t len, bool is_stdout);
162152

163-
std::recursive_mutex &GetOutputMutex() { return m_output_mutex; }
164-
165153
protected:
166154
Debugger &m_debugger;
167155
lldb::FileSP m_input_sp;
168-
lldb::StreamFileSP m_output_sp;
169-
lldb::StreamFileSP m_error_sp;
170-
std::recursive_mutex m_output_mutex;
156+
lldb::LockableStreamFileSP m_output_sp;
157+
lldb::LockableStreamFileSP m_error_sp;
171158
Predicate<bool> m_popped;
172159
Flags m_flags;
173160
Type m_type;
@@ -335,8 +322,8 @@ class IOHandlerEditline : public IOHandler {
335322

336323
IOHandlerEditline(Debugger &debugger, IOHandler::Type type,
337324
const lldb::FileSP &input_sp,
338-
const lldb::StreamFileSP &output_sp,
339-
const lldb::StreamFileSP &error_sp, uint32_t flags,
325+
const lldb::LockableStreamFileSP &output_sp,
326+
const lldb::LockableStreamFileSP &error_sp, uint32_t flags,
340327
const char *editline_name, // Used for saving history files
341328
llvm::StringRef prompt, llvm::StringRef continuation_prompt,
342329
bool multi_line, bool color,
@@ -350,9 +337,10 @@ class IOHandlerEditline : public IOHandler {
350337
IOHandlerDelegate &) = delete;
351338

352339
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;
340+
const lldb::LockableStreamFileSP &,
341+
const lldb::LockableStreamFileSP &, uint32_t, const char *,
342+
const char *, const char *, bool, bool, uint32_t,
343+
IOHandlerDelegate &) = delete;
356344

357345
~IOHandlerEditline() override;
358346

lldb/include/lldb/Core/IOHandlerCursesGUI.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
#include "lldb/Core/IOHandler.h"
1313

1414
namespace lldb_private {
15+
namespace curses {
16+
class Application;
17+
} // namespace curses
1518

1619
class IOHandlerCursesGUI : public IOHandler {
1720
public:
@@ -34,7 +37,7 @@ class IOHandlerCursesGUI : public IOHandler {
3437
void TerminalSizeChanged() override;
3538

3639
protected:
37-
curses::ApplicationAP m_app_ap;
40+
std::unique_ptr<curses::Application> m_app_up;
3841
};
3942

4043
} // namespace lldb_private

lldb/include/lldb/Core/StreamAsynchronousIO.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,17 @@
1818
namespace lldb_private {
1919
class Debugger;
2020

21+
/// A stream meant for asynchronously printing output. Output is buffered until
22+
/// the stream is flushed or destroyed. Printing is handled by the currently
23+
/// active IOHandler, or the debugger's output or error stream if there is none.
2124
class StreamAsynchronousIO : public Stream {
2225
public:
23-
StreamAsynchronousIO(Debugger &debugger, bool for_stdout, bool colors);
26+
enum ForSTDOUT : bool {
27+
STDOUT = true,
28+
STDERR = false,
29+
};
30+
31+
StreamAsynchronousIO(Debugger &debugger, ForSTDOUT for_stdout);
2432

2533
~StreamAsynchronousIO() override;
2634

@@ -32,7 +40,7 @@ class StreamAsynchronousIO : public Stream {
3240
private:
3341
Debugger &m_debugger;
3442
std::string m_data;
35-
bool m_for_stdout;
43+
ForSTDOUT m_for_stdout;
3644
};
3745

3846
} // namespace lldb_private

lldb/include/lldb/Host/Editline.h

Lines changed: 20 additions & 10 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, 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

@@ -212,19 +214,23 @@ class Editline {
212214
}
213215

214216
void SetPromptAnsiPrefix(std::string prefix) {
215-
m_prompt_ansi_prefix = std::move(prefix);
217+
if (m_color)
218+
m_prompt_ansi_prefix = std::move(prefix);
216219
}
217220

218221
void SetPromptAnsiSuffix(std::string suffix) {
219-
m_prompt_ansi_suffix = std::move(suffix);
222+
if (m_color)
223+
m_prompt_ansi_suffix = std::move(suffix);
220224
}
221225

222226
void SetSuggestionAnsiPrefix(std::string prefix) {
223-
m_suggestion_ansi_prefix = std::move(prefix);
227+
if (m_color)
228+
m_suggestion_ansi_prefix = std::move(prefix);
224229
}
225230

226231
void SetSuggestionAnsiSuffix(std::string suffix) {
227-
m_suggestion_ansi_suffix = std::move(suffix);
232+
if (m_color)
233+
m_suggestion_ansi_suffix = std::move(suffix);
228234
}
229235

230236
/// Prompts for and reads a single line of user input.
@@ -233,7 +239,8 @@ class Editline {
233239
/// Prompts for and reads a multi-line batch of user input.
234240
bool GetLines(int first_line_number, StringList &lines, bool &interrupted);
235241

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

238245
/// Convert the current input lines into a UTF8 StringList
239246
StringList GetInputAsStringList(int line_count = UINT32_MAX);
@@ -388,8 +395,11 @@ class Editline {
388395
volatile std::sig_atomic_t m_terminal_size_has_changed = 0;
389396
std::string m_editor_name;
390397
FILE *m_input_file;
391-
FILE *m_output_file;
392-
FILE *m_error_file;
398+
lldb::LockableStreamFileSP m_output_stream_sp;
399+
lldb::LockableStreamFileSP m_error_stream_sp;
400+
401+
std::optional<LockedStreamFile> m_locked_output;
402+
393403
ConnectionFileDescriptor m_input_connection;
394404

395405
IsInputCompleteCallbackType m_is_input_complete_callback;
@@ -400,13 +410,13 @@ class Editline {
400410
CompleteCallbackType m_completion_callback;
401411
SuggestionCallbackType m_suggestion_callback;
402412

413+
bool m_color;
403414
std::string m_prompt_ansi_prefix;
404415
std::string m_prompt_ansi_suffix;
405416
std::string m_suggestion_ansi_prefix;
406417
std::string m_suggestion_ansi_suffix;
407418

408419
std::size_t m_previous_autosuggestion_size = 0;
409-
std::recursive_mutex &m_output_mutex;
410420
};
411421
}
412422

lldb/include/lldb/Host/File.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,11 @@ class File : public IOObject {
377377

378378
class NativeFile : public File {
379379
public:
380+
enum TransferOwnership : bool {
381+
Owned = true,
382+
Unowned = false,
383+
};
384+
380385
NativeFile() : m_descriptor(kInvalidDescriptor), m_stream(kInvalidStream) {}
381386

382387
NativeFile(FILE *fh, bool transfer_ownership)

lldb/include/lldb/Host/StreamFile.h

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,12 @@
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>
21+
#include <mutex>
1922

2023
namespace lldb_private {
2124

@@ -52,6 +55,55 @@ class StreamFile : public Stream {
5255
const StreamFile &operator=(const StreamFile &) = delete;
5356
};
5457

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

57109
#endif // LLDB_HOST_STREAMFILE_H

0 commit comments

Comments
 (0)