(ALSA) The blocking write writes first and waits only on EAGAIN, for a bounded time

The device usually has the room; a wait before every write was a
syscall and a scheduler round trip for nothing. The write is
attempted first, a wait follows only when the device says EAGAIN,
and the wait is bounded at one buffer's worth; a device that reports
no space twice running gets a short write, not the audio thread. XRUN
and suspend go through the recovery path as before, and the
non-blocking write is unchanged.

The lifecycle harness runs the write loop against a device that takes
the write whole, one that says EAGAIN once, one that underruns, one
that never accepts, and the non-blocking case.
This commit is contained in:
LibretroAdmin authored and libretroadmin committed 2026-09-09 05:59:34 +02:00
1 parent a4f07f82da
commit 48394abbb2
2 files changed
+23 -18

No files matched your search

+22 -18
View File
@@ -493,42 +493,46 @@ static ssize_t alsa_write(void *data, const void *buf_, size_t len)
}
else
{
bool eagain_retry = true;
/* Write first; the device usually has the room, and a wait
* before every write was a syscall and a scheduler round trip
* for nothing. Wait only when it says EAGAIN, and then for a
* bounded time - one buffer's worth - so a device that stops
* draining costs a bounded pause and a short write, never the
* audio thread. A wait that returns without space, twice, is
* that device. */
unsigned waits = 0;
int wait_ms = 100;
if (alsa->stream_info.buffer_size && alsa->stream_info.rate)
wait_ms = (int)((uint64_t)BYTES_TO_FRAMES(alsa->stream_info.buffer_size,
alsa->stream_info.frame_bits) * 1000 / alsa->stream_info.rate) + 1;
while (size)
{
snd_pcm_sframes_t frames;
int rc = snd_pcm_wait(alsa->pcm, -1);
if (rc == -EPIPE || rc == -ESTRPIPE || rc == -EINTR)
{
if (snd_pcm_recover(alsa->pcm, rc, 1) < 0)
return -1;
continue;
}
frames = snd_pcm_writei(alsa->pcm, buf, size);
snd_pcm_sframes_t frames = snd_pcm_writei(alsa->pcm, buf, size);
if (frames == -EPIPE || frames == -EINTR || frames == -ESTRPIPE)
{
if (snd_pcm_recover(alsa->pcm, frames, 1) < 0)
return -1;
break;
}
else if (frames == -EAGAIN)
{
/* Definitely not supposed to happen. */
if (eagain_retry)
int rc;
if (waits++ >= 2)
break;
rc = snd_pcm_wait(alsa->pcm, wait_ms);
if (rc == -EPIPE || rc == -ESTRPIPE || rc == -EINTR)
{
eagain_retry = false;
continue;
if (snd_pcm_recover(alsa->pcm, rc, 1) < 0)
return -1;
}
break;
continue;
}
else if (frames < 0)
return -1;
waits = 0;
_len += FRAMES_TO_BYTES(frames, alsa->stream_info.frame_bits);
alsa->frames_written += (uint64_t)frames;
buf += (frames << 1) * frames_size;
@@ -255,6 +255,7 @@ int main(void)
s_stop_start(0, 0, "a device that cannot pause: stop drops, start prepares", 0, 1, 0, 1);
s_stop_start(1, -EIO, "a device that says it can pause and refuses: stop drops", 1, 1, 0, 1);
s_repeated();
s_blocking_write();
if (failures)
{