diff --git a/lldb/tools/lldb-vscode/IOStream.h b/lldb/tools/lldb-vscode/IOStream.h --- a/lldb/tools/lldb-vscode/IOStream.h +++ b/lldb/tools/lldb-vscode/IOStream.h @@ -63,6 +63,9 @@ StreamDescriptor descriptor; bool write_full(llvm::StringRef str); + + private: + std::mutex m_mutex; }; } // namespace lldb_vscode diff --git a/lldb/tools/lldb-vscode/IOStream.cpp b/lldb/tools/lldb-vscode/IOStream.cpp --- a/lldb/tools/lldb-vscode/IOStream.cpp +++ b/lldb/tools/lldb-vscode/IOStream.cpp @@ -70,6 +70,7 @@ } bool OutputStream::write_full(llvm::StringRef str) { + std::lock_guard lock(m_mutex); while (!str.empty()) { int bytes_written = 0; if (descriptor.m_is_socket) diff --git a/lldb/tools/lldb-vscode/lldb-vscode.cpp b/lldb/tools/lldb-vscode/lldb-vscode.cpp --- a/lldb/tools/lldb-vscode/lldb-vscode.cpp +++ b/lldb/tools/lldb-vscode/lldb-vscode.cpp @@ -486,6 +486,43 @@ } } +class FileDescriptorToConsoleOutputRedirector { + private: + int m_captured_fd[2]; + std::thread m_thread; + + public: + FileDescriptorToConsoleOutputRedirector(int fd) { + pipe(m_captured_fd); + dup2(m_captured_fd[1], fd); + }; + ~FileDescriptorToConsoleOutputRedirector() { + StopRedirecting(); + } + // Only call this once. + void StartRedirecting() { + int read_fd = m_captured_fd[0]; + + m_thread = std::thread([read_fd] { + char buffer[4096]; + while (true) { + ssize_t bytes_count = read(read_fd, &buffer, sizeof(buffer)); + if (bytes_count == 0) + return; + g_vsc.SendOutput(OutputType::Console, buffer); + } + }); + m_thread.detach(); + } + + void StopRedirecting() { + if (!m_thread.joinable()) + return; + close(m_captured_fd[1]); + m_thread.join(); + } +}; + // "AttachRequest": { // "allOf": [ { "$ref": "#/definitions/Request" }, { // "type": "object", @@ -2781,7 +2818,9 @@ } int main(int argc, char *argv[]) { - + int stdout_fd = dup(fileno(stdout)); + FileDescriptorToConsoleOutputRedirector stdout_redirector(fileno(stdout)); + FileDescriptorToConsoleOutputRedirector stderr_redirector(fileno(stderr)); // Initialize LLDB first before we do anything. lldb::SBDebugger::Initialize(); @@ -2824,9 +2863,11 @@ } } else { g_vsc.input.descriptor = StreamDescriptor::from_file(fileno(stdin), false); - g_vsc.output.descriptor = - StreamDescriptor::from_file(fileno(stdout), false); + g_vsc.output.descriptor = StreamDescriptor::from_file(stdout_fd, false); } + // Can start redirecting now that the output description has been properly set. + stdout_redirector.StartRedirecting(); + stderr_redirector.StartRedirecting(); auto request_handlers = GetRequestHandlers(); uint32_t packet_idx = 0; while (!g_vsc.sent_terminated_event) { @@ -2875,5 +2916,9 @@ // We must terminate the debugger in a thread before the C++ destructor // chain messes everything up. lldb::SBDebugger::Terminate(); + // Can now safely stop redirecting since lldb will no longer emit stdout + // or stderr messages. + stdout_redirector.StopRedirecting(); + stderr_redirector.StopRedirecting(); return 0; }