Index: lldb/include/lldb/Host/MainLoop.h =================================================================== --- lldb/include/lldb/Host/MainLoop.h +++ lldb/include/lldb/Host/MainLoop.h @@ -13,6 +13,7 @@ #include "lldb/Host/MainLoopBase.h" #include "llvm/ADT/DenseMap.h" #include +#include #if !HAVE_PPOLL && !HAVE_SYS_EVENT_H && !defined(__ANDROID__) #define SIGNAL_POLLING_UNSUPPORTED 1 @@ -68,7 +69,7 @@ protected: void UnregisterReadObject(IOObject::WaitableHandle handle) override; - void UnregisterSignal(int signo); + void UnregisterSignal(int signo, std::list::iterator callback_it); private: void ProcessReadObject(IOObject::WaitableHandle handle); @@ -76,14 +77,16 @@ class SignalHandle { public: - ~SignalHandle() { m_mainloop.UnregisterSignal(m_signo); } + ~SignalHandle() { m_mainloop.UnregisterSignal(m_signo, m_callback_it); } private: - SignalHandle(MainLoop &mainloop, int signo) - : m_mainloop(mainloop), m_signo(signo) {} + SignalHandle(MainLoop &mainloop, int signo, + std::list::iterator callback_it) + : m_mainloop(mainloop), m_signo(signo), m_callback_it(callback_it) {} MainLoop &m_mainloop; int m_signo; + std::list::iterator m_callback_it; friend class MainLoop; SignalHandle(const SignalHandle &) = delete; @@ -91,7 +94,7 @@ }; struct SignalInfo { - Callback callback; + std::list callbacks; #if HAVE_SIGACTION struct sigaction old_action; #endif Index: lldb/source/Host/common/MainLoop.cpp =================================================================== --- lldb/source/Host/common/MainLoop.cpp +++ lldb/source/Host/common/MainLoop.cpp @@ -302,13 +302,15 @@ 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()) { + auto callback_it = signal_it->second.callbacks.insert( + signal_it->second.callbacks.end(), callback); + return SignalHandleUP(new SignalHandle(*this, signo, callback_it)); } SignalInfo info; - info.callback = callback; + info.callbacks.push_back(callback); struct sigaction new_action; new_action.sa_sigaction = &SignalHandler; new_action.sa_flags = SA_SIGINFO; @@ -338,9 +340,10 @@ &new_action.sa_mask, &old_set); assert(ret == 0 && "pthread_sigmask failed"); info.was_blocked = sigismember(&old_set, signo); - m_signals.insert({signo, info}); + auto insert_ret = m_signals.insert({signo, info}); - return SignalHandleUP(new SignalHandle(*this, signo)); + return SignalHandleUP( + new SignalHandle(*this, signo, insert_ret.first->second.callbacks.begin())); #endif } @@ -350,13 +353,19 @@ assert(erased); } -void MainLoop::UnregisterSignal(int signo) { +void MainLoop::UnregisterSignal(int signo, + std::list::iterator callback_it) { #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()); + it->second.callbacks.erase(callback_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 +407,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 callbacks_to_run; + for (auto &x : it->second.callbacks) + callbacks_to_run.push_back(x); + for (auto &x : callbacks_to_run) + x(*this); // Do the work + } } void MainLoop::ProcessReadObject(IOObject::WaitableHandle handle) {