yinghuitan created this revision.
yinghuitan added reviewers: clayborg, labath, jingham, jdoerfert, JDevlieghere, 
kusmour, GeorgeHuyubo.
Herald added a project: All.
yinghuitan requested review of this revision.
Herald added a project: LLDB.
Herald added a subscriber: lldb-commits.

Adding a new SBDebugger::SetDestroyCallback() API.
This API can be used by any client to query for statistics/metrics before
exiting debug sessions.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D143520

Files:
  lldb/bindings/interface/SBDebugger.i
  lldb/bindings/python/python-typemaps.swig
  lldb/bindings/python/python-wrapper.swig
  lldb/include/lldb/API/SBDebugger.h
  lldb/include/lldb/API/SBDefines.h
  lldb/include/lldb/Core/Debugger.h
  lldb/include/lldb/lldb-types.h
  lldb/source/API/SBDebugger.cpp
  lldb/source/Core/Debugger.cpp
  lldb/test/API/python_api/debugger/TestDebuggerAPI.py

Index: lldb/test/API/python_api/debugger/TestDebuggerAPI.py
===================================================================
--- lldb/test/API/python_api/debugger/TestDebuggerAPI.py
+++ lldb/test/API/python_api/debugger/TestDebuggerAPI.py
@@ -30,7 +30,7 @@
         self.dbg.SetPrompt(None)
         self.dbg.SetCurrentPlatform(None)
         self.dbg.SetCurrentPlatformSDKRoot(None)
-        
+
         fresh_dbg = lldb.SBDebugger()
         self.assertEquals(len(fresh_dbg), 0)
 
@@ -146,3 +146,16 @@
         self.assertEqual(platform2.GetName(), expected_platform)
         self.assertTrue(platform2.GetWorkingDirectory().endswith("bar"),
                 platform2.GetWorkingDirectory())
+
+    def test_SetDestroyCallback(self):
+        destroy_dbg_id = None
+        def foo(dbg_id):
+            # Need nonlocal to modify closure variable.
+            nonlocal destroy_dbg_id
+            destroy_dbg_id = dbg_id
+
+        self.dbg.SetDestroyCallback(foo)
+
+        original_dbg_id = self.dbg.GetID()
+        self.dbg.Destroy(self.dbg)
+        self.assertEqual(destroy_dbg_id,  original_dbg_id)
Index: lldb/source/Core/Debugger.cpp
===================================================================
--- lldb/source/Core/Debugger.cpp
+++ lldb/source/Core/Debugger.cpp
@@ -560,6 +560,12 @@
   assert(g_debugger_list_ptr &&
          "Debugger::Terminate called without a matching Debugger::Initialize!");
 
+  if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
+    std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);
+    for (const auto &debugger : *g_debugger_list_ptr)
+      HandleDestroyCallback(debugger);
+  }
+
   if (g_thread_pool) {
     // The destructor will wait for all the threads to complete.
     delete g_thread_pool;
@@ -679,10 +685,19 @@
   return debugger_sp;
 }
 
+void Debugger::HandleDestroyCallback(const DebuggerSP &debugger_sp) {
+  if (debugger_sp->m_destroy_callback) {
+    debugger_sp->m_destroy_callback(
+        *debugger_sp, debugger_sp->m_destroy_callback_baton_sp->data());
+    debugger_sp->m_destroy_callback = nullptr;
+  }
+}
+
 void Debugger::Destroy(DebuggerSP &debugger_sp) {
   if (!debugger_sp)
     return;
 
+  HandleDestroyCallback(debugger_sp);
   CommandInterpreter &cmd_interpreter = debugger_sp->GetCommandInterpreter();
 
   if (cmd_interpreter.GetSaveSessionOnQuit()) {
@@ -1285,6 +1300,12 @@
       std::make_shared<CallbackLogHandler>(log_callback, baton);
 }
 
+void Debugger::SetDestroyCallback(
+    lldb::DebuggerDestroyCallback destroy_callback, lldb::BatonSP &baton_sp) {
+  m_destroy_callback = destroy_callback;
+  m_destroy_callback_baton_sp = baton_sp;
+}
+
 static void PrivateReportProgress(Debugger &debugger, uint64_t progress_id,
                                   const std::string &message,
                                   uint64_t completed, uint64_t total,
Index: lldb/source/API/SBDebugger.cpp
===================================================================
--- lldb/source/API/SBDebugger.cpp
+++ lldb/source/API/SBDebugger.cpp
@@ -1672,6 +1672,44 @@
   }
 }
 
