use std::os::fd::RawFd;
use std::time::Duration;
use nix::errno::Errno;
use nix::poll::{PollFd, PollTimeout, poll};
pub(crate) fn poll_eintr_safe(
pfds: &mut [PollFd<'_>],
timeout: Duration,
) -> Result<i32, std::io::Error> {
let pt = PollTimeout::try_from(timeout).unwrap_or(PollTimeout::MAX);
loop {
match poll(pfds, pt) {
Ok(n) => return Ok(n),
Err(Errno::EINTR) => continue,
Err(e) => return Err(e.into()),
}
}
}
pub(crate) fn sendto_kick_eintr_safe(fd: RawFd, flags: i32) -> Result<(), std::io::Error> {
loop {
let ret = unsafe { libc::sendto(fd, std::ptr::null(), 0, flags, std::ptr::null(), 0) };
if ret >= 0 {
return Ok(());
}
let err = std::io::Error::last_os_error();
match err.raw_os_error() {
Some(libc::EINTR) => continue,
Some(libc::EAGAIN) | Some(libc::ENOBUFS) => return Ok(()),
_ => return Err(err),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::os::fd::{AsFd, BorrowedFd};
#[test]
fn poll_eintr_safe_times_out() {
let raw_fd = 0;
let fd = unsafe { BorrowedFd::borrow_raw(raw_fd) };
let mut pfds = [PollFd::new(fd.as_fd(), nix::poll::PollFlags::POLLIN)];
let n = poll_eintr_safe(&mut pfds, Duration::from_millis(10)).unwrap();
assert!(n >= 0);
}
}