[Lldb-commits] [lldb] adb9ef0 - [lldb-dap] Partially reverting OutputRedirector changes. (#125136)
via lldb-commits
lldb-commits at lists.llvm.org
Thu Jan 30 16:35:18 PST 2025
Author: John Harrison
Date: 2025-01-30T16:35:15-08:00
New Revision: adb9ef035552d7fc42a34560677f89f4f6421295
URL: https://github.com/llvm/llvm-project/commit/adb9ef035552d7fc42a34560677f89f4f6421295
DIFF: https://github.com/llvm/llvm-project/commit/adb9ef035552d7fc42a34560677f89f4f6421295.diff
LOG: [lldb-dap] Partially reverting OutputRedirector changes. (#125136)
I just noticed with these changes lldb-dap was using 200% of my CPU and
root causing the issue it seems that lldb_private::Pipe::Read() (without
a timeout) is using a timeout of `std::chrono::microseconds::zero()`
which ends up setting the SelectHelper timeout to `now + 0` (see
https://github.com/llvm/llvm-project/blob/7ceef1b1824073fcfd4724539f5942442da1a9c2/lldb/source/Host/posix/PipePosix.cpp#L314
and
https://github.com/llvm/llvm-project/blob/7ceef1b1824073fcfd4724539f5942442da1a9c2/lldb/source/Utility/SelectHelper.cpp#L46)
which causes SelectHelper to return immediately with a timeout error. As
a result the `lldb_dap::OutputRedirector::RedirectTo()` to turn into a
busy loop.
Additionally, the 'read' call is waiting until the output buffer is full
before returning, which prevents any partial output (see
https://github.com/llvm/llvm-project/blob/7ceef1b1824073fcfd4724539f5942442da1a9c2/lldb/source/Host/posix/PipePosix.cpp#L325C9-L326C17).
This is not the desired behavior for lldb-dap. Instead we want a write
to the FD to result in a callback to send the DAP Output event, which
mean we want partial output.
To mitigate this, I'm reverting the reading operation to the previous
behavior before 873426bea3dd67d80dd10650e64e91c69796614f but keeping the
refactored structure and thread management.
Added:
Modified:
lldb/tools/lldb-dap/OutputRedirector.cpp
lldb/tools/lldb-dap/OutputRedirector.h
Removed:
################################################################################
diff --git a/lldb/tools/lldb-dap/OutputRedirector.cpp b/lldb/tools/lldb-dap/OutputRedirector.cpp
index 8fcbcfec99c443..7935e17a653bec 100644
--- a/lldb/tools/lldb-dap/OutputRedirector.cpp
+++ b/lldb/tools/lldb-dap/OutputRedirector.cpp
@@ -6,6 +6,9 @@
//
//===----------------------------------------------------------------------===/
+#include "OutputRedirector.h"
+#include "DAP.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Error.h"
#include <system_error>
#if defined(_WIN32)
@@ -15,45 +18,59 @@
#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::inconvertibleErrorCode;
using llvm::StringRef;
namespace lldb_dap {
+int OutputRedirector::kInvalidDescriptor = -1;
+
+OutputRedirector::OutputRedirector() : m_fd(kInvalidDescriptor) {}
+
Expected<int> OutputRedirector::GetWriteFileDescriptor() {
- if (!m_pipe.CanWrite())
+ if (m_fd == kInvalidDescriptor)
return createStringError(std::errc::bad_file_descriptor,
"write handle is not open for writing");
- return m_pipe.GetWriteFileDescriptor();
+ return m_fd;
}
Error OutputRedirector::RedirectTo(std::function<void(StringRef)> callback) {
- Status status = m_pipe.CreateNew(/*child_process_inherit=*/false);
- if (status.Fail())
- return status.takeError();
+ assert(m_fd == kInvalidDescriptor && "Output readirector already started.");
+ int new_fd[2];
- 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;
+#if defined(_WIN32)
+ if (::_pipe(new_fd, OutputBufferSize, O_TEXT) == -1) {
+#else
+ if (::pipe(new_fd) == -1) {
+#endif
+ int error = errno;
+ return createStringError(inconvertibleErrorCode(),
+ "Couldn't create new pipe %s", strerror(error));
+ }
- // EOF detected
- if (bytes_read == 0 || m_stopped)
+ int read_fd = new_fd[0];
+ m_fd = new_fd[1];
+ m_forwarder = std::thread([this, callback, read_fd]() {
+ char buffer[OutputBufferSize];
+ while (!m_stopped) {
+ ssize_t bytes_count = ::read(read_fd, &buffer, sizeof(buffer));
+ // EOF detected.
+ if (bytes_count == 0)
+ break;
+ if (bytes_count == -1) {
+ // Skip non-fatal errors.
+ if (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK)
+ continue;
break;
+ }
- callback(StringRef(buffer, bytes_read));
+ callback(StringRef(buffer, bytes_count));
}
+ ::close(read_fd);
});
return Error::success();
@@ -62,14 +79,15 @@ Error OutputRedirector::RedirectTo(std::function<void(StringRef)> callback) {
void OutputRedirector::Stop() {
m_stopped = true;
- if (m_pipe.CanWrite()) {
+ if (m_fd != kInvalidDescriptor) {
+ int fd = m_fd;
+ m_fd = kInvalidDescriptor;
// 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();
+ ::write(fd, buf, sizeof(buf));
+ ::close(fd);
m_forwarder.join();
}
}
diff --git a/lldb/tools/lldb-dap/OutputRedirector.h b/lldb/tools/lldb-dap/OutputRedirector.h
index 41ea05c22c6919..d2bd39797f3d75 100644
--- a/lldb/tools/lldb-dap/OutputRedirector.h
+++ b/lldb/tools/lldb-dap/OutputRedirector.h
@@ -20,6 +20,8 @@ namespace lldb_dap {
class OutputRedirector {
public:
+ static int kInvalidDescriptor;
+
/// Creates writable file descriptor that will invoke the given callback on
/// each write in a background thread.
///
@@ -33,13 +35,13 @@ class OutputRedirector {
~OutputRedirector() { Stop(); }
- OutputRedirector() = default;
+ OutputRedirector();
OutputRedirector(const OutputRedirector &) = delete;
OutputRedirector &operator=(const OutputRedirector &) = delete;
private:
std::atomic<bool> m_stopped = false;
- lldb_private::Pipe m_pipe;
+ int m_fd;
std::thread m_forwarder;
};
More information about the lldb-commits
mailing list