+struct CallbackData {
+  SBDebuggerDestroyCallback callback;
+  void *callback_baton;
+};
+
+class SBDebuggerDestroyCallbackBaton
+    : public lldb_private::TypedBaton<CallbackData> {
+public:
+  SBDebuggerDestroyCallbackBaton(SBDebuggerDestroyCallback callback,
+                                 void *baton)
+      : TypedBaton(std::make_unique<CallbackData>()) {
+    getItem()->callback = callback;
+    getItem()->callback_baton = baton;
+  }
+
+  ~SBDebuggerDestroyCallbackBaton() = default;
+
+  static void PrivateCallback(Debugger &debugger, void *baton);
+};
+
+void SBDebugger::SetDestroyCallback(
+    lldb::SBDebuggerDestroyCallback destroy_callback, void *baton) {
+  LLDB_INSTRUMENT_VA(this, destroy_callback, baton);
+  if (m_opaque_sp) {
+    BatonSP baton_sp(
+        new SBDebuggerDestroyCallbackBaton(destroy_callback, baton));
+    return m_opaque_sp->SetDestroyCallback(
+        SBDebuggerDestroyCallbackBaton::PrivateCallback, baton_sp);
+  }
+}
+
+/*static*/ void
+SBDebuggerDestroyCallbackBaton::PrivateCallback(Debugger &debugger,
+                                                void *baton) {
+  CallbackData *data = (CallbackData *)baton;
+  data->callback(debugger.GetID(), data->callback_baton);
+}
+
 SBTrace
 SBDebugger::LoadTraceFromFile(SBError &error,
                               const SBFileSpec &trace_description_file) {
Index: lldb/include/lldb/lldb-types.h
===================================================================
--- lldb/include/lldb/lldb-types.h
+++ lldb/include/lldb/lldb-types.h
@@ -68,6 +68,8 @@
 
 namespace lldb {
 typedef void (*LogOutputCallback)(const char *, void *baton);
+typedef void (*DebuggerDestroyCallback)(lldb_private::Debugger &debugger,
+                                        void *baton);
 typedef bool (*CommandOverrideCallback)(void *baton, const char **argv);
 typedef bool (*CommandOverrideCallbackWithResult)(
     void *baton, const char **argv, lldb_private::CommandReturnObject &result);
Index: lldb/include/lldb/Core/Debugger.h
===================================================================
--- lldb/include/lldb/Core/Debugger.h
+++ lldb/include/lldb/Core/Debugger.h
@@ -450,6 +450,9 @@
 
   static void ReportSymbolChange(const ModuleSpec &module_spec);
 
+  void SetDestroyCallback(lldb::DebuggerDestroyCallback destroy_callback,
+                          lldb::BatonSP &baton_sp);
+
 protected:
   friend class CommandInterpreter;
   friend class REPL;
@@ -493,6 +496,8 @@
                                    std::optional<lldb::user_id_t> debugger_id,
                                    std::once_flag *once);
 
+  static void HandleDestroyCallback(const lldb::DebuggerSP &debugger_sp);
+
   void PrintProgress(const ProgressEventData &data);
 
   bool StartEventHandlerThread();
@@ -590,6 +595,9 @@
   llvm::once_flag m_clear_once;
   lldb::TargetSP m_dummy_target_sp;
 
+  lldb::DebuggerDestroyCallback m_destroy_callback = nullptr;
+  lldb::BatonSP m_destroy_callback_baton_sp;
+
   // Events for m_sync_broadcaster
   enum {
     eBroadcastBitEventThreadIsListening = (1 << 0),
Index: lldb/include/lldb/API/SBDefines.h
===================================================================
--- lldb/include/lldb/API/SBDefines.h
+++ lldb/include/lldb/API/SBDefines.h
@@ -110,6 +110,9 @@
 typedef bool (*SBBreakpointHitCallback)(void *baton, SBProcess &process,
                                         SBThread &thread,
                                         lldb::SBBreakpointLocation &location);
+
+typedef void (*SBDebuggerDestroyCallback)(lldb::user_id_t debugger_id,
+                                          void *baton);
 typedef void *ScriptedObject;
 }
 
Index: lldb/include/lldb/API/SBDebugger.h
===================================================================
--- lldb/include/lldb/API/SBDebugger.h
+++ lldb/include/lldb/API/SBDebugger.h
@@ -291,6 +291,9 @@
 
   void SetLoggingCallback(lldb::LogOutputCallback log_callback, void *baton);
 
+  void SetDestroyCallback(lldb::SBDebuggerDestroyCallback destroy_callback,
+                          void *baton);
+
   // DEPRECATED
   void DispatchInput(void *baton, const void *data, size_t data_len);
 
Index: lldb/bindings/python/python-wrapper.swig
===================================================================
--- lldb/bindings/python/python-wrapper.swig
+++ lldb/bindings/python/python-wrapper.swig
@@ -1038,4 +1038,16 @@
     SWIG_PYTHON_THREAD_END_BLOCK;
   }
 }
