diff --git a/libs/pbd/pbd/signals.h b/libs/pbd/pbd/signals.h index a9393ea75e..91943707f4 100644 --- a/libs/pbd/pbd/signals.h +++ b/libs/pbd/pbd/signals.h @@ -67,9 +67,7 @@ public: , _debug_connection (false) #endif {} - virtual ~SignalBase () { - Glib::Threads::Mutex::Lock lm (_destruct); - } + virtual ~SignalBase () { } virtual void disconnect (boost::shared_ptr) = 0; #ifdef DEBUG_PBD_SIGNAL_CONNECTIONS void set_debug_connection (bool yn) { _debug_connection = yn; } @@ -77,7 +75,6 @@ public: protected: mutable Glib::Threads::Mutex _mutex; - Glib::Threads::Mutex _destruct; std::atomic _in_dtor; #ifdef DEBUG_PBD_SIGNAL_CONNECTIONS bool _debug_connection; @@ -98,10 +95,15 @@ public: void disconnect () { + Glib::Threads::Mutex::Lock lm (_mutex); SignalBase* signal = _signal.exchange (0, std::memory_order_acq_rel); if (signal) { - /* This will lock Signal::_mutex, or return - * immediately if Signal is being destructed + /* It is safe to assume that signal has not been destructed. + * If ~Signal d'tor runs, it will call our signal_going_away() + * which will block until we're done here. + * + * This will lock Signal::_mutex, and call disconnected () + * or return immediately if Signal is being destructed. */ signal->disconnect (shared_from_this ()); } @@ -117,7 +119,16 @@ public: void signal_going_away () { /* called with Signal::_mutex held */ - (void*) _signal.exchange (0, std::memory_order_acq_rel); + if (!_signal.exchange (0, std::memory_order_acq_rel)) { + /* disconnect () grabbed the signal, but signal->disconnect() + * has not [yet] removed the entry from the list. + * + * Allow disconnect () to complete, which will + * be an effective NO-OP since SignalBase::_in_dtor is true, + * then we can proceed. + */ + Glib::Threads::Mutex::Lock lm (_mutex); + } if (_invalidation_record) { _invalidation_record->unref (); } diff --git a/libs/pbd/pbd/signals.py b/libs/pbd/pbd/signals.py index ac52124bde..34aab19ba6 100644 --- a/libs/pbd/pbd/signals.py +++ b/libs/pbd/pbd/signals.py @@ -308,9 +308,6 @@ def signal(f, n, v): print(""" \tvoid disconnect (boost::shared_ptr c) \t{ -\t\t/* Prevent destruction to complete before this method returns */ -\t\tGlib::Threads::Mutex::Lock lx (_destruct); - \t\t/* ~ScopedConnection can call this concurrently with our d'tor */ \t\tif (!_in_dtor.load (std::memory_order_acquire)) { \t\t\tGlib::Threads::Mutex::Lock lm (_mutex);