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

via lldb-commits lldb-commits at lists.llvm.org
Fri Feb 28 14:19:37 PST 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lldb

Author: Jonas Devlieghere (JDevlieghere)

<details>
<summary>Changes</summary>

This implements a memory monitor for macOS & Linux, and registers a callback that invokes SBDebugger::MemoryPressureDetected() when a low memory event is detected.

---
Full diff: https://github.com/llvm/llvm-project/pull/129332.diff


4 Files Affected:

- (modified) lldb/tools/lldb-dap/CMakeLists.txt (+1) 
- (added) lldb/tools/lldb-dap/MemoryMonitor.cpp (+114) 
- (added) lldb/tools/lldb-dap/MemoryMonitor.h (+41) 
- (modified) lldb/tools/lldb-dap/lldb-dap.cpp (+15-2) 


``````````diff
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 :

``````````

</details>


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


More information about the lldb-commits mailing list