Skip to content

Commit 6bba9ec

Browse files
committed
feat(alsa): defend against hangs due to polling timeouts
1 parent 5fca9d2 commit 6bba9ec

1 file changed

Lines changed: 19 additions & 1 deletion

File tree

src/host/alsa/mod.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1065,7 +1065,25 @@ fn poll_for_period(
10651065

10661066
let res = alsa::poll::poll(descriptors, *poll_timeout)?;
10671067
if res == 0 {
1068-
// poll() returned 0: either a timeout or a spurious wakeup. Nothing to do.
1068+
// Timeout expired with no events. Query PCM state to handle cases where
1069+
// POLLERR/POLLHUP was not delivered before the timeout fired (e.g. some
1070+
// power-management suspend paths or VM/container ALSA shims).
1071+
match stream.handle.state() {
1072+
alsa::pcm::State::Disconnected => {
1073+
return Err(Error::with_message(
1074+
ErrorKind::DeviceNotAvailable,
1075+
"Device disconnected",
1076+
));
1077+
}
1078+
// Xrun with POLLERR missed: recover the same way the POLLERR path does.
1079+
alsa::pcm::State::XRun => {
1080+
return Err(ErrorKind::Xrun.into());
1081+
}
1082+
// Suspend with POLLHUP/POLLERR missed: attempt hardware resume.
1083+
alsa::pcm::State::Suspended => return try_resume(&stream.handle),
1084+
// No events and no error state: spurious wakeup, poll again.
1085+
_ => {}
1086+
}
10691087
return Ok(Poll::Pending);
10701088
}
10711089

0 commit comments

Comments
 (0)