blob: 8fcbcfec99c4431268ab6dde453339907a951629 [file] [log] [blame]
//===-- 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