-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[lldb-dap] Partially reverting OutputRedirector changes. #125136
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
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`. This causes the `lldb_dap::OutputRedirector::RedirectTo()` to turn into a busy loop. Additionally, the 'Read' call is not peforming parital reads and will only invoke the redirect callback once the output buffer is filled. 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 873426b but keeping the refactored structure and thread management.
|
@llvm/pr-subscribers-lldb Author: John Harrison (ashgti) ChangesI 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
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 873426b but keeping the refactored structure and thread management. Full diff: https://github.com/llvm/llvm-project/pull/125136.diff 2 Files Affected:
diff --git a/lldb/tools/lldb-dap/OutputRedirector.cpp b/lldb/tools/lldb-dap/OutputRedirector.cpp
index 8fcbcfec99c4431..7935e17a653bec3 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 41ea05c22c69195..d2bd39797f3d75b 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;
};
|
|
@ashgti , these changes break the windows build with the following errors: https://lab.llvm.org/buildbot/#/builders/197/builds/1379/steps/8/logs/stdio https://lab.llvm.org/buildbot/#/builders/197/builds/1379 would you take care of it? |
|
Note that this error occurred on Windows host building |
|
#125156 should fix this |
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 873426b but keeping the refactored structure and thread management. (cherry picked from commit adb9ef0)
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 873426b but keeping the refactored structure and thread management.
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 873426b but keeping the refactored structure and thread management.
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 tonow + 0(seellvm-project/lldb/source/Host/posix/PipePosix.cpp
Line 314 in 7ceef1b
llvm-project/lldb/source/Utility/SelectHelper.cpp
Line 46 in 7ceef1b
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 873426b but keeping the refactored structure and thread management.