1 //===-- OutputRedirector.cpp -----------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===/ 8 9 #include "llvm/Support/Error.h" 10 #include <system_error> 11 #if defined(_WIN32) 12 #include <fcntl.h> 13 #include <io.h> 14 #else 15 #include <unistd.h> 16 #endif 17 18 #include "DAP.h" 19 #include "OutputRedirector.h" 20 #include "llvm/ADT/StringRef.h" 21 22 using lldb_private::Pipe; 23 using lldb_private::Status; 24 using llvm::createStringError; 25 using llvm::Error; 26 using llvm::Expected; 27 using llvm::StringRef; 28 29 namespace lldb_dap { 30 31 Expected<int> OutputRedirector::GetWriteFileDescriptor() { 32 if (!m_pipe.CanWrite()) 33 return createStringError(std::errc::bad_file_descriptor, 34 "write handle is not open for writing"); 35 return m_pipe.GetWriteFileDescriptor(); 36 } 37 38 Error OutputRedirector::RedirectTo(std::function<void(StringRef)> callback) { 39 Status status = m_pipe.CreateNew(/*child_process_inherit=*/false); 40 if (status.Fail()) 41 return status.takeError(); 42 43 m_forwarder = std::thread([this, callback]() { 44 char buffer[OutputBufferSize]; 45 while (m_pipe.CanRead() && !m_stopped) { 46 size_t bytes_read; 47 Status status = m_pipe.Read(&buffer, sizeof(buffer), bytes_read); 48 if (status.Fail()) 49 continue; 50 51 // EOF detected 52 if (bytes_read == 0 || m_stopped) 53 break; 54 55 callback(StringRef(buffer, bytes_read)); 56 } 57 }); 58 59 return Error::success(); 60 } 61 62 void OutputRedirector::Stop() { 63 m_stopped = true; 64 65 if (m_pipe.CanWrite()) { 66 // Closing the pipe may not be sufficient to wake up the thread in case the 67 // write descriptor is duplicated (to stdout/err or to another process). 68 // Write a null byte to ensure the read call returns. 69 char buf[] = "\0"; 70 size_t bytes_written; 71 m_pipe.Write(buf, sizeof(buf), bytes_written); 72 m_pipe.CloseWriteFileDescriptor(); 73 m_forwarder.join(); 74 } 75 } 76 77 } // namespace lldb_dap 78