+
+// For DebuggerTerminateCallback functions
+static void LLDBSwigPythonCallPythonSBDebuggerTerminateCallback(lldb::user_id_t debugger_id,
+                                                      void *baton) {
+  if (baton != Py_None) {
+    SWIG_PYTHON_THREAD_BEGIN_BLOCK;
+    PyObject *result = PyObject_CallFunction(
+        reinterpret_cast<PyObject *>(baton), const_cast<char *>("l"), debugger_id);
+    Py_XDECREF(result);
+    SWIG_PYTHON_THREAD_END_BLOCK;
+  }
+}
 %}
Index: lldb/bindings/python/python-typemaps.swig
===================================================================
--- lldb/bindings/python/python-typemaps.swig
+++ lldb/bindings/python/python-typemaps.swig
@@ -382,6 +382,29 @@
   $1 = $1 || PyCallable_Check(reinterpret_cast<PyObject *>($input));
 }
 
+// For lldb::SBDebuggerDestroyCallback
+%typemap(in) (lldb::SBDebuggerDestroyCallback destroy_callback, void *baton) {
+  if (!($input == Py_None ||
+        PyCallable_Check(reinterpret_cast<PyObject *>($input)))) {
+    PyErr_SetString(PyExc_TypeError, "Need a callable object or None!");
+    SWIG_fail;
+  }
+
+  // FIXME (filcab): We can't currently check if our callback is already
+  // LLDBSwigPythonCallPythonSBDebuggerTerminateCallback (to DECREF the previous
+  // baton) nor can we just remove all traces of a callback, if we want to
+  // revert to a file logging mechanism.
+
+  // Don't lose the callback reference
+  Py_INCREF($input);
+  $1 = LLDBSwigPythonCallPythonSBDebuggerTerminateCallback;
+  $2 = $input;
+}
+
+%typemap(typecheck) (lldb::SBDebuggerDestroyCallback destroy_callback, void *baton) {
+  $1 = $input == Py_None;
+  $1 = $1 || PyCallable_Check(reinterpret_cast<PyObject *>($input));
+}
 
 %typemap(in) lldb::FileSP {
   PythonFile py_file(PyRefType::Borrowed, $input);
Index: lldb/bindings/interface/SBDebugger.i
===================================================================
--- lldb/bindings/interface/SBDebugger.i
+++ lldb/bindings/interface/SBDebugger.i
@@ -410,6 +410,9 @@
     static bool
     StateIsStoppedState (lldb::StateType state);
 
+    void
+    SetDestroyCallback(lldb::SBDebuggerDestroyCallback destroy_callback, void *baton);
+
     bool
     EnableLog (const char *channel, const char ** types);
 
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to