From 2b11efdf3b4bd352f0970456dc21c00025da1161 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 16 Apr 2024 09:30:23 +0200 Subject: [PATCH] alsa: fix race when updating the eventfd The eventfd is read/written from/to the data thread and the main thread concurrently with the update_active() function. Use an atomic compare and swap to make this update atomic and avoid an inconsistency between the active boolean and the eventfd. This could result in the eventfd being unsignaled while the active flag was true and the application receiving a timeout and XRun in its poll loop. Fixes #3711 --- pipewire-alsa/alsa-plugins/pcm_pipewire.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/pipewire-alsa/alsa-plugins/pcm_pipewire.c b/pipewire-alsa/alsa-plugins/pcm_pipewire.c index 7347f8bab..f1785b7f4 100644 --- a/pipewire-alsa/alsa-plugins/pcm_pipewire.c +++ b/pipewire-alsa/alsa-plugins/pcm_pipewire.c @@ -56,9 +56,10 @@ typedef struct { unsigned int draining:1; unsigned int xrun_detected:1; unsigned int hw_params_changed:1; - unsigned int active:1; unsigned int negotiated:1; + bool active; + snd_pcm_uframes_t hw_ptr; snd_pcm_uframes_t boundary; snd_pcm_uframes_t min_avail; @@ -93,8 +94,9 @@ static int update_active(snd_pcm_ioplug_t *io) { snd_pcm_pipewire_t *pw = io->private_data; snd_pcm_sframes_t avail; - bool active; + bool active, old; +retry: avail = snd_pcm_ioplug_avail(io, pw->hw_ptr, io->appl_ptr); if (pw->error > 0) { @@ -112,7 +114,8 @@ static int update_active(snd_pcm_ioplug_t *io) else { active = false; } - if (pw->active != active) { + old = SPA_ATOMIC_LOAD(pw->active); + if (old != active) { uint64_t val; pw_log_trace("%p: avail:%lu min-avail:%lu state:%s hw:%lu appl:%lu active:%d->%d state:%s", @@ -120,11 +123,13 @@ static int update_active(snd_pcm_ioplug_t *io) pw->hw_ptr, io->appl_ptr, pw->active, active, snd_pcm_state_name(io->state)); - pw->active = active; if (active) spa_system_eventfd_write(pw->system, io->poll_fd, 1); else spa_system_eventfd_read(pw->system, io->poll_fd, &val); + + if (!SPA_ATOMIC_CAS(pw->active, old, active)) + goto retry; } return active; }