mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-12-05 01:10:24 +00:00
LibMedia: Stop using threading-unsafe Weakable for PulseAudioContext
We can't control whether the instantiation mutex is held when ~Weakable() is called, so we need to implement this via a static raw pointer instead to ensure that all operations on it are effectively atomic.
This commit is contained in:
committed by
Gregory Bertilson
parent
3e485ba51c
commit
13cf0e72d8
Notes:
github-actions[bot]
2025-11-24 21:10:44 +00:00
Author: https://github.com/Zaggy1024 Commit: https://github.com/LadybirdBrowser/ladybird/commit/13cf0e72d81 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/6684
@@ -6,35 +6,28 @@
|
||||
|
||||
#include "PulseAudioWrappers.h"
|
||||
|
||||
#include <AK/WeakPtr.h>
|
||||
#include <LibThreading/Mutex.h>
|
||||
|
||||
namespace Audio {
|
||||
|
||||
WeakPtr<PulseAudioContext> PulseAudioContext::weak_instance()
|
||||
{
|
||||
// Use a weak pointer to allow the context to be shut down if we stop outputting audio.
|
||||
static WeakPtr<PulseAudioContext> the_instance;
|
||||
return the_instance;
|
||||
}
|
||||
static PulseAudioContext* s_pulse_audio_context;
|
||||
static Threading::Mutex s_pulse_audio_context_mutex;
|
||||
|
||||
ErrorOr<NonnullRefPtr<PulseAudioContext>> PulseAudioContext::the()
|
||||
{
|
||||
static Threading::Mutex instantiation_mutex;
|
||||
auto instantiation_locker = Threading::MutexLocker(s_pulse_audio_context_mutex);
|
||||
|
||||
// Lock and unlock the mutex to ensure that the mutex is fully unlocked at application
|
||||
// exit.
|
||||
auto atexit_result = atexit([]() {
|
||||
instantiation_mutex.lock();
|
||||
instantiation_mutex.unlock();
|
||||
s_pulse_audio_context_mutex.lock();
|
||||
s_pulse_audio_context_mutex.unlock();
|
||||
});
|
||||
if (atexit_result) {
|
||||
return Error::from_string_literal("Unable to set PulseAudioContext atexit action");
|
||||
}
|
||||
|
||||
auto instantiation_locker = Threading::MutexLocker(instantiation_mutex);
|
||||
|
||||
auto the_instance = weak_instance();
|
||||
RefPtr<PulseAudioContext> strong_instance_pointer = the_instance.strong_ref();
|
||||
RefPtr<PulseAudioContext> strong_instance_pointer = RefPtr<PulseAudioContext>(s_pulse_audio_context);
|
||||
|
||||
if (strong_instance_pointer == nullptr) {
|
||||
auto* main_loop = pa_threaded_mainloop_new();
|
||||
@@ -99,12 +92,18 @@ ErrorOr<NonnullRefPtr<PulseAudioContext>> PulseAudioContext::the()
|
||||
pa_context_set_state_callback(context, nullptr, nullptr);
|
||||
}
|
||||
|
||||
the_instance = strong_instance_pointer;
|
||||
s_pulse_audio_context = strong_instance_pointer;
|
||||
}
|
||||
|
||||
return strong_instance_pointer.release_nonnull();
|
||||
}
|
||||
|
||||
bool PulseAudioContext::is_connected()
|
||||
{
|
||||
auto locker = Threading::MutexLocker(s_pulse_audio_context_mutex);
|
||||
return s_pulse_audio_context != nullptr;
|
||||
}
|
||||
|
||||
PulseAudioContext::PulseAudioContext(pa_threaded_mainloop* main_loop, pa_mainloop_api* api, pa_context* context)
|
||||
: m_main_loop(main_loop)
|
||||
, m_api(api)
|
||||
@@ -114,13 +113,17 @@ PulseAudioContext::PulseAudioContext(pa_threaded_mainloop* main_loop, pa_mainloo
|
||||
|
||||
PulseAudioContext::~PulseAudioContext()
|
||||
{
|
||||
auto locker = Threading::MutexLocker(s_pulse_audio_context_mutex);
|
||||
|
||||
{
|
||||
auto locker = main_loop_locker();
|
||||
auto loop_locker = main_loop_locker();
|
||||
pa_context_disconnect(m_context);
|
||||
pa_context_unref(m_context);
|
||||
}
|
||||
pa_threaded_mainloop_stop(m_main_loop);
|
||||
pa_threaded_mainloop_free(m_main_loop);
|
||||
|
||||
s_pulse_audio_context = nullptr;
|
||||
}
|
||||
|
||||
bool PulseAudioContext::current_thread_is_main_loop_thread()
|
||||
|
||||
@@ -36,11 +36,10 @@ using PulseAudioDataRequestCallback = Function<ReadonlyBytes(PulseAudioStream&,
|
||||
// A wrapper around the PulseAudio main loop and context structs.
|
||||
// Generally, only one instance of this should be needed for a single process.
|
||||
class MEDIA_API PulseAudioContext
|
||||
: public AtomicRefCounted<PulseAudioContext>
|
||||
, public Weakable<PulseAudioContext> {
|
||||
: public AtomicRefCounted<PulseAudioContext> {
|
||||
public:
|
||||
static AK::WeakPtr<PulseAudioContext> weak_instance();
|
||||
static ErrorOr<NonnullRefPtr<PulseAudioContext>> the();
|
||||
static bool is_connected();
|
||||
|
||||
explicit PulseAudioContext(pa_threaded_mainloop*, pa_mainloop_api*, pa_context*);
|
||||
PulseAudioContext(PulseAudioContext const& other) = delete;
|
||||
@@ -69,6 +68,8 @@ public:
|
||||
private:
|
||||
friend class PulseAudioStream;
|
||||
|
||||
PulseAudioContext*& nullable_instance();
|
||||
|
||||
pa_threaded_mainloop* m_main_loop { nullptr };
|
||||
pa_mainloop_api* m_api { nullptr };
|
||||
pa_context* m_context;
|
||||
|
||||
@@ -42,6 +42,6 @@ TEST_CASE(create_and_destroy_playback_stream)
|
||||
}
|
||||
|
||||
#if defined(HAVE_PULSEAUDIO)
|
||||
VERIFY(!Audio::PulseAudioContext::weak_instance());
|
||||
VERIFY(!Audio::PulseAudioContext::is_connected());
|
||||
#endif
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user