summaryrefslogtreecommitdiff
path: root/libs/backends
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2020-04-01 23:04:23 -0600
committerPaul Davis <paul@linuxaudiosystems.com>2020-04-02 19:45:31 -0600
commit9ac0d5b60f34682166954a5e70f52754ec4af671 (patch)
tree96911d0f7daf98a9ab391a742426384491a78791 /libs/backends
parent714e2f1736693fbf8281513921ef2df49b7c248b (diff)
add RCU to manage _ports and _portmap in AlsaAudioBackend
This is intended to prevent crashes when unregister_port() modifies the contents of these two members at the same time that something else is iterating over them.
Diffstat (limited to 'libs/backends')
-rw-r--r--libs/backends/alsa/alsa_audiobackend.cc112
-rw-r--r--libs/backends/alsa/alsa_audiobackend.h14
2 files changed, 94 insertions, 32 deletions
diff --git a/libs/backends/alsa/alsa_audiobackend.cc b/libs/backends/alsa/alsa_audiobackend.cc
index ae4ef51448..0d598a4192 100644
--- a/libs/backends/alsa/alsa_audiobackend.cc
+++ b/libs/backends/alsa/alsa_audiobackend.cc
@@ -75,6 +75,8 @@ AlsaAudioBackend::AlsaAudioBackend (AudioEngine& e, AudioBackendInfo& info)
, _midi_device_thread_active (false)
, _dsp_load (0)
, _processed_samples (0)
+ , _portmap (new PortMap)
+ , _ports (new PortIndex)
, _port_change_flag (false)
{
_instance_name = s_instance_name;
@@ -753,14 +755,22 @@ AlsaAudioBackend::_start (bool for_latency_measurement)
return BackendReinitializationError;
}
- if (_ports.size () || _portmap.size ()) {
- PBD::warning << _("AlsaAudioBackend: recovering from unclean shutdown, port registry is not empty.") << endmsg;
- _system_inputs.clear();
- _system_outputs.clear();
- _system_midi_in.clear();
- _system_midi_out.clear();
- _ports.clear();
- _portmap.clear();
+ {
+ RCUWriter<PortIndex> index_writer (_ports);
+ RCUWriter<PortMap> map_writer (_portmap);
+
+ boost::shared_ptr<PortIndex> ps = index_writer.get_copy();
+ boost::shared_ptr<PortMap> pm = map_writer.get_copy ();
+
+ if (ps->size () || pm->size ()) {
+ PBD::warning << _("AlsaAudioBackend: recovering from unclean shutdown, port registry is not empty.") << endmsg;
+ _system_inputs.clear();
+ _system_outputs.clear();
+ _system_midi_in.clear();
+ _system_midi_out.clear();
+ ps->clear();
+ pm->clear();
+ }
}
/* reset internal state */
@@ -1201,8 +1211,15 @@ AlsaAudioBackend::set_port_name (PortEngine::PortHandle port, const std::string&
}
AlsaPort* p = static_cast<AlsaPort*>(port);
- _portmap.erase (p->name());
- _portmap.insert (make_pair (newname, p));
+
+ {
+ RCUWriter<PortMap> map_writer (_portmap);
+ boost::shared_ptr<PortMap> pm = map_writer.get_copy ();
+
+ pm->erase (p->name());
+ pm->insert (make_pair (newname, p));
+ }
+
return p->set_name (newname);
}
@@ -1279,7 +1296,9 @@ AlsaAudioBackend::get_ports (
}
}
- for (PortIndex::const_iterator i = _ports.begin (); i != _ports.end (); ++i) {
+ boost::shared_ptr<PortIndex> p = _ports.reader ();
+
+ for (PortIndex::const_iterator i = p->begin (); i != p->end (); ++i) {
AlsaPort* port = *i;
if ((port->type () == type) && flags == (port->flags () & flags)) {
if (!use_regexp || !regexec (&port_regex, port->name ().c_str (), 0, NULL, 0)) {
@@ -1339,8 +1358,16 @@ AlsaAudioBackend::add_port (
return 0;
}
- _ports.insert (port);
- _portmap.insert (make_pair (name, port));
+ {
+ RCUWriter<PortIndex> index_writer (_ports);
+ RCUWriter<PortMap> map_writer (_portmap);
+
+ boost::shared_ptr<PortIndex> ps = index_writer.get_copy ();
+ boost::shared_ptr<PortMap> pm = map_writer.get_copy ();
+
+ ps->insert (port);
+ pm->insert (make_pair (name, port));
+ }
return port;
}
@@ -1351,15 +1378,29 @@ AlsaAudioBackend::unregister_port (PortEngine::PortHandle port_handle)
if (!_run) {
return;
}
+
AlsaPort* port = static_cast<AlsaPort*>(port_handle);
- PortIndex::iterator i = std::find (_ports.begin(), _ports.end(), static_cast<AlsaPort*>(port_handle));
- if (i == _ports.end ()) {
- PBD::error << _("AlsaBackend::unregister_port: Failed to find port") << endmsg;
- return;
+
+ {
+ RCUWriter<PortIndex> index_writer (_ports);
+ RCUWriter<PortMap> map_writer (_portmap);
+
+ boost::shared_ptr<PortIndex> ps = index_writer.get_copy ();
+ boost::shared_ptr<PortMap> pm = map_writer.get_copy ();
+
+ PortIndex::iterator i = std::find (ps->begin(), ps->end(), static_cast<AlsaPort*>(port_handle));
+
+ if (i == ps->end ()) {
+ PBD::error << _("AlsaBackend::unregister_port: Failed to find port") << endmsg;
+ return;
+ }
+
+ disconnect_all(port_handle);
+
+ pm->erase (port->name());
+ ps->erase (i);
}
- disconnect_all(port_handle);
- _portmap.erase (port->name());
- _ports.erase (i);
+
delete port;
}
@@ -1729,14 +1770,21 @@ AlsaAudioBackend::unregister_ports (bool system_only)
_system_midi_in.clear();
_system_midi_out.clear();
- for (PortIndex::iterator i = _ports.begin (); i != _ports.end ();) {
+ RCUWriter<PortIndex> index_writer (_ports);
+ RCUWriter<PortMap> map_writer (_portmap);
+
+ boost::shared_ptr<PortIndex> ps = index_writer.get_copy ();
+ boost::shared_ptr<PortMap> pm = map_writer.get_copy ();
+
+
+ for (PortIndex::iterator i = ps->begin (); i != ps->end ();) {
PortIndex::iterator cur = i++;
AlsaPort* port = *cur;
if (! system_only || (port->is_physical () && port->is_terminal ())) {
port->disconnect_all ();
- _portmap.erase (port->name());
+ pm->erase (port->name());
delete port;
- _ports.erase (cur);
+ ps->erase (cur);
}
}
}
@@ -2000,7 +2048,9 @@ AlsaAudioBackend::port_is_physical (PortEngine::PortHandle port) const
void
AlsaAudioBackend::get_physical_outputs (DataType type, std::vector<std::string>& port_names)
{
- for (PortIndex::iterator i = _ports.begin (); i != _ports.end (); ++i) {
+ boost::shared_ptr<PortIndex> p = _ports.reader();
+
+ for (PortIndex::iterator i = p->begin (); i != p->end (); ++i) {
AlsaPort* port = *i;
if ((port->type () == type) && port->is_input () && port->is_physical ()) {
port_names.push_back (port->name ());
@@ -2011,7 +2061,9 @@ AlsaAudioBackend::get_physical_outputs (DataType type, std::vector<std::string>&
void
AlsaAudioBackend::get_physical_inputs (DataType type, std::vector<std::string>& port_names)
{
- for (PortIndex::iterator i = _ports.begin (); i != _ports.end (); ++i) {
+ boost::shared_ptr<PortIndex> p = _ports.reader();
+
+ for (PortIndex::iterator i = p->begin (); i != p->end (); ++i) {
AlsaPort* port = *i;
if ((port->type () == type) && port->is_output () && port->is_physical ()) {
port_names.push_back (port->name ());
@@ -2024,7 +2076,10 @@ AlsaAudioBackend::n_physical_outputs () const
{
int n_midi = 0;
int n_audio = 0;
- for (PortIndex::const_iterator i = _ports.begin (); i != _ports.end (); ++i) {
+
+ boost::shared_ptr<PortIndex> p = _ports.reader();
+
+ for (PortIndex::const_iterator i = p->begin (); i != p->end (); ++i) {
AlsaPort* port = *i;
if (port->is_output () && port->is_physical ()) {
switch (port->type ()) {
@@ -2045,7 +2100,10 @@ AlsaAudioBackend::n_physical_inputs () const
{
int n_midi = 0;
int n_audio = 0;
- for (PortIndex::const_iterator i = _ports.begin (); i != _ports.end (); ++i) {
+
+ boost::shared_ptr<PortIndex> p = _ports.reader();
+
+ for (PortIndex::const_iterator i = p->begin (); i != p->end (); ++i) {
AlsaPort* port = *i;
if (port->is_input () && port->is_physical ()) {
switch (port->type ()) {
diff --git a/libs/backends/alsa/alsa_audiobackend.h b/libs/backends/alsa/alsa_audiobackend.h
index 1d71c85876..51783749e1 100644
--- a/libs/backends/alsa/alsa_audiobackend.h
+++ b/libs/backends/alsa/alsa_audiobackend.h
@@ -31,6 +31,8 @@
#include <boost/shared_ptr.hpp>
#include "pbd/natsort.h"
+#include "pbd/rcu.h"
+
#include "ardour/audio_backend.h"
#include "ardour/dsp_load_calculator.h"
#include "ardour/system_exec.h"
@@ -439,8 +441,8 @@ class AlsaAudioBackend : public AudioBackend {
typedef std::map<std::string, AlsaPort *> PortMap; // fast lookup in _ports
typedef std::set<AlsaPort *, SortByPortName> PortIndex; // fast lookup in _ports
- PortMap _portmap;
- PortIndex _ports;
+ SerializedRCUManager<PortMap> _portmap;
+ SerializedRCUManager<PortIndex> _ports;
std::vector<AlsaMidiOut *> _rmidi_out;
std::vector<AlsaMidiIn *> _rmidi_in;
@@ -471,12 +473,14 @@ class AlsaAudioBackend : public AudioBackend {
}
bool valid_port (PortHandle port) const {
- return std::find (_ports.begin(), _ports.end(), static_cast<AlsaPort*>(port)) != _ports.end ();
+ boost::shared_ptr<PortIndex> p = _ports.reader();
+ return std::find (p->begin(), p->end(), static_cast<AlsaPort*>(port)) != p->end ();
}
AlsaPort* find_port (const std::string& port_name) const {
- PortMap::const_iterator it = _portmap.find (port_name);
- if (it == _portmap.end()) {
+ boost::shared_ptr<PortMap> p = _portmap.reader();
+ PortMap::const_iterator it = p->find (port_name);
+ if (it == p->end()) {
return NULL;
}
return (*it).second;