13
0

fix race condition when dropping Ports

Jack2 calls back from a notification thread and the callback (PortManager::connect_callback())
could end up holding the final reference on 1 or more ports. The ports would then be
unregistered as we leave the callback scope, which is illegal (no server calls from
a notification thread)
This commit is contained in:
Paul Davis 2016-08-08 09:26:50 -04:00
parent fdf63ace6a
commit 448902f870

View File

@ -405,6 +405,7 @@ IO::ensure_ports_locked (ChanCount count, bool clear, bool& changed)
#endif #endif
boost::shared_ptr<Port> port; boost::shared_ptr<Port> port;
vector<boost::shared_ptr<Port> > deleted_ports;
changed = false; changed = false;
@ -418,11 +419,30 @@ IO::ensure_ports_locked (ChanCount count, bool clear, bool& changed)
assert(port); assert(port);
_ports.remove(port); _ports.remove(port);
/* hold a reference to the port so that we can ensure
* that this thread, and not a JACK notification thread,
* holds the final reference.
*/
deleted_ports.push_back (port);
_session.engine().unregister_port (port); _session.engine().unregister_port (port);
changed = true; changed = true;
} }
/* this will drop the final reference to the deleted ports,
* which will in turn call their destructors, which will in
* turn call the backend to unregister them.
*
* There will no connect/disconnect or register/unregister
* callbacks from the backend until we get here, because
* they are driven by the Port destructor. The destructor
* will not execute until we drop the final reference,
* which all happens right .... here.
*/
deleted_ports.clear ();
/* create any necessary new ports */ /* create any necessary new ports */
while (n_ports().get(*t) < n) { while (n_ports().get(*t) < n) {