13
0

ALSA: add locks to safely add/remove MIDI devices

Theoretically this could be lock-free by using a queue of device
ports to be added/remove in sync in the process-callback, but
realistically adding/removing devices doesn't have to be rt-safe.
This commit is contained in:
Robin Gareus 2019-01-14 22:07:51 +01:00
parent 8f9e63575f
commit 8b71967be9
Signed by: rgareus
GPG Key ID: A090BCE02CF57F04
2 changed files with 26 additions and 2 deletions

View File

@ -78,6 +78,7 @@ AlsaAudioBackend::AlsaAudioBackend (AudioEngine& e, AudioBackendInfo& info)
{ {
_instance_name = s_instance_name; _instance_name = s_instance_name;
pthread_mutex_init (&_port_callback_mutex, 0); pthread_mutex_init (&_port_callback_mutex, 0);
pthread_mutex_init (&_device_port_mutex, 0);
_input_audio_device_info.valid = false; _input_audio_device_info.valid = false;
_output_audio_device_info.valid = false; _output_audio_device_info.valid = false;
@ -87,6 +88,7 @@ AlsaAudioBackend::AlsaAudioBackend (AudioEngine& e, AudioBackendInfo& info)
AlsaAudioBackend::~AlsaAudioBackend () AlsaAudioBackend::~AlsaAudioBackend ()
{ {
pthread_mutex_destroy (&_port_callback_mutex); pthread_mutex_destroy (&_port_callback_mutex);
pthread_mutex_destroy (&_device_port_mutex);
} }
/* AUDIOBACKEND API */ /* AUDIOBACKEND API */
@ -474,6 +476,7 @@ AlsaAudioBackend::update_systemic_audio_latencies ()
void void
AlsaAudioBackend::update_systemic_midi_latencies () AlsaAudioBackend::update_systemic_midi_latencies ()
{ {
pthread_mutex_lock (&_device_port_mutex);
uint32_t i = 0; uint32_t i = 0;
for (std::vector<AlsaPort*>::iterator it = _system_midi_out.begin (); it != _system_midi_out.end (); ++it, ++i) { for (std::vector<AlsaPort*>::iterator it = _system_midi_out.begin (); it != _system_midi_out.end (); ++it, ++i) {
assert (_rmidi_out.size() > i); assert (_rmidi_out.size() > i);
@ -495,6 +498,7 @@ AlsaAudioBackend::update_systemic_midi_latencies ()
lr.min = lr.max = (_measure_latency ? 0 : nfo->systemic_input_latency); lr.min = lr.max = (_measure_latency ? 0 : nfo->systemic_input_latency);
set_latency_range (*it, true, lr); set_latency_range (*it, true, lr);
} }
pthread_mutex_unlock (&_device_port_mutex);
update_latencies (); update_latencies ();
} }
@ -682,6 +686,7 @@ AlsaAudioBackend::set_midi_device_enabled (std::string const device, bool enable
register_system_midi_ports(device); register_system_midi_ports(device);
} else { } else {
// remove all ports provided by the given device // remove all ports provided by the given device
pthread_mutex_lock (&_device_port_mutex);
uint32_t i = 0; uint32_t i = 0;
for (std::vector<AlsaPort*>::iterator it = _system_midi_out.begin (); it != _system_midi_out.end ();) { for (std::vector<AlsaPort*>::iterator it = _system_midi_out.begin (); it != _system_midi_out.end ();) {
assert (_rmidi_out.size() > i); assert (_rmidi_out.size() > i);
@ -705,6 +710,7 @@ AlsaAudioBackend::set_midi_device_enabled (std::string const device, bool enable
_rmidi_in.erase (_rmidi_in.begin() + i); _rmidi_in.erase (_rmidi_in.begin() + i);
delete rm; delete rm;
} }
pthread_mutex_unlock (&_device_port_mutex);
} }
update_systemic_midi_latencies (); update_systemic_midi_latencies ();
} }
@ -1540,12 +1546,14 @@ AlsaAudioBackend::update_system_port_latecies ()
(*it)->update_connected_latency (false); (*it)->update_connected_latency (false);
} }
pthread_mutex_lock (&_device_port_mutex);
for (std::vector<AlsaPort*>::const_iterator it = _system_midi_in.begin (); it != _system_midi_in.end (); ++it) { for (std::vector<AlsaPort*>::const_iterator it = _system_midi_in.begin (); it != _system_midi_in.end (); ++it) {
(*it)->update_connected_latency (true); (*it)->update_connected_latency (true);
} }
for (std::vector<AlsaPort*>::const_iterator it = _system_midi_out.begin (); it != _system_midi_out.end (); ++it) { for (std::vector<AlsaPort*>::const_iterator it = _system_midi_out.begin (); it != _system_midi_out.end (); ++it) {
(*it)->update_connected_latency (false); (*it)->update_connected_latency (false);
} }
pthread_mutex_unlock (&_device_port_mutex);
for (AudioSlaves::iterator s = _slaves.begin (); s != _slaves.end (); ++s) { for (AudioSlaves::iterator s = _slaves.begin (); s != _slaves.end (); ++s) {
if ((*s)->dead) { if ((*s)->dead) {
@ -1648,7 +1656,9 @@ AlsaAudioBackend::register_system_midi_ports(const std::string device)
static_cast<AlsaMidiPort*>(p)->set_n_periods(_periods_per_cycle); // TODO check MIDI alignment static_cast<AlsaMidiPort*>(p)->set_n_periods(_periods_per_cycle); // TODO check MIDI alignment
AlsaPort *ap = static_cast<AlsaPort*>(p); AlsaPort *ap = static_cast<AlsaPort*>(p);
ap->set_pretty_name (replace_name_io (i->first, false)); ap->set_pretty_name (replace_name_io (i->first, false));
pthread_mutex_lock (&_device_port_mutex);
_system_midi_out.push_back (ap); _system_midi_out.push_back (ap);
pthread_mutex_unlock (&_device_port_mutex);
_rmidi_out.push_back (mout); _rmidi_out.push_back (mout);
} }
} }
@ -1687,7 +1697,9 @@ AlsaAudioBackend::register_system_midi_ports(const std::string device)
set_latency_range (p, false, lr); set_latency_range (p, false, lr);
AlsaPort *ap = static_cast<AlsaPort*>(p); AlsaPort *ap = static_cast<AlsaPort*>(p);
ap->set_pretty_name (replace_name_io (i->first, true)); ap->set_pretty_name (replace_name_io (i->first, true));
pthread_mutex_lock (&_device_port_mutex);
_system_midi_in.push_back (ap); _system_midi_in.push_back (ap);
pthread_mutex_unlock (&_device_port_mutex);
_rmidi_in.push_back (midin); _rmidi_in.push_back (midin);
} }
} }
@ -2170,6 +2182,8 @@ AlsaAudioBackend::main_process_thread ()
} }
} }
/* only used when adding/removing MIDI device/system ports */
pthread_mutex_lock (&_device_port_mutex);
/* de-queue incoming midi*/ /* de-queue incoming midi*/
i = 0; i = 0;
for (std::vector<AlsaPort*>::const_iterator it = _system_midi_in.begin (); it != _system_midi_in.end (); ++it, ++i) { for (std::vector<AlsaPort*>::const_iterator it = _system_midi_in.begin (); it != _system_midi_in.end (); ++it, ++i) {
@ -2186,6 +2200,7 @@ AlsaAudioBackend::main_process_thread ()
} }
rm->sync_time (clock1); rm->sync_time (clock1);
} }
pthread_mutex_unlock (&_device_port_mutex);
for (std::vector<AlsaPort*>::const_iterator it = _system_outputs.begin (); it != _system_outputs.end (); ++it) { for (std::vector<AlsaPort*>::const_iterator it = _system_outputs.begin (); it != _system_outputs.end (); ++it) {
memset ((*it)->get_buffer (_samples_per_period), 0, _samples_per_period * sizeof (Sample)); memset ((*it)->get_buffer (_samples_per_period), 0, _samples_per_period * sizeof (Sample));
@ -2199,6 +2214,8 @@ AlsaAudioBackend::main_process_thread ()
return 0; return 0;
} }
/* only used when adding/removing MIDI device/system ports */
pthread_mutex_lock (&_device_port_mutex);
for (std::vector<AlsaPort*>::iterator it = _system_midi_out.begin (); it != _system_midi_out.end (); ++it) { for (std::vector<AlsaPort*>::iterator it = _system_midi_out.begin (); it != _system_midi_out.end (); ++it) {
static_cast<AlsaMidiPort*>(*it)->next_period(); static_cast<AlsaMidiPort*>(*it)->next_period();
} }
@ -2214,6 +2231,7 @@ AlsaAudioBackend::main_process_thread ()
rm->send_event (mit->timestamp (), mit->data (), mit->size ()); rm->send_event (mit->timestamp (), mit->data (), mit->size ());
} }
} }
pthread_mutex_unlock (&_device_port_mutex);
/* write back audio */ /* write back audio */
i = 0; i = 0;
@ -2265,6 +2283,7 @@ AlsaAudioBackend::main_process_thread ()
clock1 = g_get_monotonic_time(); clock1 = g_get_monotonic_time();
uint32_t i = 0; uint32_t i = 0;
pthread_mutex_lock (&_device_port_mutex);
for (std::vector<AlsaPort*>::const_iterator it = _system_midi_in.begin (); it != _system_midi_in.end (); ++it, ++i) { for (std::vector<AlsaPort*>::const_iterator it = _system_midi_in.begin (); it != _system_midi_in.end (); ++it, ++i) {
static_cast<AlsaMidiBuffer*>((*it)->get_buffer(0))->clear (); static_cast<AlsaMidiBuffer*>((*it)->get_buffer(0))->clear ();
AlsaMidiIn *rm = _rmidi_in.at(i); AlsaMidiIn *rm = _rmidi_in.at(i);
@ -2280,6 +2299,7 @@ AlsaAudioBackend::main_process_thread ()
} }
rm->sync_time (clock1); rm->sync_time (clock1);
} }
pthread_mutex_unlock (&_device_port_mutex);
_last_process_start = 0; _last_process_start = 0;
if (engine.process_callback (_samples_per_period)) { if (engine.process_callback (_samples_per_period)) {
@ -2289,10 +2309,12 @@ AlsaAudioBackend::main_process_thread ()
} }
// drop all outgoing MIDI messages // drop all outgoing MIDI messages
pthread_mutex_lock (&_device_port_mutex);
for (std::vector<AlsaPort*>::const_iterator it = _system_midi_out.begin (); it != _system_midi_out.end (); ++it) { for (std::vector<AlsaPort*>::const_iterator it = _system_midi_out.begin (); it != _system_midi_out.end (); ++it) {
void *bptr = (*it)->get_buffer(0); void *bptr = (*it)->get_buffer(0);
midi_clear(bptr); midi_clear(bptr);
} }
pthread_mutex_unlock (&_device_port_mutex);
_dsp_load = 1.0; _dsp_load = 1.0;
reset_dll = true; reset_dll = true;

View File

@ -393,6 +393,8 @@ class AlsaAudioBackend : public AudioBackend {
pthread_t _midi_device_thread_id; pthread_t _midi_device_thread_id;
bool _midi_device_thread_active; bool _midi_device_thread_active;
pthread_mutex_t _device_port_mutex;
/* processing */ /* processing */
float _dsp_load; float _dsp_load;
ARDOUR::DSPLoadCalculator _dsp_load_calc; ARDOUR::DSPLoadCalculator _dsp_load_calc;