| //===-- OutputRedirector.cpp -----------------------------------*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===/ |
| |
| #include "llvm/Support/Error.h" |
| #include <system_error> |
| #if defined(_WIN32) |
| #include <fcntl.h> |
| #include <io.h> |
| #else |
| #include <unistd.h> |
| #endif |
| |
| #include "DAP.h" |
| #include "OutputRedirector.h" |
| #include "llvm/ADT/StringRef.h" |
| |
| using lldb_private::Pipe; |
| using lldb_private::Status; |
| using llvm::createStringError; |
| using llvm::Error; |
| using llvm::Expected; |
| using llvm::StringRef; |
| |
| namespace lldb_dap { |
| |
| Expected<int> OutputRedirector::GetWriteFileDescriptor() { |
| if (!m_pipe.CanWrite()) |
| return createStringError(std::errc::bad_file_descriptor, |
| "write handle is not open for writing"); |
| return m_pipe.GetWriteFileDescriptor(); |
| } |
| |
| Error OutputRedirector::RedirectTo(std::function<void(StringRef)> callback) { |
| Status status = m_pipe.CreateNew(/*child_process_inherit=*/false); |
| if (status.Fail()) |
| return status.takeError(); |
| |
| m_forwarder = std::thread([this, callback]() { |
| char buffer[OutputBufferSize]; |
| while (m_pipe.CanRead() && !m_stopped) { |
| size_t bytes_read; |
| Status status = m_pipe.Read(&buffer, sizeof(buffer), bytes_read); |
| if (status.Fail()) |
| continue; |
| |
| // EOF detected |
| if (bytes_read == 0 || m_stopped) |
| break; |
| |
| callback(StringRef(buffer, bytes_read)); |
| } |
| }); |
| |
| return Error::success(); |
| } |
| |
| void OutputRedirector::Stop() { |
| m_stopped = true; |
| |
| if (m_pipe.CanWrite()) { |
| // Closing the pipe may not be sufficient to wake up the thread in case the |
| // write descriptor is duplicated (to stdout/err or to another process). |
| // Write a null byte to ensure the read call returns. |
| char buf[] = "\0"; |
| size_t bytes_written; |
| m_pipe.Write(buf, sizeof(buf), bytes_written); |
| m_pipe.CloseWriteFileDescriptor(); |
| m_forwarder.join(); |
| } |
| } |
| |
| } // namespace lldb_dap |