Bind weak pointers to rt_slot events
This fixes a crash when deleting routes, while there are still automation events queued for the route. Specifically, SoloControl has a reference Soloable& _soloable; which points to the parent route. A rt-event can still hold a valid shared pointer to the SoloControl, even if the route is destroyed. Calling SoloControl::actually_set_value is fine (the control still exists due to the shared ptr), but then checking the parent route: ``` if (_soloable.is_safe() || !can_solo()) ``` accesses the already deleted route, which causes a crash. The solution implemented here is to not bind a shared_ptr to the realtime event. However, since deletion of the route happens in the main UI thread, there may or may not still be a race.
This commit is contained in:
parent
c64869596e
commit
3b9a253a84
@ -2251,7 +2251,7 @@ private:
|
||||
}
|
||||
|
||||
/* specialized version realtime "apply to set of controls" operations */
|
||||
SessionEvent* get_rt_event (boost::shared_ptr<ControlList> cl, double arg, PBD::Controllable::GroupControlDisposition group_override) {
|
||||
SessionEvent* get_rt_event (boost::shared_ptr<WeakControlList> cl, double arg, PBD::Controllable::GroupControlDisposition group_override) {
|
||||
SessionEvent* ev = new SessionEvent (SessionEvent::RealTimeOperation, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0);
|
||||
ev->rt_slot = boost::bind (&Session::rt_set_controls, this, cl, arg, group_override);
|
||||
ev->rt_return = Session::rt_cleanup;
|
||||
@ -2260,7 +2260,7 @@ private:
|
||||
return ev;
|
||||
}
|
||||
|
||||
void rt_set_controls (boost::shared_ptr<ControlList>, double val, PBD::Controllable::GroupControlDisposition group_override);
|
||||
void rt_set_controls (boost::shared_ptr<WeakControlList>, double val, PBD::Controllable::GroupControlDisposition group_override);
|
||||
void rt_clear_all_solo_state (boost::shared_ptr<RouteList>, bool yn, PBD::Controllable::GroupControlDisposition group_override);
|
||||
|
||||
void setup_midi_machine_control ();
|
||||
|
@ -638,6 +638,7 @@ typedef std::list<boost::shared_ptr<Stripable> > StripableList;
|
||||
typedef std::list<boost::weak_ptr <Route> > WeakRouteList;
|
||||
typedef std::list<boost::weak_ptr <Stripable> > WeakStripableList;
|
||||
typedef std::list<boost::shared_ptr<AutomationControl> > ControlList;
|
||||
typedef std::list<boost::weak_ptr <AutomationControl> > WeakControlList;
|
||||
typedef std::list<boost::shared_ptr<SlavableAutomationControl> > SlavableControlList;
|
||||
typedef std::set <AutomationType> AutomationTypeSet;
|
||||
|
||||
|
@ -71,12 +71,15 @@ Session::set_controls (boost::shared_ptr<ControlList> cl, double val, Controllab
|
||||
}
|
||||
#endif
|
||||
|
||||
boost::shared_ptr<WeakControlList> wcl (new WeakControlList);
|
||||
for (ControlList::iterator ci = cl->begin(); ci != cl->end(); ++ci) {
|
||||
/* as of july 2017 this is a no-op for everything except record enable */
|
||||
(*ci)->pre_realtime_queue_stuff (val, gcd);
|
||||
/* fill in weak pointer ctrl list */
|
||||
wcl->push_back (*ci);
|
||||
}
|
||||
|
||||
queue_event (get_rt_event (cl, val, gcd));
|
||||
queue_event (get_rt_event (wcl, val, gcd));
|
||||
}
|
||||
|
||||
void
|
||||
@ -92,7 +95,7 @@ Session::set_control (boost::shared_ptr<AutomationControl> ac, double val, Contr
|
||||
}
|
||||
|
||||
void
|
||||
Session::rt_set_controls (boost::shared_ptr<ControlList> cl, double val, Controllable::GroupControlDisposition gcd)
|
||||
Session::rt_set_controls (boost::shared_ptr<WeakControlList> cl, double val, Controllable::GroupControlDisposition gcd)
|
||||
{
|
||||
/* Note that we require that all controls in the ControlList are of the
|
||||
same type.
|
||||
@ -101,15 +104,21 @@ Session::rt_set_controls (boost::shared_ptr<ControlList> cl, double val, Control
|
||||
return;
|
||||
}
|
||||
|
||||
for (ControlList::iterator c = cl->begin(); c != cl->end(); ++c) {
|
||||
(*c)->set_value (val, gcd);
|
||||
AutomationType type = NullAutomation;
|
||||
|
||||
for (auto const& c : *cl) {
|
||||
boost::shared_ptr<AutomationControl> ac = c.lock ();
|
||||
if (ac) {
|
||||
ac->set_value (val, gcd);
|
||||
type = ac->desc().type;
|
||||
}
|
||||
}
|
||||
|
||||
/* some controls need global work to take place after they are set. Do
|
||||
* that here.
|
||||
*/
|
||||
|
||||
switch (cl->front()->parameter().type()) {
|
||||
switch (type) {
|
||||
case SoloAutomation:
|
||||
update_route_solo_state ();
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user