use io_lifetimes::BorrowedFd;
use posish::fs::{fcntl_getfd, fcntl_setfd, FdFlags};
use std::io;
pub(crate) fn ensure_cloexec(fd: BorrowedFd<'_>) -> io::Result<()> {
use std::sync::atomic::{AtomicUsize, Ordering};
const OPEN_CLOEXEC_UNKNOWN: usize = 0;
const OPEN_CLOEXEC_SUPPORTED: usize = 1;
const OPEN_CLOEXEC_NOTSUPPORTED: usize = 2;
static OPEN_CLOEXEC: AtomicUsize = AtomicUsize::new(OPEN_CLOEXEC_UNKNOWN);
let need_to_set;
match OPEN_CLOEXEC.load(Ordering::Relaxed) {
OPEN_CLOEXEC_UNKNOWN => {
need_to_set = !get_cloexec(fd)?;
OPEN_CLOEXEC.store(
if need_to_set {
OPEN_CLOEXEC_NOTSUPPORTED
} else {
OPEN_CLOEXEC_SUPPORTED
},
Ordering::Relaxed,
);
}
OPEN_CLOEXEC_SUPPORTED => need_to_set = false,
OPEN_CLOEXEC_NOTSUPPORTED => need_to_set = true,
_ => unreachable!(),
}
if need_to_set {
set_cloexec(fd)?;
}
Ok(())
}
fn get_cloexec(fd: BorrowedFd<'_>) -> io::Result<bool> {
Ok(fcntl_getfd(&fd)?.contains(FdFlags::CLOEXEC))
}
fn set_cloexec(fd: BorrowedFd<'_>) -> io::Result<()> {
let previous = fcntl_getfd(&fd)?;
let new = previous | FdFlags::CLOEXEC;
if new != previous {
fcntl_setfd(&fd, new)?;
}
Ok(())
}