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.
This commit is contained in:
parent
cc82fc675b
commit
2a95d79014
|
@ -265,6 +265,7 @@ class LIBARDOUR_API PresentationInfo : public PBD::Stateful
|
||||||
color_t _color;
|
color_t _color;
|
||||||
|
|
||||||
static PBD::PropertyChange _pending_static_changes;
|
static PBD::PropertyChange _pending_static_changes;
|
||||||
|
static Glib::Threads::Mutex static_signal_lock;
|
||||||
static int _change_signal_suspended;
|
static int _change_signal_suspended;
|
||||||
static void send_static_change (const PBD::PropertyChange&);
|
static void send_static_change (const PBD::PropertyChange&);
|
||||||
};
|
};
|
||||||
|
|
|
@ -40,6 +40,7 @@ using std::string;
|
||||||
string PresentationInfo::state_node_name = X_("PresentationInfo");
|
string PresentationInfo::state_node_name = X_("PresentationInfo");
|
||||||
|
|
||||||
PBD::Signal1<void,PropertyChange const &> PresentationInfo::Change;
|
PBD::Signal1<void,PropertyChange const &> PresentationInfo::Change;
|
||||||
|
Glib::Threads::Mutex PresentationInfo::static_signal_lock;
|
||||||
int PresentationInfo::_change_signal_suspended = 0;
|
int PresentationInfo::_change_signal_suspended = 0;
|
||||||
PBD::PropertyChange PresentationInfo::_pending_static_changes;
|
PBD::PropertyChange PresentationInfo::_pending_static_changes;
|
||||||
|
|
||||||
|
@ -60,24 +61,30 @@ PresentationInfo::suspend_change_signal ()
|
||||||
void
|
void
|
||||||
PresentationInfo::unsuspend_change_signal ()
|
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
|
if (g_atomic_int_get (const_cast<gint*> (&_change_signal_suspended)) == 1) {
|
||||||
* be reset by another thread before or after we decrement.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (g_atomic_int_dec_and_test (const_cast<gint*> (&_change_signal_suspended))) {
|
if (!_pending_static_changes.empty()) {
|
||||||
if (!pc.empty()) {
|
|
||||||
_pending_static_changes.clear ();
|
|
||||||
|
|
||||||
std::cerr << "PI change (unsuspended): ";
|
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 << g_quark_to_string (*x) << ',';
|
||||||
}
|
}
|
||||||
std::cerr << '\n';
|
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<gint*>(&_change_signal_suspended), -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,6 +95,8 @@ PresentationInfo::send_static_change (const PropertyChange& what_changed)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Glib::Threads::Mutex::Lock lm (static_signal_lock);
|
||||||
|
|
||||||
if (g_atomic_int_get (&_change_signal_suspended)) {
|
if (g_atomic_int_get (&_change_signal_suspended)) {
|
||||||
_pending_static_changes.add (what_changed);
|
_pending_static_changes.add (what_changed);
|
||||||
return;
|
return;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user