summaryrefslogtreecommitdiff
path: root/libs/ardour/port_manager.cc
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2016-10-13 17:18:42 -0400
committerPaul Davis <paul@linuxaudiosystems.com>2016-10-13 17:18:54 -0400
commit8f9a9523d2161ee15975f5f9136ef80d4bfbf3e2 (patch)
treefa82656ffa02c7e9d8a959803f501ab95fcbd482 /libs/ardour/port_manager.cc
parent1552547f650a82487ac72615c8533fd25b4ffc39 (diff)
new scheme for managing port deletion
shared_ptr<Port> now uses a deleter functor which pushes Port* to a lock-free FIFO so that the Port is always deleted (and thus unregistered with the PortEngine/backend) in a safe context w.r.t. various callbacks in the host. Currently the auto_connect_thread in Session has been tasked with doing these deletions.
Diffstat (limited to 'libs/ardour/port_manager.cc')
-rw-r--r--libs/ardour/port_manager.cc34
1 files changed, 31 insertions, 3 deletions
diff --git a/libs/ardour/port_manager.cc b/libs/ardour/port_manager.cc
index 408e780460..f057b2ffa2 100644
--- a/libs/ardour/port_manager.cc
+++ b/libs/ardour/port_manager.cc
@@ -47,10 +47,21 @@ using std::vector;
PortManager::PortManager ()
: ports (new Ports)
, _port_remove_in_progress (false)
+ , _port_deletions_pending (8192) /* ick, arbitrary sizing */
{
}
void
+PortManager::clear_pending_port_deletions ()
+{
+ Port* p;
+
+ while (_port_deletions_pending.read (&p, 1) == 1) {
+ delete p;
+ }
+}
+
+void
PortManager::remove_all_ports ()
{
/* make sure that JACK callbacks that will be invoked as we cleanup
@@ -72,6 +83,13 @@ PortManager::remove_all_ports ()
ports.flush ();
+ /* clear out pending port deletion list. we know this is safe because
+ * the auto connect thread in Session is already dead when this is
+ * done. It doesn't use shared_ptr<Port> anyway.
+ */
+
+ _port_deletions_pending.reset ();
+
_port_remove_in_progress = false;
}
@@ -300,6 +318,13 @@ PortManager::port_registration_failure (const std::string& portname)
throw PortRegistrationFailure (string_compose (_("AudioEngine: cannot register port \"%1\": %2"), portname, reason).c_str());
}
+struct PortDeleter
+{
+ void operator() (Port* p) {
+ AudioEngine::instance()->add_pending_port_deletion (p);
+ }
+};
+
boost::shared_ptr<Port>
PortManager::register_port (DataType dtype, const string& portname, bool input, bool async, PortFlags flags)
{
@@ -313,16 +338,19 @@ PortManager::register_port (DataType dtype, const string& portname, bool input,
if (dtype == DataType::AUDIO) {
DEBUG_TRACE (DEBUG::Ports, string_compose ("registering AUDIO port %1, input %2\n",
portname, input));
- newport.reset (new AudioPort (portname, PortFlags ((input ? IsInput : IsOutput) | flags)));
+ newport.reset (new AudioPort (portname, PortFlags ((input ? IsInput : IsOutput) | flags)),
+ PortDeleter());
} else if (dtype == DataType::MIDI) {
if (async) {
DEBUG_TRACE (DEBUG::Ports, string_compose ("registering ASYNC MIDI port %1, input %2\n",
portname, input));
- newport.reset (new AsyncMIDIPort (portname, PortFlags ((input ? IsInput : IsOutput) | flags)));
+ newport.reset (new AsyncMIDIPort (portname, PortFlags ((input ? IsInput : IsOutput) | flags)),
+ PortDeleter());
} else {
DEBUG_TRACE (DEBUG::Ports, string_compose ("registering MIDI port %1, input %2\n",
portname, input));
- newport.reset (new MidiPort (portname, PortFlags ((input ? IsInput : IsOutput) | flags)));
+ newport.reset (new MidiPort (portname, PortFlags ((input ? IsInput : IsOutput) | flags)),
+ PortDeleter());
}
} else {
throw PortRegistrationFailure("unable to create port (unknown type)");