Say which mixer calls run without the renderer lock in audren.h.

The comment above the mixer interface said every call but open, close and set_running runs with r->lock held, but
audren.c render_thread calls audio_mixer_pace_ns and audio_mixer_owed before it takes the lock, and stats_report calls
audio_mixer_out_stats after it drops it. That is correct, since they touch only atomics and render-thread state
(device_check and channels_switch, the only code that closes and opens the output stream, run on the render thread,
and audio_mixer_close runs after renderer_close joined it), but the comment read as a data race (AUDIT D-08). It now
names the three calls and why they need no lock. Comment only; audio_mixer_check passes and both files compile.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
chrg6
2026-11-13 17:29:07 -05:00
parent 6029321eff
commit 88a64573a2

View File

@@ -185,7 +185,11 @@ typedef struct AudioRenderer {
void audren_manager_handler(IpcSession *s, const IpcRequest *rq, IpcResponse *rs);
long audren_renderers_live(void); // renderers whose render tick runs
// Mixer interface (audio_mixer.c). Every call but open/close/set_running runs with r->lock held.
// Mixer interface (audio_mixer.c). Every call runs with r->lock held except open, close and set_running, and the
// render thread's audio_mixer_pace_ns, audio_mixer_owed and audio_mixer_out_stats (audren.c render_thread and
// stats_report call them without it). Those three touch only atomics and state that only the render thread changes:
// device_check and channels_switch, which close and open the output stream, run on that thread too, and
// audio_mixer_close runs after renderer_close has joined it.
void audio_mixer_open(AudioRenderer *r);
void audio_mixer_set_running(AudioRenderer *r, int running);
void audio_mixer_close(AudioRenderer *r);