JDevlieghere created this revision.
JDevlieghere added a reviewer: jingham.
Herald added a subscriber: mgorny.
Herald added a project: All.
JDevlieghere requested review of this revision.

Jim is looking into adding support for interrupts to the SB API. Part of that 
work requires clearing the interrupt bit once we return from the SB API. 
Luckily, this is already tracked by the API instrumentation. This patch adds 
the necessary interruption boilerplate to hook it up with the SB API 
instrumentation.


https://reviews.llvm.org/D133129

Files:
  lldb/include/lldb/Core/Debugger.h
  lldb/include/lldb/Utility/Instrumentation.h
  lldb/source/Core/Debugger.cpp
  lldb/source/Utility/Instrumentation.cpp
  lldb/unittests/Utility/CMakeLists.txt
  lldb/unittests/Utility/InstrumentationTest.cpp

Index: lldb/unittests/Utility/InstrumentationTest.cpp
===================================================================
--- /dev/null
+++ lldb/unittests/Utility/InstrumentationTest.cpp
@@ -0,0 +1,49 @@
+//===-- InstrumentationTest.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 "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+#include "lldb/Utility/Instrumentation.h"
+
+using namespace llvm;
+using namespace lldb_private;
+using namespace lldb_private::instrumentation;
+
+TEST(InsturmentationTest, Callback) {
+  size_t entry = 0;
+  size_t exit = 0;
+
+  Instrumenter::UnregisterCallbacks();
+
+  Instrumenter::RegisterEntryCallback([&]() { entry++; });
+  Instrumenter::RegisterExitCallback([&]() { exit++; });
+
+  EXPECT_EQ(entry, 0UL);
+  EXPECT_EQ(exit, 0UL);
+
+  {
+    Instrumenter foo("foo");
+    EXPECT_EQ(entry, 1UL);
+    EXPECT_EQ(exit, 0UL);
+  }
+
+  EXPECT_EQ(entry, 1UL);
+  EXPECT_EQ(exit, 1UL);
+
+  {
+    Instrumenter bar("bar");
+    EXPECT_EQ(entry, 2UL);
+    EXPECT_EQ(exit, 1UL);
+  }
+
+  EXPECT_EQ(entry, 2UL);
+  EXPECT_EQ(exit, 2UL);
+
+  Instrumenter::UnregisterCallbacks();
+}
Index: lldb/unittests/Utility/CMakeLists.txt
===================================================================
--- lldb/unittests/Utility/CMakeLists.txt
+++ lldb/unittests/Utility/CMakeLists.txt
@@ -13,6 +13,7 @@
   EventTest.cpp
   FileSpecTest.cpp
   FlagsTest.cpp
+  InstrumentationTest.cpp
   ListenerTest.cpp
   LogTest.cpp
   NameMatchesTest.cpp
Index: lldb/source/Utility/Instrumentation.cpp
===================================================================
--- lldb/source/Utility/Instrumentation.cpp
+++ lldb/source/Utility/Instrumentation.cpp
@@ -23,12 +23,20 @@
 // Instrument SB API calls with singposts when supported.
 static llvm::ManagedStatic<llvm::SignpostEmitter> g_api_signposts;
 
