never send signals while nodes are still locked

A signal emitted and received in the same thread will call other functions
before returning to the one that emitted the signal. If these other functions
try to lock a mutex while a mutex is already locked by the emitting function,
we get stuck in a deadlock. These changes ensure that a signal is never emitted
by any function until all the nodes locked by it are unlocked.
This commit is contained in:
itsmattkc
2019-11-23 17:04:33 +09:00
parent cb5d816145
commit 1bc8a20425
2 changed files with 35 additions and 10 deletions
+6 -3
View File
@@ -178,16 +178,19 @@ const rational &Block::media_in()
void Block::set_media_in(const rational &media_in)
{
LockUserInput();
bool changed = false;
LockUserInput();
if (media_in_ != media_in) {
media_in_ = media_in;
changed = true;
}
UnlockUserInput();
if (changed) {
// Signal that this clips contents have changed
SendInvalidateCache(in(), out());
}
UnlockUserInput();
}
const QString &Block::block_name()
+29 -7
View File
@@ -132,6 +132,10 @@ void NodeInput::set_value_at_time(const rational &time, const QVariant &value)
if (parent() != nullptr)
parent()->LockUserInput();
// We set up these variables in advance (see end of function)
bool signal_vc = false;
TimeRange signal_vc_range;
if (is_keyframing()) {
// Insert value into the keyframe list chronologically
@@ -145,7 +149,8 @@ void NodeInput::set_value_at_time(const rational &time, const QVariant &value)
// Value has changed since the earliest point up until the ex-first keyframe (since the frames
// interpolating between the key we're adding and the key that existed are changing too)
emit ValueChanged(RATIONAL_MIN, existing_first_key);
signal_vc = true;
signal_vc_range = TimeRange(RATIONAL_MIN, existing_first_key);
} else if (keyframes_.first().time() == time) {
@@ -153,7 +158,8 @@ void NodeInput::set_value_at_time(const rational &time, const QVariant &value)
keyframes_.first().set_value(value);
// Value has changed since the earliest point up until the keyframe we just changed
emit ValueChanged(RATIONAL_MIN, time);
signal_vc = true;
signal_vc_range = TimeRange(RATIONAL_MIN, time);
} else if (keyframes_.last().time() < time) {
@@ -165,7 +171,8 @@ void NodeInput::set_value_at_time(const rational &time, const QVariant &value)
// Value has changed since the ex-last point up until the latest possible point (since the frames
// interpolating between the key we're adding and the key that existed are changing too)
emit ValueChanged(existing_last_key, RATIONAL_MAX);
signal_vc = true;
signal_vc_range = TimeRange(existing_last_key, RATIONAL_MAX);
} else if (keyframes_.last().time() == time) {
@@ -173,7 +180,8 @@ void NodeInput::set_value_at_time(const rational &time, const QVariant &value)
keyframes_.last().set_value(value);
// Value has changed from this point until the latest possible point
emit ValueChanged(time, RATIONAL_MAX);
signal_vc = true;
signal_vc_range = TimeRange(time, RATIONAL_MAX);
} else {
for (int i=0;i<keyframes_.size()-1;i++) {
@@ -185,14 +193,16 @@ void NodeInput::set_value_at_time(const rational &time, const QVariant &value)
before.set_value(value);
// Values have changed since the last keyframe and the next one
emit ValueChanged(keyframes_.at(i-1).time(), keyframes_.at(i+1).time());
signal_vc = true;
signal_vc_range = TimeRange(keyframes_.at(i-1).time(), keyframes_.at(i+1).time());
break;
} else if (before.time() < time && after.time() > time) {
// Insert value in between these two keyframes
keyframes_.insert(i+1, NodeKeyframe(time, value, before.type()));
// Values have changed since the last keyframe and the next one
emit ValueChanged(before.time(), after.time());
signal_vc = true;
signal_vc_range = TimeRange(before.time(), after.time());
break;
}
}
@@ -202,11 +212,17 @@ void NodeInput::set_value_at_time(const rational &time, const QVariant &value)
keyframes_.first().set_value(value);
// Values have changed for all times since the value is static
emit ValueChanged(RATIONAL_MIN, RATIONAL_MAX);
signal_vc = true;
signal_vc_range = TimeRange(RATIONAL_MIN, RATIONAL_MAX);
}
if (parent() != nullptr)
parent()->UnlockUserInput();
// We make sure this signal is emitted AFTER we've unlocked the node in case this leads to a tangent where something
// tries to relock this node before it's unlocked here
if (signal_vc)
emit ValueChanged(signal_vc_range.in(), signal_vc_range.out());
}
const QVariant &NodeInput::value()
@@ -282,12 +298,18 @@ void NodeInput::set_maximum(const QVariant &max)
void NodeInput::CopyValues(NodeInput *source, NodeInput *dest, bool include_connections)
{
source->parent()->LockUserInput();
dest->parent()->LockUserInput();
// Copy values
dest->keyframes_ = source->keyframes_;
// Copy keyframing state
dest->set_is_keyframing(source->is_keyframing());
source->parent()->UnlockUserInput();
dest->parent()->UnlockUserInput();
// Copy connections
if (include_connections && source->get_connected_output() != nullptr) {
ConnectEdge(source->get_connected_output(), dest);