summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Kellermann <max@musicpd.org>2016-09-09 14:36:24 +0200
committerMax Kellermann <max@musicpd.org>2016-09-09 14:36:24 +0200
commit860064c8128fd12b2ae6a32d399f01fe6390a223 (patch)
tree08d65e153d2cc1a70bfd853a5bf19e2963745051
parent845901ab015660e2999f01c4f112d274295c7417 (diff)
output/pulse: use a RTTI lock guard
Make all the locks exception-safe.
-rw-r--r--Makefile.am1
-rw-r--r--src/lib/pulse/LockGuard.hxx46
-rw-r--r--src/mixer/plugins/PulseMixerPlugin.cxx12
-rw-r--r--src/output/plugins/PulseOutputPlugin.cxx68
-rw-r--r--src/output/plugins/PulseOutputPlugin.hxx7
5 files changed, 70 insertions, 64 deletions
diff --git a/Makefile.am b/Makefile.am
index 09be93a82..31f088629 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1457,6 +1457,7 @@ libmixer_plugins_a_SOURCES += \
noinst_LIBRARIES += libpulse.a
libpulse_a_SOURCES = \
+ src/lib/pulse/LockGuard.hxx \
src/lib/pulse/LogError.cxx src/lib/pulse/LogError.hxx \
src/lib/pulse/Error.cxx src/lib/pulse/Error.hxx \
src/lib/pulse/Domain.cxx src/lib/pulse/Domain.hxx
diff --git a/src/lib/pulse/LockGuard.hxx b/src/lib/pulse/LockGuard.hxx
new file mode 100644
index 000000000..630cf3f05
--- /dev/null
+++ b/src/lib/pulse/LockGuard.hxx
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2003-2016 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_PULSE_LOCK_GUARD_HXX
+#define MPD_PULSE_LOCK_GUARD_HXX
+
+#include <pulse/thread-mainloop.h>
+
+namespace Pulse {
+
+class LockGuard {
+ struct pa_threaded_mainloop *const mainloop;
+
+public:
+ explicit LockGuard(struct pa_threaded_mainloop *_mainloop)
+ :mainloop(_mainloop) {
+ pa_threaded_mainloop_lock(mainloop);
+ }
+
+ ~LockGuard() {
+ pa_threaded_mainloop_unlock(mainloop);
+ }
+
+ LockGuard(const LockGuard &) = delete;
+ LockGuard &operator=(const LockGuard &) = delete;
+};
+
+};
+
+#endif
diff --git a/src/mixer/plugins/PulseMixerPlugin.cxx b/src/mixer/plugins/PulseMixerPlugin.cxx
index 20846cfe0..efdcf43fd 100644
--- a/src/mixer/plugins/PulseMixerPlugin.cxx
+++ b/src/mixer/plugins/PulseMixerPlugin.cxx
@@ -21,6 +21,7 @@
#include "PulseMixerPlugin.hxx"
#include "lib/pulse/Domain.hxx"
#include "lib/pulse/LogError.hxx"
+#include "lib/pulse/LockGuard.hxx"
#include "mixer/MixerInternal.hxx"
#include "mixer/Listener.hxx"
#include "output/plugins/PulseOutputPlugin.hxx"
@@ -181,12 +182,9 @@ PulseMixer::~PulseMixer()
int
PulseMixer::GetVolume(gcc_unused Error &error)
{
- pulse_output_lock(output);
+ Pulse::LockGuard lock(pulse_output_get_mainloop(output));
- int result = GetVolumeInternal(error);
- pulse_output_unlock(output);
-
- return result;
+ return GetVolumeInternal(error);
}
/**
@@ -203,10 +201,9 @@ PulseMixer::GetVolumeInternal(gcc_unused Error &error)
bool
PulseMixer::SetVolume(unsigned new_volume, Error &error)
{
- pulse_output_lock(output);
+ Pulse::LockGuard lock(pulse_output_get_mainloop(output));
if (!online) {
- pulse_output_unlock(output);
error.Set(pulse_domain, "disconnected");
return false;
}
@@ -218,7 +215,6 @@ PulseMixer::SetVolume(unsigned new_volume, Error &error)
if (success)
volume = cvolume;
- pulse_output_unlock(output);
return success;
}
diff --git a/src/output/plugins/PulseOutputPlugin.cxx b/src/output/plugins/PulseOutputPlugin.cxx
index dd4610f4d..748eff636 100644
--- a/src/output/plugins/PulseOutputPlugin.cxx
+++ b/src/output/plugins/PulseOutputPlugin.cxx
@@ -22,6 +22,7 @@
#include "lib/pulse/Domain.hxx"
#include "lib/pulse/Error.hxx"
#include "lib/pulse/LogError.hxx"
+#include "lib/pulse/LockGuard.hxx"
#include "../OutputAPI.hxx"
#include "../Wrapper.hxx"
#include "mixer/MixerList.hxx"
@@ -75,12 +76,8 @@ public:
bool SetVolume(const pa_cvolume &volume, Error &error);
- void Lock() {
- pa_threaded_mainloop_lock(mainloop);
- }
-
- void Unlock() {
- pa_threaded_mainloop_unlock(mainloop);
+ struct pa_threaded_mainloop *GetMainloop() {
+ return mainloop;
}
void OnContextStateChanged(pa_context_state_t new_state);
@@ -180,16 +177,10 @@ private:
bool StreamPause(bool pause, Error &error);
};
-void
-pulse_output_lock(PulseOutput &po)
-{
- po.Lock();
-}
-
-void
-pulse_output_unlock(PulseOutput &po)
+struct pa_threaded_mainloop *
+pulse_output_get_mainloop(PulseOutput &po)
{
- po.Unlock();
+ return po.GetMainloop();
}
inline void
@@ -202,7 +193,7 @@ PulseOutput::SetMixer(PulseMixer &_mixer)
if (mainloop == nullptr)
return;
- pa_threaded_mainloop_lock(mainloop);
+ Pulse::LockGuard lock(mainloop);
if (context != nullptr &&
pa_context_get_state(context) == PA_CONTEXT_READY) {
@@ -212,8 +203,6 @@ PulseOutput::SetMixer(PulseMixer &_mixer)
pa_stream_get_state(stream) == PA_STREAM_READY)
pulse_mixer_on_change(_mixer, context, stream);
}
-
- pa_threaded_mainloop_unlock(mainloop);
}
void
@@ -653,7 +642,7 @@ PulseOutput::Open(AudioFormat &audio_format, Error &error)
{
assert(mainloop != nullptr);
- pa_threaded_mainloop_lock(mainloop);
+ Pulse::LockGuard lock(mainloop);
if (context != nullptr) {
switch (pa_context_get_state(context)) {
@@ -674,10 +663,8 @@ PulseOutput::Open(AudioFormat &audio_format, Error &error)
}
}
- if (!WaitConnection(error)) {
- pa_threaded_mainloop_unlock(mainloop);
+ if (!WaitConnection(error))
return false;
- }
/* Use the sample formats that our version of PulseAudio and MPD
have in common, otherwise force MPD to send 16 bit */
@@ -708,10 +695,8 @@ PulseOutput::Open(AudioFormat &audio_format, Error &error)
/* create a stream .. */
- if (!SetupStream(ss, error)) {
- pa_threaded_mainloop_unlock(mainloop);
+ if (!SetupStream(ss, error))
return false;
- }
/* .. and connect it (asynchronously) */
@@ -722,11 +707,9 @@ PulseOutput::Open(AudioFormat &audio_format, Error &error)
SetPulseError(error, context,
"pa_stream_connect_playback() has failed");
- pa_threaded_mainloop_unlock(mainloop);
return false;
}
- pa_threaded_mainloop_unlock(mainloop);
return true;
}
@@ -735,7 +718,7 @@ PulseOutput::Close()
{
assert(mainloop != nullptr);
- pa_threaded_mainloop_lock(mainloop);
+ Pulse::LockGuard lock(mainloop);
if (pa_stream_get_state(stream) == PA_STREAM_READY) {
pa_operation *o =
@@ -753,8 +736,6 @@ PulseOutput::Close()
if (context != nullptr &&
pa_context_get_state(context) != PA_CONTEXT_READY)
DeleteContext();
-
- pa_threaded_mainloop_unlock(mainloop);
}
bool
@@ -806,7 +787,7 @@ PulseOutput::StreamPause(bool pause, Error &error)
inline unsigned
PulseOutput::Delay()
{
- pa_threaded_mainloop_lock(mainloop);
+ Pulse::LockGuard lock(mainloop);
unsigned result = 0;
if (base.pause && pa_stream_is_corked(stream) &&
@@ -814,8 +795,6 @@ PulseOutput::Delay()
/* idle while paused */
result = 1000;
- pa_threaded_mainloop_unlock(mainloop);
-
return result;
}
@@ -825,29 +804,24 @@ PulseOutput::Play(const void *chunk, size_t size, Error &error)
assert(mainloop != nullptr);
assert(stream != nullptr);
- pa_threaded_mainloop_lock(mainloop);
+ Pulse::LockGuard lock(mainloop);
/* check if the stream is (already) connected */
- if (!WaitStream(error)) {
- pa_threaded_mainloop_unlock(mainloop);
+ if (!WaitStream(error))
return 0;
- }
assert(context != nullptr);
/* unpause if previously paused */
- if (pa_stream_is_corked(stream) && !StreamPause(false, error)) {
- pa_threaded_mainloop_unlock(mainloop);
+ if (pa_stream_is_corked(stream) && !StreamPause(false, error))
return 0;
- }
/* wait until the server allows us to write */
while (writable == 0) {
if (pa_stream_is_suspended(stream)) {
- pa_threaded_mainloop_unlock(mainloop);
error.Set(pulse_domain, "suspended");
return 0;
}
@@ -855,7 +829,6 @@ PulseOutput::Play(const void *chunk, size_t size, Error &error)
pa_threaded_mainloop_wait(mainloop);
if (pa_stream_get_state(stream) != PA_STREAM_READY) {
- pa_threaded_mainloop_unlock(mainloop);
error.Set(pulse_domain, "disconnected");
return 0;
}
@@ -871,7 +844,6 @@ PulseOutput::Play(const void *chunk, size_t size, Error &error)
int result = pa_stream_write(stream, chunk, size, nullptr,
0, PA_SEEK_RELATIVE);
- pa_threaded_mainloop_unlock(mainloop);
if (result < 0) {
SetPulseError(error, context, "pa_stream_write() failed");
return 0;
@@ -886,12 +858,11 @@ PulseOutput::Cancel()
assert(mainloop != nullptr);
assert(stream != nullptr);
- pa_threaded_mainloop_lock(mainloop);
+ Pulse::LockGuard lock(mainloop);
if (pa_stream_get_state(stream) != PA_STREAM_READY) {
/* no need to flush when the stream isn't connected
yet */
- pa_threaded_mainloop_unlock(mainloop);
return;
}
@@ -902,12 +873,10 @@ PulseOutput::Cancel()
this);
if (o == nullptr) {
LogPulseError(context, "pa_stream_flush() has failed");
- pa_threaded_mainloop_unlock(mainloop);
return;
}
pulse_wait_for_operation(mainloop, o);
- pa_threaded_mainloop_unlock(mainloop);
}
inline bool
@@ -916,13 +885,12 @@ PulseOutput::Pause()
assert(mainloop != nullptr);
assert(stream != nullptr);
- pa_threaded_mainloop_lock(mainloop);
+ Pulse::LockGuard lock(mainloop);
/* check if the stream is (already/still) connected */
Error error;
if (!WaitStream(error)) {
- pa_threaded_mainloop_unlock(mainloop);
LogError(error);
return false;
}
@@ -932,12 +900,10 @@ PulseOutput::Pause()
/* cork the stream */
if (!pa_stream_is_corked(stream) && !StreamPause(true, error)) {
- pa_threaded_mainloop_unlock(mainloop);
LogError(error);
return false;
}
- pa_threaded_mainloop_unlock(mainloop);
return true;
}
diff --git a/src/output/plugins/PulseOutputPlugin.hxx b/src/output/plugins/PulseOutputPlugin.hxx
index 27c28b5b6..c25371b0e 100644
--- a/src/output/plugins/PulseOutputPlugin.hxx
+++ b/src/output/plugins/PulseOutputPlugin.hxx
@@ -27,11 +27,8 @@ class Error;
extern const struct AudioOutputPlugin pulse_output_plugin;
-void
-pulse_output_lock(PulseOutput &po);
-
-void
-pulse_output_unlock(PulseOutput &po);
+struct pa_threaded_mainloop *
+pulse_output_get_mainloop(PulseOutput &po);
void
pulse_output_set_mixer(PulseOutput &po, PulseMixer &pm);