summaryrefslogtreecommitdiff
path: root/libs/ardour/io.cc
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2016-08-08 09:26:50 -0400
committerPaul Davis <paul@linuxaudiosystems.com>2016-08-08 09:27:21 -0400
commit448902f870a1673829c27afa3330c3faa73d610f (patch)
tree568a90de7f1e3ca6792ecbc012c31f6196d8686b /libs/ardour/io.cc
parentfdf63ace6a655f772a46e73719de14f9dd6fb940 (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.cc20
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) {