https://github.com/da-viper updated https://github.com/llvm/llvm-project/pull/178083
>From 0d4eb594ea600e1cc2716f99e54906ddb6e72a42 Mon Sep 17 00:00:00 2001 From: Ebuka Ezike <[email protected]> Date: Mon, 26 Jan 2026 21:28:48 +0000 Subject: [PATCH 1/3] [lldb] Fix memory monitor shutdown on Linux using eventfd The current linux implementation has a 1 second timeout when polling for memory pressure. lldb-dap may take up to an extra 1 second to shutdown. Use an event filedescriptor to immediately stop the memory monitor thread. Fixes #150220 --- lldb/include/lldb/Host/MemoryMonitor.h | 3 +- lldb/source/Host/common/MemoryMonitor.cpp | 98 ++++++++++++++++++----- 2 files changed, 81 insertions(+), 20 deletions(-) diff --git a/lldb/include/lldb/Host/MemoryMonitor.h b/lldb/include/lldb/Host/MemoryMonitor.h index 504f5f9cba96b..541a647c2276f 100644 --- a/lldb/include/lldb/Host/MemoryMonitor.h +++ b/lldb/include/lldb/Host/MemoryMonitor.h @@ -11,6 +11,7 @@ #include <functional> #include <memory> +#include <utility> namespace lldb_private { @@ -18,7 +19,7 @@ class MemoryMonitor { public: using Callback = std::function<void()>; - MemoryMonitor(Callback callback) : m_callback(callback) {} + MemoryMonitor(Callback callback) : m_callback(std::move(callback)) {} virtual ~MemoryMonitor() = default; /// MemoryMonitor is not copyable. diff --git a/lldb/source/Host/common/MemoryMonitor.cpp b/lldb/source/Host/common/MemoryMonitor.cpp index dbd44a4774758..d68f64e5c5043 100644 --- a/lldb/source/Host/common/MemoryMonitor.cpp +++ b/lldb/source/Host/common/MemoryMonitor.cpp @@ -13,7 +13,6 @@ #include "lldb/Utility/Log.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/Support/Error.h" -#include <atomic> #include <cstddef> #include <cstdio> #include <cstring> @@ -21,46 +20,102 @@ #if defined(__linux__) #include <fcntl.h> #include <poll.h> +#include <sys/eventfd.h> +#include <sys/poll.h> #include <unistd.h> #endif #if defined(_WIN32) +#include <atomic> #include <windows.h> #endif using namespace lldb_private; -class MemoryMonitorPoll : public MemoryMonitor { +#if defined(__linux__) +class MemoryMonitorLinux : public MemoryMonitor { public: using MemoryMonitor::MemoryMonitor; lldb::thread_result_t MonitorThread() { -#if defined(__linux__) - struct pollfd fds; - fds.fd = open("/proc/pressure/memory", O_RDWR | O_NONBLOCK); - if (fds.fd < 0) + constexpr size_t pressure_idx = 0; + constexpr size_t stop_idx = 1; + constexpr size_t fd_count = 2; + std::array<pollfd, fd_count> pfds{}; + + // Setup stop file descriptor. + m_stop_fd = ::eventfd(0, O_NONBLOCK); + if (m_stop_fd < 0) + return {}; + pfds[stop_idx].fd = m_stop_fd; + pfds[stop_idx].events = POLLIN; + + // Setup pressure file descriptor. + pfds[pressure_idx].fd = + ::open("/proc/pressure/memory", O_RDWR | O_NONBLOCK); + if (pfds[pressure_idx].fd < 0) { + ::close(m_stop_fd); return {}; - fds.events = POLLPRI; + } + pfds[pressure_idx].events = POLLPRI; - llvm::scope_exit cleanup([&]() { close(fds.fd); }); + llvm::scope_exit cleanup([&]() { + ::close(pfds[pressure_idx].fd); + ::close(m_stop_fd); + }); // Detect a 50ms stall in a 2 second time window. - const char trig[] = "some 50000 2000000"; - if (write(fds.fd, trig, strlen(trig) + 1) < 0) + constexpr llvm::StringRef trigger = "some 50000 2000000"; + if (::write(pfds[pressure_idx].fd, trigger.data(), trigger.size()) < 0) return {}; - while (!m_done) { - int n = poll(&fds, 1, g_timeout); + while (true) { + constexpr int timeout_infinite = -1; + const int n = ::poll(pfds.data(), pfds.size(), timeout_infinite); if (n > 0) { - if (fds.revents & POLLERR) + // Handle stop event. + if (pfds[stop_idx].revents & (POLLIN | POLLERR)) + return {}; + + if (pfds[pressure_idx].revents & POLLERR) return {}; - if (fds.revents & POLLPRI) + if (pfds[pressure_idx].revents & POLLPRI) m_callback(); } } -#endif + return {}; + } -#if defined(_WIN32) + void Start() override { + llvm::Expected<HostThread> memory_monitor_thread = + ThreadLauncher::LaunchThread("memory.monitor", + [this] { return MonitorThread(); }); + if (memory_monitor_thread) { + m_memory_monitor_thread = *memory_monitor_thread; + } else { + LLDB_LOG_ERROR(GetLog(LLDBLog::Host), memory_monitor_thread.takeError(), + "failed to launch host thread: {0}"); + } + } + + void Stop() override { + if (m_memory_monitor_thread.IsJoinable()) { + ::eventfd_write(m_stop_fd, 1); + m_memory_monitor_thread.Join(nullptr); + } + } + +private: + int m_stop_fd = -1; + HostThread m_memory_monitor_thread; +}; +#elif defined(_WIN32) + +class MemoryMonitorWindows : public MemoryMonitor { +public: + using MemoryMonitor::MemoryMonitor; + + lldb::thread_result_t MonitorThread() { HANDLE low_memory_notification = CreateMemoryResourceNotification(LowMemoryResourceNotification); if (!low_memory_notification) @@ -72,8 +127,6 @@ class MemoryMonitorPoll : public MemoryMonitor { m_callback(); } } -#endif - return {}; } @@ -101,9 +154,16 @@ class MemoryMonitorPoll : public MemoryMonitor { std::atomic<bool> m_done = false; HostThread m_memory_monitor_thread; }; +#endif #if !defined(__APPLE__) std::unique_ptr<MemoryMonitor> MemoryMonitor::Create(Callback callback) { - return std::make_unique<MemoryMonitorPoll>(callback); +#if defined(__linux__) + return std::make_unique<MemoryMonitorLinux>(std::move(callback)); +#elif defined(_WIN32) + return std::make_unique<MemoryMonitorWindows>(std::move(callback)); +#else + return nullptr; +#endif } #endif >From 12d9fe14df288a8e8646d31f827463a8b581fe04 Mon Sep 17 00:00:00 2001 From: Ebuka Ezike <[email protected]> Date: Tue, 27 Jan 2026 20:04:35 +0000 Subject: [PATCH 2/3] make the monitor thread private --- lldb/source/Host/common/MemoryMonitor.cpp | 73 +++++++++++++---------- 1 file changed, 42 insertions(+), 31 deletions(-) diff --git a/lldb/source/Host/common/MemoryMonitor.cpp b/lldb/source/Host/common/MemoryMonitor.cpp index d68f64e5c5043..fc873b6bd9e50 100644 --- a/lldb/source/Host/common/MemoryMonitor.cpp +++ b/lldb/source/Host/common/MemoryMonitor.cpp @@ -37,6 +37,46 @@ class MemoryMonitorLinux : public MemoryMonitor { public: using MemoryMonitor::MemoryMonitor; + explicit MemoryMonitorLinux(Callback callback) + : MemoryMonitor(std::move(callback)), + m_stop_fd(::eventfd(0, EFD_NONBLOCK)) {} + + ~MemoryMonitorLinux() { + if (m_memory_monitor_thread.IsJoinable()) + m_memory_monitor_thread.Join(nullptr); + if (m_stop_fd != 1) + ::close(m_stop_fd); + } + + void Start() override { + if (m_stop_fd < 0) { + LLDB_LOG_ERROR( + GetLog(LLDBLog::Host), + llvm::errorCodeToError(llvm::errnoAsErrorCode()), + "failed to create stop file descriptor for memory monitor: {0}"); + return; + } + + llvm::Expected<HostThread> memory_monitor_thread = + ThreadLauncher::LaunchThread("memory.monitor", + [this] { return MonitorThread(); }); + if (memory_monitor_thread) { + m_memory_monitor_thread = *memory_monitor_thread; + } else { + LLDB_LOG_ERROR(GetLog(LLDBLog::Host), memory_monitor_thread.takeError(), + "failed to launch host thread: {0}"); + } + } + + void Stop() override { + if (m_memory_monitor_thread.IsJoinable()) { + if (m_stop_fd != -1) + ::eventfd_write(m_stop_fd, 1); + m_memory_monitor_thread.Join(nullptr); + } + } + +private: lldb::thread_result_t MonitorThread() { constexpr size_t pressure_idx = 0; constexpr size_t stop_idx = 1; @@ -44,25 +84,17 @@ class MemoryMonitorLinux : public MemoryMonitor { std::array<pollfd, fd_count> pfds{}; // Setup stop file descriptor. - m_stop_fd = ::eventfd(0, O_NONBLOCK); - if (m_stop_fd < 0) - return {}; pfds[stop_idx].fd = m_stop_fd; pfds[stop_idx].events = POLLIN; // Setup pressure file descriptor. pfds[pressure_idx].fd = ::open("/proc/pressure/memory", O_RDWR | O_NONBLOCK); - if (pfds[pressure_idx].fd < 0) { - ::close(m_stop_fd); + if (pfds[pressure_idx].fd < 0) return {}; - } pfds[pressure_idx].events = POLLPRI; - llvm::scope_exit cleanup([&]() { - ::close(pfds[pressure_idx].fd); - ::close(m_stop_fd); - }); + llvm::scope_exit cleanup([&]() { ::close(pfds[pressure_idx].fd); }); // Detect a 50ms stall in a 2 second time window. constexpr llvm::StringRef trigger = "some 50000 2000000"; @@ -85,27 +117,6 @@ class MemoryMonitorLinux : public MemoryMonitor { } return {}; } - - void Start() override { - llvm::Expected<HostThread> memory_monitor_thread = - ThreadLauncher::LaunchThread("memory.monitor", - [this] { return MonitorThread(); }); - if (memory_monitor_thread) { - m_memory_monitor_thread = *memory_monitor_thread; - } else { - LLDB_LOG_ERROR(GetLog(LLDBLog::Host), memory_monitor_thread.takeError(), - "failed to launch host thread: {0}"); - } - } - - void Stop() override { - if (m_memory_monitor_thread.IsJoinable()) { - ::eventfd_write(m_stop_fd, 1); - m_memory_monitor_thread.Join(nullptr); - } - } - -private: int m_stop_fd = -1; HostThread m_memory_monitor_thread; }; >From cc6cadc8dee190ea82bf8aa90dd77d0b82a4841e Mon Sep 17 00:00:00 2001 From: Ebuka Ezike <[email protected]> Date: Wed, 28 Jan 2026 12:32:01 +0000 Subject: [PATCH 3/3] fix offset --- lldb/source/Host/common/MemoryMonitor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/source/Host/common/MemoryMonitor.cpp b/lldb/source/Host/common/MemoryMonitor.cpp index fc873b6bd9e50..7734be8688675 100644 --- a/lldb/source/Host/common/MemoryMonitor.cpp +++ b/lldb/source/Host/common/MemoryMonitor.cpp @@ -98,7 +98,7 @@ class MemoryMonitorLinux : public MemoryMonitor { // Detect a 50ms stall in a 2 second time window. constexpr llvm::StringRef trigger = "some 50000 2000000"; - if (::write(pfds[pressure_idx].fd, trigger.data(), trigger.size()) < 0) + if (::write(pfds[pressure_idx].fd, trigger.data(), trigger.size() + 1) < 0) return {}; while (true) { _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
