From 4aa4280a0ad7870ef9867901fd5abec3d38c35b2 Mon Sep 17 00:00:00 2001 From: Adrian Date: Sat, 22 Oct 2022 21:04:59 +0200 Subject: [PATCH] ALSA plugin: Reduce mutex lock duration To mitigate deadlock issues on switching the audio input device, this commit reduces the time m_deviceListMutex is locked by switching std::lock_guard and manual locking for std::unique_lock and deferring locking only to places where access to the device list is needed. Closes: https://github.com/psmokotnin/osm/issues/56 --- src/audio/plugins/alsa.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/audio/plugins/alsa.cpp b/src/audio/plugins/alsa.cpp index 9987ba37..61537f22 100644 --- a/src/audio/plugins/alsa.cpp +++ b/src/audio/plugins/alsa.cpp @@ -16,6 +16,7 @@ * along with this program. If not, see . */ #include "alsa.h" +#include #include #include #define ALSA_BUFFER_SIZE 1024 @@ -175,23 +176,26 @@ Format AlsaPlugin::deviceFormat(const DeviceInfo::Id &id, const Plugin::Directio Stream *AlsaPlugin::open(const DeviceInfo::Id &id, const Plugin::Direction &mode, const Format &format, QIODevice *endpoint) { - std::lock_guard lock(m_deviceListMutex); + std::unique_lock lock(m_deviceListMutex, std::defer_lock); if (id.isNull()) { return nullptr; } + assert(!lock.owns_lock()); + lock.lock(); AlsaPCMDevice *device = m_devices[ {mode, id}]; if (!device) { device = new AlsaPCMDevice(id, mode, format, m_deviceListMutex); connect (device, &AlsaPCMDevice::closed, this, [this, mode, id, device]() { - //mutex is locked here by device + std::lock_guard lock{m_deviceListMutex}; m_devices[ {mode, id}] = nullptr; device->deleteLater(); - m_deviceListMutex.unlock(); }); m_devices[ {mode, id}] = device; } + assert(lock.owns_lock()); + lock.unlock(); if (!device->start()) { return nullptr; } @@ -326,14 +330,18 @@ bool AlsaPCMDevice::start() } QCoreApplication::processEvents(); if (m_callbacks.empty()) { - m_mutex.lock(); + std::unique_lock lock{m_mutex}; if (m_keepAlive) { + lock.unlock(); QCoreApplication::processEvents(); + lock.lock(); } else { - m_threadActive = false; + assert(lock.owns_lock()); + lock.unlock(); break; } - m_mutex.unlock(); + assert(lock.owns_lock()); + lock.unlock(); } m_threadActive = true; m_keepAlive = false;