From 2a95d79014c6c7dcef73c8cae083c2e34c7bb811 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Fri, 27 Jan 2017 22:15:10 +0100 Subject: use a lock when dealing with PresentationInfo::Change emission This allows us to emit the signal while still marking further emissions as blocked. This in turns prevents handlers from recursively calling themselves. --- libs/ardour/ardour/presentation_info.h | 1 + libs/ardour/presentation_info.cc | 27 ++++++++++++++++++--------- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/libs/ardour/ardour/presentation_info.h b/libs/ardour/ardour/presentation_info.h index aa94cfd7aa..6984930f3d 100644 --- a/libs/ardour/ardour/presentation_info.h +++ b/libs/ardour/ardour/presentation_info.h @@ -265,6 +265,7 @@ class LIBARDOUR_API PresentationInfo : public PBD::Stateful color_t _color; static PBD::PropertyChange _pending_static_changes; + static Glib::Threads::Mutex static_signal_lock; static int _change_signal_suspended; static void send_static_change (const PBD::PropertyChange&); }; diff --git a/libs/ardour/presentation_info.cc b/libs/ardour/presentation_info.cc index 45acef2963..31f595a8c2 100644 --- a/libs/ardour/presentation_info.cc +++ b/libs/ardour/presentation_info.cc @@ -40,6 +40,7 @@ using std::string; string PresentationInfo::state_node_name = X_("PresentationInfo"); PBD::Signal1 PresentationInfo::Change; +Glib::Threads::Mutex PresentationInfo::static_signal_lock; int PresentationInfo::_change_signal_suspended = 0; PBD::PropertyChange PresentationInfo::_pending_static_changes; @@ -60,24 +61,30 @@ PresentationInfo::suspend_change_signal () void PresentationInfo::unsuspend_change_signal () { - PropertyChange pc = _pending_static_changes; + Glib::Threads::Mutex::Lock lm (static_signal_lock); - /* XXX some possible race condition here; _pending_static_changes could - * be reset by another thread before or after we decrement. - */ + if (g_atomic_int_get (const_cast (&_change_signal_suspended)) == 1) { - if (g_atomic_int_dec_and_test (const_cast (&_change_signal_suspended))) { - if (!pc.empty()) { - _pending_static_changes.clear (); + if (!_pending_static_changes.empty()) { std::cerr << "PI change (unsuspended): "; - for (PropertyChange::const_iterator x = pc.begin(); x != pc.end(); ++x) { + for (PropertyChange::const_iterator x = _pending_static_changes.begin(); x != _pending_static_changes.end(); ++x) { std::cerr << g_quark_to_string (*x) << ','; } std::cerr << '\n'; - Change (pc); /* EMIT SIGNAL */ + /* emit the signal with further emissions still + * blocked, so that if the handlers modify other PI + * states, the signal for that won't be sent while + * they are handling this one. + */ + + Change (_pending_static_changes); /* EMIT SIGNAL */ + + _pending_static_changes.clear (); } + + g_atomic_int_add (const_cast(&_change_signal_suspended), -1); } } @@ -88,6 +95,8 @@ PresentationInfo::send_static_change (const PropertyChange& what_changed) return; } + Glib::Threads::Mutex::Lock lm (static_signal_lock); + if (g_atomic_int_get (&_change_signal_suspended)) { _pending_static_changes.add (what_changed); return; -- cgit v1.2.3