From 7d579e7400069d116628da38ff3026670fe53611 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 14 Nov 2017 21:06:17 +0100 Subject: [PATCH] lib/alsa/NonBlock: throw exception on error Avoid another potential deadlock: if no file descriptors are registered, our non-blocking ALSA code cannot ever work. --- src/lib/alsa/NonBlock.cxx | 19 ++++++++++++++----- src/lib/alsa/NonBlock.hxx | 4 +++- src/output/plugins/AlsaOutputPlugin.cxx | 8 +++++++- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/lib/alsa/NonBlock.cxx b/src/lib/alsa/NonBlock.cxx index 2a079a7d5..c9850186c 100644 --- a/src/lib/alsa/NonBlock.cxx +++ b/src/lib/alsa/NonBlock.cxx @@ -20,22 +20,31 @@ #include "config.h" #include "NonBlock.hxx" #include "event/MultiSocketMonitor.hxx" +#include "util/RuntimeError.hxx" std::chrono::steady_clock::duration PrepareAlsaPcmSockets(MultiSocketMonitor &m, snd_pcm_t *pcm, - ReusableArray &pfd_buffer) noexcept + ReusableArray &pfd_buffer) { int count = snd_pcm_poll_descriptors_count(pcm); if (count <= 0) { - m.ClearSocketList(); - return std::chrono::steady_clock::duration(-1); + if (count == 0) + throw std::runtime_error("snd_pcm_poll_descriptors_count() failed"); + else + throw FormatRuntimeError("snd_pcm_poll_descriptors_count() failed: %s", + snd_strerror(-count)); } struct pollfd *pfds = pfd_buffer.Get(count); count = snd_pcm_poll_descriptors(pcm, pfds, count); - if (count < 0) - count = 0; + if (count <= 0) { + if (count == 0) + throw std::runtime_error("snd_pcm_poll_descriptors() failed"); + else + throw FormatRuntimeError("snd_pcm_poll_descriptors() failed: %s", + snd_strerror(-count)); + } m.ReplaceSocketList(pfds, count); return std::chrono::steady_clock::duration(-1); diff --git a/src/lib/alsa/NonBlock.hxx b/src/lib/alsa/NonBlock.hxx index d6fff8e16..4c3767d79 100644 --- a/src/lib/alsa/NonBlock.hxx +++ b/src/lib/alsa/NonBlock.hxx @@ -33,10 +33,12 @@ class MultiSocketMonitor; * Update #MultiSocketMonitor's socket list from * snd_pcm_poll_descriptors(). To be called from * MultiSocketMonitor::PrepareSockets(). + * + * Throws exception on error. */ std::chrono::steady_clock::duration PrepareAlsaPcmSockets(MultiSocketMonitor &m, snd_pcm_t *pcm, - ReusableArray &pfd_buffer) noexcept; + ReusableArray &pfd_buffer); /** * Update #MultiSocketMonitor's socket list from diff --git a/src/output/plugins/AlsaOutputPlugin.cxx b/src/output/plugins/AlsaOutputPlugin.cxx index c7dda9e9a..8a7acee95 100644 --- a/src/output/plugins/AlsaOutputPlugin.cxx +++ b/src/output/plugins/AlsaOutputPlugin.cxx @@ -815,7 +815,13 @@ AlsaOutput::PrepareSockets() noexcept return std::chrono::steady_clock::duration(-1); } - return PrepareAlsaPcmSockets(*this, pcm, pfd_buffer); + try { + return PrepareAlsaPcmSockets(*this, pcm, pfd_buffer); + } catch (...) { + ClearSocketList(); + LockCaughtError(); + return std::chrono::steady_clock::duration(-1); + } } void