use std::io;
use std::os::unix::io::RawFd;
#[derive(Debug)]
pub(crate) enum FlockOutcome {
Acquired,
Held,
Failed(io::Error),
}
const MAX_EINTR_RETRIES: u32 = 8;
pub(crate) fn resolve<F>(mut call: F) -> FlockOutcome
where
F: FnMut() -> Result<(), i32>,
{
for _ in 0..=MAX_EINTR_RETRIES {
match call() {
Ok(()) => return FlockOutcome::Acquired,
Err(errno) if errno == libc::EINTR => continue,
Err(errno) if errno == libc::EWOULDBLOCK => return FlockOutcome::Held,
Err(errno) => return FlockOutcome::Failed(io::Error::from_raw_os_error(errno)),
}
}
FlockOutcome::Failed(io::Error::from_raw_os_error(libc::EINTR))
}
pub(crate) fn exclusive(fd: RawFd, non_blocking: bool) -> FlockOutcome {
let op = if non_blocking {
libc::LOCK_EX | libc::LOCK_NB
} else {
libc::LOCK_EX
};
resolve(|| {
if unsafe { libc::flock(fd, op) } == 0 {
Ok(())
} else {
Err(io::Error::last_os_error()
.raw_os_error()
.unwrap_or(libc::EIO))
}
})
}