host_env: Use close_range syscall (FreeBSD/Linux) (#9016)

FreeBSD and Linux implement a syscall for close_range. It's faster than
looping through the file descriptors to close which would cause a
context switch per descriptor. CPython also uses the syscall where
available.

See:
* https://man.freebsd.org/cgi/man.cgi?close_range(2)
* https://man7.org/linux/man-pages/man2/close_range.2.html
* https://github.com/python/cpython/blob/5a22a62b96a68c2dd31784c5e3427ad7b365388a/Python/fileutils.c#L3193-L3231
This commit is contained in:
Joshua Megnauth authored and GitHub committed 2026-10-10 09:08:44 +09:00
1 parent f5b6526c49
commit 5c40bb25af
1 file changed
+34 -1
+34 -1
View File
@@ -348,8 +348,41 @@ pub fn close(fd: Owned) -> io::Result<()> {
_close(fd.into_raw())
}
#[cfg(not(any(target_os = "freebsd", target_os = "linux")))]
pub fn closerange(fd_low: Raw, fd_high: Raw) {
for fd in fd_low..fd_high {
close_range_slow(fd_low, fd_high);
}
// _Py_closerange
#[cfg(any(target_os = "freebsd", target_os = "linux"))]
pub fn closerange(fd_low: Raw, fd_high: Raw) {
// CPython clamps low to 0.
let fd_low = fd_low.max(0);
// close_range(2) is [low, high] whereas CPython's is [low, high).
if fd_high < fd_low {
return;
}
let high = fd_high - 1;
if close_range(fd_low as _, high as _) == -1
&& io::Error::last_os_error().raw_os_error() == Some(libc::ENOSYS)
{
close_range_slow(fd_low, fd_high);
}
}
#[cfg(target_os = "freebsd")]
fn close_range(low: ffi::c_uint, high: ffi::c_uint) -> ffi::c_int {
unsafe { libc::close_range(low, high, 0) as ffi::c_int }
}
#[cfg(target_os = "linux")]
fn close_range(low: ffi::c_uint, high: ffi::c_uint) -> ffi::c_int {
unsafe { libc::syscall(libc::SYS_close_range, low, high, 0) as ffi::c_int }
}
fn close_range_slow(low: Raw, high: Raw) {
for fd in low..high {
// The range can contain closed descriptors, so it cannot use Owned.
let _ = _close(fd);
}