mgorny created this revision.
mgorny added reviewers: labath, emaste, krytarowski.
mgorny requested review of this revision.

Support registering multiple callbacks for a single signal.  This is
necessary to support multiple co-existing native process instances, with
separate SIGCHLD handlers.

Since std::function does not support equality comparison,
RegisterSignal() now accepts an optional argument to define identifier
for the callback.  If multiple handlers for the same signal are expeted
to be registered, unique identifiers are used to distinguish between
them.

The system signal handler is registered on first request, additional
callback are added on subsequent requests.  The system signal handler
is removed when last callback is unregistered.


https://reviews.llvm.org/D100418

Files:
  lldb/include/lldb/Host/MainLoop.h
  lldb/source/Host/common/MainLoop.cpp
  lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp

Index: lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
===================================================================
--- lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
+++ lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
@@ -301,7 +301,7 @@
 
   Status status;
   m_sigchld_handle = mainloop.RegisterSignal(
-      SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, status);
+      SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, status, this);
   assert(m_sigchld_handle && status.Success());
 
   for (const auto &tid : tids) {
Index: lldb/source/Host/common/MainLoop.cpp
===================================================================
--- lldb/source/Host/common/MainLoop.cpp
+++ lldb/source/Host/common/MainLoop.cpp
@@ -296,19 +296,24 @@
 
 // We shall block the signal, then install the signal handler. The signal will
 // be unblocked in the Run() function to check for signal delivery.
-MainLoop::SignalHandleUP
-MainLoop::RegisterSignal(int signo, const Callback &callback, Status &error) {
+MainLoop::SignalHandleUP MainLoop::RegisterSignal(int signo,
+                                                  const Callback &callback,
+                                                  Status &error,
+                                                  void *callback_id) {
 #ifdef SIGNAL_POLLING_UNSUPPORTED
   error.SetErrorString("Signal polling is not supported on this platform.");
   return nullptr;
 #else
-  if (m_signals.find(signo) != m_signals.end()) {
-    error.SetErrorStringWithFormat("Signal %d already monitored.", signo);
-    return nullptr;
+  auto signal_it = m_signals.find(signo);
+  if (signal_it != m_signals.end()) {
+    assert(signal_it->second.callbacks.find(callback_id) ==
+           signal_it->second.callbacks.end());
+    signal_it->second.callbacks[callback_id] = callback;
+    return SignalHandleUP(new SignalHandle(*this, signo, callback_id));
   }
 
   SignalInfo info;
-  info.callback = callback;
+  info.callbacks[callback_id] = callback;
   struct sigaction new_action;
   new_action.sa_sigaction = &SignalHandler;
   new_action.sa_flags = SA_SIGINFO;
@@ -340,7 +345,7 @@
   info.was_blocked = sigismember(&old_set, signo);
   m_signals.insert({signo, info});
 
-  return SignalHandleUP(new SignalHandle(*this, signo));
+  return SignalHandleUP(new SignalHandle(*this, signo, callback_id));
 #endif
 }
 
@@ -350,13 +355,21 @@
   assert(erased);
 }
 
-void MainLoop::UnregisterSignal(int signo) {
+void MainLoop::UnregisterSignal(int signo, void *callback_id) {
 #if SIGNAL_POLLING_UNSUPPORTED
   Status("Signal polling is not supported on this platform.");
 #else
   auto it = m_signals.find(signo);
   assert(it != m_signals.end());
 
+  auto cb_it = it->second.callbacks.find(callback_id);
+  assert(cb_it != it->second.callbacks.end());
+  it->second.callbacks.erase(cb_it);
+
+  // Do not remove the signal handler unless all callbacks have been erased.
+  if (!it->second.callbacks.empty())
+    return;
+
   sigaction(signo, &it->second.old_action, nullptr);
 
   sigset_t set;
@@ -398,8 +411,15 @@
 
 void MainLoop::ProcessSignal(int signo) {
   auto it = m_signals.find(signo);
-  if (it != m_signals.end())
-    it->second.callback(*this); // Do the work
+  if (it != m_signals.end()) {
+    // The callback may actually register/unregister signal handlers,
+    // so we need to create a copy first.
+    llvm::SmallVector<Callback, 4> callbacks_to_run;
+    for (auto &x : it->second.callbacks)
+      callbacks_to_run.push_back(x.second);
+    for (auto &x : callbacks_to_run)
+      x(*this); // Do the work
+  }
 }
 
 void MainLoop::ProcessReadObject(IOObject::WaitableHandle handle) {
Index: lldb/include/lldb/Host/MainLoop.h
===================================================================
--- lldb/include/lldb/Host/MainLoop.h
+++ lldb/include/lldb/Host/MainLoop.h
@@ -56,7 +56,7 @@
   // handler. However, since the callback is not invoked synchronously, you
   // cannot use this mechanism to handle SIGSEGV and the like.
   SignalHandleUP RegisterSignal(int signo, const Callback &callback,
-                                Status &error);
+                                Status &error, void *callback_id = nullptr);
 
   Status Run() override;
 
@@ -68,7 +68,7 @@
 protected:
   void UnregisterReadObject(IOObject::WaitableHandle handle) override;
 
-  void UnregisterSignal(int signo);
+  void UnregisterSignal(int signo, void *callback_id);
 
 private:
   void ProcessReadObject(IOObject::WaitableHandle handle);
@@ -76,14 +76,15 @@
 
   class SignalHandle {
   public:
-    ~SignalHandle() { m_mainloop.UnregisterSignal(m_signo); }
+    ~SignalHandle() { m_mainloop.UnregisterSignal(m_signo, m_callback_id); }
 
   private:
-    SignalHandle(MainLoop &mainloop, int signo)
-        : m_mainloop(mainloop), m_signo(signo) {}
+    SignalHandle(MainLoop &mainloop, int signo, void *callback_id)
+        : m_mainloop(mainloop), m_signo(signo), m_callback_id(callback_id) {}
 
     MainLoop &m_mainloop;
     int m_signo;
+    void *m_callback_id;
 
     friend class MainLoop;
     SignalHandle(const SignalHandle &) = delete;
@@ -91,7 +92,7 @@
   };
 
   struct SignalInfo {
-    Callback callback;
+    llvm::DenseMap<void*, Callback> callbacks;
 #if HAVE_SIGACTION
     struct sigaction old_action;
 #endif
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to