diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2016-08-08 09:26:50 -0400 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2016-08-08 09:27:21 -0400 |
commit | 448902f870a1673829c27afa3330c3faa73d610f (patch) | |
tree | 568a90de7f1e3ca6792ecbc012c31f6196d8686b /libs/ardour/io.cc | |
parent | fdf63ace6a655f772a46e73719de14f9dd6fb940 (diff) |
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)
Diffstat (limited to 'libs/ardour/io.cc')
-rw-r--r-- | libs/ardour/io.cc | 20 |
1 files changed, 20 insertions, 0 deletions
diff --git a/libs/ardour/io.cc b/libs/ardour/io.cc index f7e2b95eb3..f535467cbe 100644 --- a/libs/ardour/io.cc +++ b/libs/ardour/io.cc @@ -405,6 +405,7 @@ IO::ensure_ports_locked (ChanCount count, bool clear, bool& changed) #endif boost::shared_ptr<Port> port; + vector<boost::shared_ptr<Port> > deleted_ports; changed = false; @@ -418,11 +419,30 @@ IO::ensure_ports_locked (ChanCount count, bool clear, bool& changed) assert(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); 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 */ while (n_ports().get(*t) < n) { |