Cont'd work on concurrent Signal, Connection destruction

See also 7580d6aba7
This commit is contained in:
Robin Gareus 2021-11-21 03:22:26 +01:00
parent 031b858f47
commit 992c727959
No known key found for this signature in database
GPG key ID: A090BCE02CF57F04
2 changed files with 18 additions and 10 deletions

View file

@ -67,9 +67,7 @@ public:
, _debug_connection (false) , _debug_connection (false)
#endif #endif
{} {}
virtual ~SignalBase () { virtual ~SignalBase () { }
Glib::Threads::Mutex::Lock lm (_destruct);
}
virtual void disconnect (boost::shared_ptr<Connection>) = 0; virtual void disconnect (boost::shared_ptr<Connection>) = 0;
#ifdef DEBUG_PBD_SIGNAL_CONNECTIONS #ifdef DEBUG_PBD_SIGNAL_CONNECTIONS
void set_debug_connection (bool yn) { _debug_connection = yn; } void set_debug_connection (bool yn) { _debug_connection = yn; }
@ -77,7 +75,6 @@ public:
protected: protected:
mutable Glib::Threads::Mutex _mutex; mutable Glib::Threads::Mutex _mutex;
Glib::Threads::Mutex _destruct;
std::atomic<bool> _in_dtor; std::atomic<bool> _in_dtor;
#ifdef DEBUG_PBD_SIGNAL_CONNECTIONS #ifdef DEBUG_PBD_SIGNAL_CONNECTIONS
bool _debug_connection; bool _debug_connection;
@ -98,10 +95,15 @@ public:
void disconnect () void disconnect ()
{ {
Glib::Threads::Mutex::Lock lm (_mutex);
SignalBase* signal = _signal.exchange (0, std::memory_order_acq_rel); SignalBase* signal = _signal.exchange (0, std::memory_order_acq_rel);
if (signal) { if (signal) {
/* This will lock Signal::_mutex, or return /* It is safe to assume that signal has not been destructed.
* immediately if Signal is being 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 ()); signal->disconnect (shared_from_this ());
} }
@ -117,7 +119,16 @@ public:
void signal_going_away () void signal_going_away ()
{ {
/* called with Signal::_mutex held */ /* 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) { if (_invalidation_record) {
_invalidation_record->unref (); _invalidation_record->unref ();
} }

View file

@ -308,9 +308,6 @@ def signal(f, n, v):
print(""" print("""
\tvoid disconnect (boost::shared_ptr<Connection> c) \tvoid disconnect (boost::shared_ptr<Connection> c)
\t{ \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\t/* ~ScopedConnection can call this concurrently with our d'tor */
\t\tif (!_in_dtor.load (std::memory_order_acquire)) { \t\tif (!_in_dtor.load (std::memory_order_acquire)) {
\t\t\tGlib::Threads::Mutex::Lock lm (_mutex); \t\t\tGlib::Threads::Mutex::Lock lm (_mutex);