+// Callbacks for entering the instrumentation boundary.
+static std::vector<Instrumenter::Callback> g_entry_callbacks;
+
+// Callbacks for leaving the instrumentation boundary.
+static std::vector<Instrumenter::Callback> g_exit_callbacks;
+
 Instrumenter::Instrumenter(llvm::StringRef pretty_func,
                            std::string &&pretty_args)
     : m_pretty_func(pretty_func) {
   if (!g_global_boundary) {
     g_global_boundary = true;
     m_local_boundary = true;
+    for (Callback callback : g_entry_callbacks)
+      callback();
     g_api_signposts->startInterval(this, m_pretty_func);
   }
   LLDB_LOG(GetLog(LLDBLog::API), "[{0}] {1} ({2})",
@@ -39,6 +47,21 @@
 Instrumenter::~Instrumenter() {
   if (m_local_boundary) {
     g_global_boundary = false;
+    for (Callback callback : g_exit_callbacks)
+      callback();
     g_api_signposts->endInterval(this, m_pretty_func);
   }
 }
+
+void Instrumenter::RegisterEntryCallback(Instrumenter::Callback callback) {
+  g_entry_callbacks.emplace_back(std::move(callback));
+}
+
+void Instrumenter::RegisterExitCallback(Instrumenter::Callback callback) {
+  g_exit_callbacks.emplace_back(std::move(callback));
+}
+
+void Instrumenter::UnregisterCallbacks() {
+  g_entry_callbacks.clear();
+  g_exit_callbacks.clear();
+}
Index: lldb/source/Core/Debugger.cpp
===================================================================
--- lldb/source/Core/Debugger.cpp
+++ lldb/source/Core/Debugger.cpp
@@ -45,6 +45,7 @@
 #include "lldb/Target/ThreadList.h"
 #include "lldb/Utility/AnsiTerminal.h"
 #include "lldb/Utility/Event.h"
+#include "lldb/Utility/Instrumentation.h"
 #include "lldb/Utility/LLDBLog.h"
 #include "lldb/Utility/Listener.h"
 #include "lldb/Utility/Log.h"
@@ -542,6 +543,7 @@
   g_debugger_list_ptr = new DebuggerList();
   g_thread_pool = new llvm::ThreadPool(llvm::optimal_concurrency());
   g_load_plugin_callback = load_plugin_callback;
+  instrumentation::Instrumenter::RegisterExitCallback([]() { Debugger::ClearInterrupts(); });
 }
 
 void Debugger::Terminate() {
@@ -1303,6 +1305,23 @@
       std::make_shared<CallbackLogHandler>(log_callback, baton);
 }
 
+void Debugger::RequestInterrupt() {
+  m_interrupt_requested = true;
+}
+
+void Debugger::ClearInterrupt() {
+  m_interrupt_requested = false;
+}
+
+void Debugger::ClearInterrupts() {
+  if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
+    std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);
+    DebuggerList::iterator pos, end = g_debugger_list_ptr->end();
+    for (pos = g_debugger_list_ptr->begin(); pos != end; ++pos)
+      (*pos)->ClearInterrupt();
+  }
+}
+
 static void PrivateReportProgress(Debugger &debugger, uint64_t progress_id,
                                   const std::string &message,
                                   uint64_t completed, uint64_t total,
Index: lldb/include/lldb/Utility/Instrumentation.h
===================================================================
--- lldb/include/lldb/Utility/Instrumentation.h
+++ lldb/include/lldb/Utility/Instrumentation.h
@@ -81,6 +81,19 @@
   Instrumenter(llvm::StringRef pretty_func, std::string &&pretty_args = {});
   ~Instrumenter();
 
+  using Callback = std::function<void(void)>;
+
+  /// Register a callback that's called when entering the instrumentation
+  /// boundary.
+  static void RegisterEntryCallback(Callback callback);
+
+  /// Register a callback that's called when leaving the instrumentation
+  /// boundary.
+  static void RegisterExitCallback(Callback callback);
+
+  /// Unregister all entry and exit callbacks.
+  static void UnregisterCallbacks();
+
 private:
   void UpdateBoundary();
 
Index: lldb/include/lldb/Core/Debugger.h
===================================================================
--- lldb/include/lldb/Core/Debugger.h
+++ lldb/include/lldb/Core/Debugger.h
@@ -387,6 +387,15 @@
   /// Shared thread poll. Use only with ThreadPoolTaskGroup.
   static llvm::ThreadPool &GetThreadPool();
 
+  /// Request an interrupt.
+  void RequestInterrupt();
+
+  /// Clear the request for an interrupt.
+  void ClearInterrupt();
+
+  /// Clear all interrupt requests.
+  static void ClearInterrupts();
+
   /// Report warning events.
   ///
   /// Progress events will be delivered to any debuggers that have listeners
@@ -573,6 +582,8 @@
   llvm::once_flag m_clear_once;
   lldb::TargetSP m_dummy_target_sp;
 
+  bool m_interrupt_requested;
+
   // Events for m_sync_broadcaster
   enum {
     eBroadcastBitEventThreadIsListening = (1 << 0),
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to