From f653c3a7381294f383b65685a92d585a2e990ee9 Mon Sep 17 00:00:00 2001
From: Patrick Ziegler
Date: Wed, 4 May 2022 08:58:53 +0200
Subject: [PATCH] fix(pulse): Hanging during connection setup (#2709)
If context_state_callback is called before we call
pa_threaded_mainloop_wait in the main thread, the signal is lost and we
wait forever.
Fixes #2707
Ref #2699
Ref #2697
---
CHANGELOG.md | 1 +
include/adapters/pulseaudio.hpp | 6 ++++++
src/adapters/pulseaudio.cpp | 15 ++++++++++++++-
3 files changed, 21 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c3ee2e7b..8aa1c047 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- ipc: Polybar failing to open IPC channel after another user already ran polybar, if `XDG_RUNTIME_DIR` is not set ([`#2683`](https://github.com/polybar/polybar/issues/2683), [`#2684`](https://github.com/polybar/polybar/pull/2684))
- No overlines/underlines being drawn when using offsets ([`#2685`](https://github.com/polybar/polybar/pull/2685))
- Update struts (`_NET_WM_STRUT_PARTIAL`) when hiding the bar ([`#2702`](https://github.com/polybar/polybar/pull/2702))
+- `internal/pulseaudio`: Hanging during startup ([`#2707`](https://github.com/polybar/polybar/issues/2707), [`#2709`](https://github.com/polybar/polybar/pull/2709))
## [3.6.2] - 2022-04-03
### Fixed
diff --git a/include/adapters/pulseaudio.hpp b/include/adapters/pulseaudio.hpp
index a5d23426..1ee10b52 100644
--- a/include/adapters/pulseaudio.hpp
+++ b/include/adapters/pulseaudio.hpp
@@ -2,6 +2,7 @@
#include
+#include
#include
#include "common.hpp"
@@ -58,6 +59,11 @@ class pulseaudio {
const logger& m_log;
+ /**
+ * Has context_state_callback signalled the mainloop during connection.
+ */
+ std::atomic_bool m_state_callback_signal{false};
+
// used for temporary callback results
int success{0};
pa_cvolume cv{};
diff --git a/src/adapters/pulseaudio.cpp b/src/adapters/pulseaudio.cpp
index 1a6a15b8..8404cceb 100644
--- a/src/adapters/pulseaudio.cpp
+++ b/src/adapters/pulseaudio.cpp
@@ -24,6 +24,8 @@ pulseaudio::pulseaudio(const logger& logger, string&& sink_name, bool max_volume
pa_context_set_state_callback(m_context, context_state_callback, this);
+ m_state_callback_signal = false;
+
if (pa_context_connect(m_context, nullptr, PA_CONTEXT_NOFLAGS, nullptr) < 0) {
pa_context_disconnect(m_context);
pa_context_unref(m_context);
@@ -42,7 +44,17 @@ pulseaudio::pulseaudio(const logger& logger, string&& sink_name, bool max_volume
m_log.trace("pulseaudio: started mainloop");
- pa_threaded_mainloop_wait(m_mainloop);
+ /*
+ * Only wait for signal from the context state callback, if it has not
+ * already signalled the mainloop since pa_context_connect was called,
+ * otherwise, we would wait forever.
+ *
+ * The while loop ensures spurious wakeups are handled.
+ */
+ while (!m_state_callback_signal) {
+ pa_threaded_mainloop_wait(m_mainloop);
+ }
+
if (pa_context_get_state(m_context) != PA_CONTEXT_READY) {
pa_threaded_mainloop_unlock(m_mainloop);
pa_threaded_mainloop_stop(m_mainloop);
@@ -310,6 +322,7 @@ void pulseaudio::context_state_callback(pa_context* context, void* userdata) {
case PA_CONTEXT_READY:
case PA_CONTEXT_TERMINATED:
case PA_CONTEXT_FAILED:
+ This->m_state_callback_signal = true;
pa_threaded_mainloop_signal(This->m_mainloop, 0);
break;