[Lldb-commits] [lldb] [lldb-dap] Implement a MemoryMonitor for macOS & Linux (PR #129332)

Jonas Devlieghere via lldb-commits lldb-commits at lists.llvm.org
Tue Mar 4 22:44:10 PST 2025


https://github.com/JDevlieghere updated https://github.com/llvm/llvm-project/pull/129332

>From c63350db79ac6bcc6f180cc84a37e829d1c8b2a8 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jonas at devlieghere.com>
Date: Fri, 28 Feb 2025 14:54:42 -0600
Subject: [PATCH 1/5] [lldb-dap] Implement a MemoryMonitor for macOS & Linux

This implements a memory monitor for macOS & Linux, and registers a
callback that invokes SBDebugger::MemoryPressureDetected() when a low
memory event is detected.
---
 lldb/tools/lldb-dap/CMakeLists.txt    |   1 +
 lldb/tools/lldb-dap/MemoryMonitor.cpp | 114 ++++++++++++++++++++++++++
 lldb/tools/lldb-dap/MemoryMonitor.h   |  41 +++++++++
 lldb/tools/lldb-dap/lldb-dap.cpp      |  17 +++-
 4 files changed, 171 insertions(+), 2 deletions(-)
 create mode 100644 lldb/tools/lldb-dap/MemoryMonitor.cpp
 create mode 100644 lldb/tools/lldb-dap/MemoryMonitor.h

diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt
index 8b3c520ec4360..8db377e31c3c6 100644
--- a/lldb/tools/lldb-dap/CMakeLists.txt
+++ b/lldb/tools/lldb-dap/CMakeLists.txt
@@ -36,6 +36,7 @@ add_lldb_tool(lldb-dap
   RunInTerminal.cpp
   SourceBreakpoint.cpp
   Watchpoint.cpp
+  MemoryMonitor.cpp
 
   Handler/ResponseHandler.cpp
   Handler/AttachRequestHandler.cpp
diff --git a/lldb/tools/lldb-dap/MemoryMonitor.cpp b/lldb/tools/lldb-dap/MemoryMonitor.cpp
new file mode 100644
index 0000000000000..da3da42fe9b0f
--- /dev/null
+++ b/lldb/tools/lldb-dap/MemoryMonitor.cpp
@@ -0,0 +1,114 @@
+//===-- MemoryMonitor.cpp -------------------------------------------------===//
+//
+// 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 "MemoryMonitor.h"
+#include "llvm/ADT/ScopeExit.h"
+#include <atomic>
+#include <cstdio>
+#include <cstring>
+#include <thread>
+
+#if defined(__APPLE__)
+#include <dispatch/dispatch.h>
+#endif
+
+#if defined(__linux__)
+#include <fcntl.h>
+#include <poll.h>
+#include <unistd.h>
+#endif
+
+using namespace lldb_dap;
+
+#if defined(__APPLE__)
+class MemoryMonitorDarwin : public MemoryMonitor {
+  using MemoryMonitor::MemoryMonitor;
+  void Start() override {
+    m_memory_pressure_source = dispatch_source_create(
+        DISPATCH_SOURCE_TYPE_MEMORYPRESSURE,
+        0, // system-wide monitoring
+        DISPATCH_MEMORYPRESSURE_WARN | DISPATCH_MEMORYPRESSURE_CRITICAL,
+        dispatch_get_main_queue());
+
+    dispatch_source_set_event_handler(m_memory_pressure_source, ^{
+      dispatch_source_memorypressure_flags_t pressureLevel =
+          dispatch_source_get_data(m_memory_pressure_source);
+      if (pressureLevel &
+          (DISPATCH_MEMORYPRESSURE_WARN | DISPATCH_MEMORYPRESSURE_CRITICAL)) {
+        m_callback();
+      }
+    });
+  }
+
+  void Stop() override { dispatch_source_cancel(m_memory_pressure_source); }
+
+private:
+  dispatch_source_t m_memory_pressure_source;
+};
+#endif
+
+#if defined(__linux__)
+static void MonitorThread(std::atomic<bool> &done,
+                          MemoryMonitor::Callback callback) {
+  struct pollfd fds;
+  fds.fd = open("/proc/pressure/memory", O_RDWR | O_NONBLOCK);
+  if (fds.fd < 0)
+    return;
+  fds.events = POLLPRI;
+
+  auto cleanup = llvm::make_scope_exit([&]() { close(fds.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)
+    return;
+
+  while (!done) {
+    int n = poll(&fds, 1, 1000);
+    if (n > 0) {
+      if (fds.revents & POLLERR)
+        return;
+      if (fds.revents & POLLPRI)
+        callback();
+    }
+  }
+}
+
+class MemoryMonitorLinux : public MemoryMonitor {
+public:
+  using MemoryMonitor::MemoryMonitor;
+
+  void Start() override {
+    m_memory_pressure_thread =
+        std::thread(MonitorThread, std::ref(m_done), m_callback);
+  }
+
+  void Stop() override {
+    if (m_memory_pressure_thread.joinable()) {
+      m_done = true;
+      m_memory_pressure_thread.join();
+    }
+  }
+
+private:
+  std::atomic<bool> m_done = false;
+  std::thread m_memory_pressure_thread;
+};
+#endif
+
+std::unique_ptr<MemoryMonitor> MemoryMonitor::Create(Callback callback) {
+#if defined(__APPLE__)
+  return std::make_unique<MemoryMonitorDarwin>(callback);
+#endif
+
+#if defined(__linux__)
+  return std::make_unique<MemoryMonitorLinux>(callback);
+#endif
+
+  return nullptr;
+}
diff --git a/lldb/tools/lldb-dap/MemoryMonitor.h b/lldb/tools/lldb-dap/MemoryMonitor.h
new file mode 100644
index 0000000000000..e07c3bde9e85c
--- /dev/null
+++ b/lldb/tools/lldb-dap/MemoryMonitor.h
@@ -0,0 +1,41 @@
+//===-- MemoryMonitor.h ---------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_TOOLS_LLDB_DAP_WATCHPOINT_H
+#define LLDB_TOOLS_LLDB_DAP_WATCHPOINT_H
+
+#include <functional>
+#include <memory>
+
+namespace lldb_dap {
+
+class MemoryMonitor {
+public:
+  using Callback = std::function<void()>;
+
+  MemoryMonitor(Callback callback) : m_callback(callback) {}
+  virtual ~MemoryMonitor() = default;
+
+  /// MemoryMonitor is not copyable.
+  /// @{
+  MemoryMonitor(const MemoryMonitor &) = delete;
+  MemoryMonitor &operator=(const MemoryMonitor &) = delete;
+  /// @}
+
+  static std::unique_ptr<MemoryMonitor> Create(Callback callback);
+
+  virtual void Start() = 0;
+  virtual void Stop() = 0;
+
+protected:
+  Callback m_callback;
+};
+
+} // namespace lldb_dap
+
+#endif
diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp
index d005eccfae903..41405df548da2 100644
--- a/lldb/tools/lldb-dap/lldb-dap.cpp
+++ b/lldb/tools/lldb-dap/lldb-dap.cpp
@@ -9,7 +9,9 @@
 #include "DAP.h"
 #include "EventHelper.h"
 #include "Handler/RequestHandler.h"
+#include "MemoryMonitor.h"
 #include "RunInTerminal.h"
+#include "lldb/API/SBDebugger.h"
 #include "lldb/API/SBStream.h"
 #include "lldb/Host/Config.h"
 #include "lldb/Host/File.h"
@@ -504,9 +506,20 @@ int main(int argc, char *argv[]) {
     return EXIT_FAILURE;
   }
 
+  // Create a memory monitor. This can return nullptr if the host platform is
+  // not supported.
+  std::unique_ptr<MemoryMonitor> memory_monitor = MemoryMonitor::Create(
+      []() { lldb::SBDebugger::MemoryPressureDetected(); });
+
+  if (memory_monitor)
+    memory_monitor->Start();
+
   // Terminate the debugger before the C++ destructor chain kicks in.
-  auto terminate_debugger =
-      llvm::make_scope_exit([] { lldb::SBDebugger::Terminate(); });
+  auto terminate_debugger = llvm::make_scope_exit([&] {
+    if (memory_monitor)
+      memory_monitor->Stop();
+    lldb::SBDebugger::Terminate();
+  });
 
   std::vector<std::string> pre_init_commands;
   for (const std::string &arg :

>From 59594877e40c60c29832f37a8ff5f1eb495f69f9 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jonas at devlieghere.com>
Date: Fri, 28 Feb 2025 17:07:55 -0600
Subject: [PATCH 2/5] Use the dispatch_get_global_queue and call
 dispatch_release

---
 lldb/tools/lldb-dap/MemoryMonitor.cpp | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/lldb/tools/lldb-dap/MemoryMonitor.cpp b/lldb/tools/lldb-dap/MemoryMonitor.cpp
index da3da42fe9b0f..a9118a89a82ac 100644
--- a/lldb/tools/lldb-dap/MemoryMonitor.cpp
+++ b/lldb/tools/lldb-dap/MemoryMonitor.cpp
@@ -33,7 +33,10 @@ class MemoryMonitorDarwin : public MemoryMonitor {
         DISPATCH_SOURCE_TYPE_MEMORYPRESSURE,
         0, // system-wide monitoring
         DISPATCH_MEMORYPRESSURE_WARN | DISPATCH_MEMORYPRESSURE_CRITICAL,
-        dispatch_get_main_queue());
+        dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
+
+    if (!m_memory_pressure_source)
+      return;
 
     dispatch_source_set_event_handler(m_memory_pressure_source, ^{
       dispatch_source_memorypressure_flags_t pressureLevel =
@@ -45,7 +48,12 @@ class MemoryMonitorDarwin : public MemoryMonitor {
     });
   }
 
-  void Stop() override { dispatch_source_cancel(m_memory_pressure_source); }
+  void Stop() override {
+    if (m_memory_pressure_source) {
+      dispatch_source_cancel(m_memory_pressure_source);
+      dispatch_release(m_memory_pressure_source);
+    }
+  }
 
 private:
   dispatch_source_t m_memory_pressure_source;

>From 05632355c720cb80891d13acc174d5a86ea0d823 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jonas at devlieghere.com>
Date: Mon, 3 Mar 2025 17:02:04 -0600
Subject: [PATCH 3/5] Move MemoryMonitor into Host

---
 .../lldb/Host}/MemoryMonitor.h                |  8 +--
 lldb/source/Host/CMakeLists.txt               |  3 +-
 .../Host/common}/MemoryMonitor.cpp            | 50 ++----------------
 lldb/source/Host/macosx/objcxx/CMakeLists.txt |  1 +
 .../Host/macosx/objcxx/MemoryMonitorMacOSX.mm | 51 +++++++++++++++++++
 lldb/tools/lldb-dap/CMakeLists.txt            |  1 -
 lldb/tools/lldb-dap/lldb-dap.cpp              |  7 +--
 7 files changed, 66 insertions(+), 55 deletions(-)
 rename lldb/{tools/lldb-dap => include/lldb/Host}/MemoryMonitor.h (87%)
 rename lldb/{tools/lldb-dap => source/Host/common}/MemoryMonitor.cpp (60%)
 create mode 100644 lldb/source/Host/macosx/objcxx/MemoryMonitorMacOSX.mm

diff --git a/lldb/tools/lldb-dap/MemoryMonitor.h b/lldb/include/lldb/Host/MemoryMonitor.h
similarity index 87%
rename from lldb/tools/lldb-dap/MemoryMonitor.h
rename to lldb/include/lldb/Host/MemoryMonitor.h
index e07c3bde9e85c..504f5f9cba96b 100644
--- a/lldb/tools/lldb-dap/MemoryMonitor.h
+++ b/lldb/include/lldb/Host/MemoryMonitor.h
@@ -6,13 +6,13 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef LLDB_TOOLS_LLDB_DAP_WATCHPOINT_H
-#define LLDB_TOOLS_LLDB_DAP_WATCHPOINT_H
+#ifndef LLDB_HOST_MEMORYMONITOR_H
+#define LLDB_HOST_MEMORYMONITOR_H
 
 #include <functional>
 #include <memory>
 
-namespace lldb_dap {
+namespace lldb_private {
 
 class MemoryMonitor {
 public:
@@ -36,6 +36,6 @@ class MemoryMonitor {
   Callback m_callback;
 };
 
-} // namespace lldb_dap
+} // namespace lldb_private
 
 #endif
diff --git a/lldb/source/Host/CMakeLists.txt b/lldb/source/Host/CMakeLists.txt
index cdfb6184f2219..f4be151756b3b 100644
--- a/lldb/source/Host/CMakeLists.txt
+++ b/lldb/source/Host/CMakeLists.txt
@@ -27,6 +27,7 @@ add_host_subdirectory(common
   common/LockFileBase.cpp
   common/LZMA.cpp
   common/MainLoopBase.cpp
+  common/MemoryMonitor.cpp
   common/MonitoringProcessLauncher.cpp
   common/NativeProcessProtocol.cpp
   common/NativeRegisterContext.cpp
@@ -136,7 +137,7 @@ else()
   elseif (CMAKE_SYSTEM_NAME MATCHES "AIX")
     add_host_subdirectory(aix
       aix/HostInfoAIX.cpp
-      )    
+      )
   endif()
 endif()
 
diff --git a/lldb/tools/lldb-dap/MemoryMonitor.cpp b/lldb/source/Host/common/MemoryMonitor.cpp
similarity index 60%
rename from lldb/tools/lldb-dap/MemoryMonitor.cpp
rename to lldb/source/Host/common/MemoryMonitor.cpp
index a9118a89a82ac..7fa774b638415 100644
--- a/lldb/tools/lldb-dap/MemoryMonitor.cpp
+++ b/lldb/source/Host/common/MemoryMonitor.cpp
@@ -6,59 +6,20 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "MemoryMonitor.h"
+#include "lldb/Host/MemoryMonitor.h"
 #include "llvm/ADT/ScopeExit.h"
 #include <atomic>
 #include <cstdio>
 #include <cstring>
 #include <thread>
 
-#if defined(__APPLE__)
-#include <dispatch/dispatch.h>
-#endif
-
 #if defined(__linux__)
 #include <fcntl.h>
 #include <poll.h>
 #include <unistd.h>
 #endif
 
-using namespace lldb_dap;
-
-#if defined(__APPLE__)
-class MemoryMonitorDarwin : public MemoryMonitor {
-  using MemoryMonitor::MemoryMonitor;
-  void Start() override {
-    m_memory_pressure_source = dispatch_source_create(
-        DISPATCH_SOURCE_TYPE_MEMORYPRESSURE,
-        0, // system-wide monitoring
-        DISPATCH_MEMORYPRESSURE_WARN | DISPATCH_MEMORYPRESSURE_CRITICAL,
-        dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
-
-    if (!m_memory_pressure_source)
-      return;
-
-    dispatch_source_set_event_handler(m_memory_pressure_source, ^{
-      dispatch_source_memorypressure_flags_t pressureLevel =
-          dispatch_source_get_data(m_memory_pressure_source);
-      if (pressureLevel &
-          (DISPATCH_MEMORYPRESSURE_WARN | DISPATCH_MEMORYPRESSURE_CRITICAL)) {
-        m_callback();
-      }
-    });
-  }
-
-  void Stop() override {
-    if (m_memory_pressure_source) {
-      dispatch_source_cancel(m_memory_pressure_source);
-      dispatch_release(m_memory_pressure_source);
-    }
-  }
-
-private:
-  dispatch_source_t m_memory_pressure_source;
-};
-#endif
+using namespace lldb_private;
 
 #if defined(__linux__)
 static void MonitorThread(std::atomic<bool> &done,
@@ -109,14 +70,11 @@ class MemoryMonitorLinux : public MemoryMonitor {
 };
 #endif
 
+#if !defined(__APPLE__)
 std::unique_ptr<MemoryMonitor> MemoryMonitor::Create(Callback callback) {
-#if defined(__APPLE__)
-  return std::make_unique<MemoryMonitorDarwin>(callback);
-#endif
-
 #if defined(__linux__)
   return std::make_unique<MemoryMonitorLinux>(callback);
 #endif
-
   return nullptr;
 }
+#endif
diff --git a/lldb/source/Host/macosx/objcxx/CMakeLists.txt b/lldb/source/Host/macosx/objcxx/CMakeLists.txt
index 1e693bed12ce1..cda8269ca9efd 100644
--- a/lldb/source/Host/macosx/objcxx/CMakeLists.txt
+++ b/lldb/source/Host/macosx/objcxx/CMakeLists.txt
@@ -6,6 +6,7 @@ add_lldb_library(lldbHostMacOSXObjCXX NO_PLUGIN_DEPENDENCIES
   Host.mm
   HostInfoMacOSX.mm
   HostThreadMacOSX.mm
+  MemoryMonitorMacOSX.mm
 
   LINK_LIBS
     lldbUtility
diff --git a/lldb/source/Host/macosx/objcxx/MemoryMonitorMacOSX.mm b/lldb/source/Host/macosx/objcxx/MemoryMonitorMacOSX.mm
new file mode 100644
index 0000000000000..cb6c2457df1e3
--- /dev/null
+++ b/lldb/source/Host/macosx/objcxx/MemoryMonitorMacOSX.mm
@@ -0,0 +1,51 @@
+//===-- MemoryMonitorMacOSX.mm --------------------------------------------===//
+//
+// 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 "lldb/Host/MemoryMonitor.h"
+#include <cassert>
+#include <dispatch/dispatch.h>
+
+using namespace lldb_private;
+
+class MemoryMonitorMacOSX : public MemoryMonitor {
+  using MemoryMonitor::MemoryMonitor;
+  void Start() override {
+    m_memory_pressure_source = dispatch_source_create(
+        DISPATCH_SOURCE_TYPE_MEMORYPRESSURE, 0,
+        DISPATCH_MEMORYPRESSURE_WARN | DISPATCH_MEMORYPRESSURE_CRITICAL,
+        dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
+
+    if (!m_memory_pressure_source)
+      return;
+
+    dispatch_source_set_event_handler(m_memory_pressure_source, ^{
+      dispatch_source_memorypressure_flags_t pressureLevel =
+          dispatch_source_get_data(m_memory_pressure_source);
+      if (pressureLevel &
+          (DISPATCH_MEMORYPRESSURE_WARN | DISPATCH_MEMORYPRESSURE_CRITICAL)) {
+        m_callback();
+      }
+    });
+    dispatch_activate(m_memory_pressure_source);
+    printf("Started\n");
+  }
+
+  void Stop() override {
+    if (m_memory_pressure_source) {
+      dispatch_source_cancel(m_memory_pressure_source);
+      dispatch_release(m_memory_pressure_source);
+    }
+  }
+
+private:
+  dispatch_source_t m_memory_pressure_source;
+};
+
+std::unique_ptr<MemoryMonitor> MemoryMonitor::Create(Callback callback) {
+  return std::make_unique<MemoryMonitorMacOSX>(callback);
+}
diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt
index 8db377e31c3c6..8b3c520ec4360 100644
--- a/lldb/tools/lldb-dap/CMakeLists.txt
+++ b/lldb/tools/lldb-dap/CMakeLists.txt
@@ -36,7 +36,6 @@ add_lldb_tool(lldb-dap
   RunInTerminal.cpp
   SourceBreakpoint.cpp
   Watchpoint.cpp
-  MemoryMonitor.cpp
 
   Handler/ResponseHandler.cpp
   Handler/AttachRequestHandler.cpp
diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp
index 41405df548da2..95d0efb1eef91 100644
--- a/lldb/tools/lldb-dap/lldb-dap.cpp
+++ b/lldb/tools/lldb-dap/lldb-dap.cpp
@@ -9,7 +9,6 @@
 #include "DAP.h"
 #include "EventHelper.h"
 #include "Handler/RequestHandler.h"
-#include "MemoryMonitor.h"
 #include "RunInTerminal.h"
 #include "lldb/API/SBDebugger.h"
 #include "lldb/API/SBStream.h"
@@ -17,6 +16,7 @@
 #include "lldb/Host/File.h"
 #include "lldb/Host/MainLoop.h"
 #include "lldb/Host/MainLoopBase.h"
+#include "lldb/Host/MemoryMonitor.h"
 #include "lldb/Host/Socket.h"
 #include "lldb/Utility/Status.h"
 #include "lldb/Utility/UriParser.h"
@@ -508,8 +508,9 @@ int main(int argc, char *argv[]) {
 
   // Create a memory monitor. This can return nullptr if the host platform is
   // not supported.
-  std::unique_ptr<MemoryMonitor> memory_monitor = MemoryMonitor::Create(
-      []() { lldb::SBDebugger::MemoryPressureDetected(); });
+  std::unique_ptr<lldb_private::MemoryMonitor> memory_monitor =
+      lldb_private::MemoryMonitor::Create(
+          []() { lldb::SBDebugger::MemoryPressureDetected(); });
 
   if (memory_monitor)
     memory_monitor->Start();

>From 9209e108976bc1c321dfd9ce895d707d99b20fe5 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jonas at devlieghere.com>
Date: Mon, 3 Mar 2025 19:17:14 -0600
Subject: [PATCH 4/5] Use NativeThread and attempt a Windows implementation

---
 lldb/source/Host/common/MemoryMonitor.cpp | 106 ++++++++++++++--------
 1 file changed, 68 insertions(+), 38 deletions(-)

diff --git a/lldb/source/Host/common/MemoryMonitor.cpp b/lldb/source/Host/common/MemoryMonitor.cpp
index 7fa774b638415..9fced2684a85c 100644
--- a/lldb/source/Host/common/MemoryMonitor.cpp
+++ b/lldb/source/Host/common/MemoryMonitor.cpp
@@ -7,11 +7,16 @@
 //===----------------------------------------------------------------------===//
 
 #include "lldb/Host/MemoryMonitor.h"
+#include "lldb/Host/HostThread.h"
+#include "lldb/Host/ThreadLauncher.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
 #include "llvm/ADT/ScopeExit.h"
+#include "llvm/Support/Error.h"
 #include <atomic>
+#include <cstddef>
 #include <cstdio>
 #include <cstring>
-#include <thread>
 
 #if defined(__linux__)
 #include <fcntl.h>
@@ -19,62 +24,87 @@
 #include <unistd.h>
 #endif
 
+#if defined(_WIN32)
+#include <memoryapi.h>
+#include <synchapi.h>
+#endif
+
 using namespace lldb_private;
 
+class MemoryMonitorPoll : public MemoryMonitor {
+public:
+  using MemoryMonitor::MemoryMonitor;
+
+  lldb::thread_result_t MonitorThread() {
 #if defined(__linux__)
-static void MonitorThread(std::atomic<bool> &done,
-                          MemoryMonitor::Callback callback) {
-  struct pollfd fds;
-  fds.fd = open("/proc/pressure/memory", O_RDWR | O_NONBLOCK);
-  if (fds.fd < 0)
-    return;
-  fds.events = POLLPRI;
-
-  auto cleanup = llvm::make_scope_exit([&]() { close(fds.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)
-    return;
-
-  while (!done) {
-    int n = poll(&fds, 1, 1000);
-    if (n > 0) {
-      if (fds.revents & POLLERR)
-        return;
-      if (fds.revents & POLLPRI)
-        callback();
+    struct pollfd fds;
+    fds.fd = open("/proc/pressure/memory", O_RDWR | O_NONBLOCK);
+    if (fds.fd < 0)
+      return {};
+    fds.events = POLLPRI;
+
+    auto cleanup = llvm::make_scope_exit([&]() { close(fds.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)
+      return {};
+
+    while (!m_done) {
+      int n = poll(&fds, 1, g_timeout);
+      if (n > 0) {
+        if (fds.revents & POLLERR)
+          return {};
+        if (fds.revents & POLLPRI)
+          m_callback();
+      }
     }
-  }
-}
+#endif
 
-class MemoryMonitorLinux : public MemoryMonitor {
-public:
-  using MemoryMonitor::MemoryMonitor;
+#if defined(_WIN32)
+    HANDLE low_memory_notification =
+        CreateMemoryResourceNotification(LowMemoryResourceNotification);
+    if (!low_memory_notification)
+      return {};
+
+    while (!m_done) {
+      if (WaitForSingleObject(low_memory_notification, g_timeout) ==
+          WAIT_OBJECT_0) {
+        m_callback();
+      }
+    }
+#endif
+
+    return {};
+  }
 
   void Start() override {
-    m_memory_pressure_thread =
-        std::thread(MonitorThread, std::ref(m_done), m_callback);
+    llvm::Expected<HostThread> memory_monitor_thread =
+        ThreadLauncher::LaunchThread("lldb.debugger.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_pressure_thread.joinable()) {
+    if (m_memory_monitor_thread.IsJoinable()) {
       m_done = true;
-      m_memory_pressure_thread.join();
+      m_memory_monitor_thread.Join(nullptr);
     }
   }
 
 private:
+  static constexpr uint32_t g_timeout = 1000;
   std::atomic<bool> m_done = false;
-  std::thread m_memory_pressure_thread;
+  HostThread m_memory_monitor_thread;
 };
-#endif
 
 #if !defined(__APPLE__)
 std::unique_ptr<MemoryMonitor> MemoryMonitor::Create(Callback callback) {
-#if defined(__linux__)
-  return std::make_unique<MemoryMonitorLinux>(callback);
-#endif
-  return nullptr;
+  return std::make_unique<MemoryMonitorPoll>(callback);
 }
 #endif

>From f42780863a9dfbf66716aecf1c4c5ae0c2de7f81 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jonas at devlieghere.com>
Date: Tue, 4 Mar 2025 22:43:50 -0800
Subject: [PATCH 5/5] Include windows.h instead of memoryapi.h and synchapi.h

---
 lldb/source/Host/common/MemoryMonitor.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/lldb/source/Host/common/MemoryMonitor.cpp b/lldb/source/Host/common/MemoryMonitor.cpp
index 9fced2684a85c..932fa9c43a22c 100644
--- a/lldb/source/Host/common/MemoryMonitor.cpp
+++ b/lldb/source/Host/common/MemoryMonitor.cpp
@@ -25,8 +25,7 @@
 #endif
 
 #if defined(_WIN32)
-#include <memoryapi.h>
-#include <synchapi.h>
+#include <windows.h>
 #endif
 
 using namespace lldb_private;



More information about the lldb-commits mailing list