diff --git a/src/sys/fd.rs b/src/sys/fd.rs index add0523b5926..d5ba61b6de5c 100644 --- a/src/sys/fd.rs +++ b/src/sys/fd.rs @@ -1,7 +1,5 @@ -#[cfg(any(target_os = "macos", windows))] -use core::ffi::c_int; #[cfg(windows)] -use core::ffi::c_void; +use core::ffi::{c_int, c_void}; // `Fd` (the packed handle struct + pure-data accessors) is canonical in // bun_core. This file adds the syscall-touching surface as an extension trait. @@ -102,46 +100,10 @@ impl FdExt for Fd { }; let result: Option = { - #[cfg(any(target_os = "linux", target_os = "android"))] + #[cfg(unix)] { debug_assert!(self.native() >= 0); - // Raw `SYS_close` via rustix — no glibc wrapper (which is a - // pthread cancellation point). Never retry on EINTR. - match sys::linux_syscall::close(self.native()) { - Err(e) if e == libc::EBADF => Some(sys::Error { - errno: sys::E::EBADF as _, - syscall: sys::Tag::close, - fd: self, - ..Default::default() - }), - _ => None, - } - } - #[cfg(target_os = "freebsd")] - { - debug_assert!(self.native() >= 0); - match sys::get_errno(sys::safe_libc::close(self.native())) { - sys::E::EBADF => Some(sys::Error { - errno: sys::E::EBADF as _, - syscall: sys::Tag::close, - fd: self, - ..Default::default() - }), - _ => None, - } - } - #[cfg(target_os = "macos")] - { - debug_assert!(self.native() >= 0); - match sys::get_errno(close_nocancel(self.native())) { - sys::E::EBADF => Some(sys::Error { - errno: sys::E::EBADF as _, - syscall: sys::Tag::close, - fd: self, - ..Default::default() - }), - _ => None, - } + sys::posix_impl::close_error(self) } #[cfg(windows)] { @@ -293,16 +255,8 @@ impl FdExt for Fd { // bun.sys.File. // ────────────────────────────────────────────────────────────────────────── -// Platform helpers (Windows libuv / macOS close_nocancel). +// Platform helpers (Windows libuv). // ────────────────────────────────────────────────────────────────────────── -#[cfg(target_os = "macos")] -unsafe extern "C" { - // Darwin libc: close that doesn't get interrupted by pthread cancellation. - // By-value `c_int` only; bad fd → `EBADF`, no UB. - #[link_name = "close$NOCANCEL"] - safe fn close_nocancel(fd: c_int) -> c_int; -} - #[cfg(windows)] fn uv_open_osfhandle(in_: *mut c_void) -> Result { let out = bun_core::fd::uv_open_osfhandle(in_); diff --git a/src/sys/lib.rs b/src/sys/lib.rs index e1e5255b4296..00aef5536e89 100644 --- a/src/sys/lib.rs +++ b/src/sys/lib.rs @@ -1934,29 +1934,35 @@ mod posix_impl { } openat(dir, path, flags, mode) } - pub fn close(fd: Fd) -> Maybe<()> { - // Call close ONCE; never retry on EINTR (Linux may have already - // released the fd, retrying would close someone else's). Only EBADF surfaces. - // Darwin uses `close$NOCANCEL` (avoid pthread cancellation point). + /// `close(2)`, once. Linux releases the fd even on EINTR, so a retry could close another thread's fd. `Err` is the errno. + #[inline] + pub(crate) fn close_once(fd: Fd) -> core::result::Result<(), i32> { #[cfg(any(target_os = "linux", target_os = "android"))] { - return match super::linux_syscall::close(fd.native()) { - Err(e) if e == libc::EBADF => { - Err(Error::from_code_int(libc::EBADF, Tag::close).with_fd(fd)) - } - _ => Ok(()), - }; + super::linux_syscall::close(fd.native()) } #[cfg(not(any(target_os = "linux", target_os = "android")))] { + // Darwin uses `close$NOCANCEL` (avoid pthread cancellation point). #[cfg(target_os = "macos")] let rc = super::nocancel::close(fd.native()); #[cfg(not(target_os = "macos"))] let rc = safe_libc::close(fd.native()); - if rc < 0 && last_errno() == libc::EBADF { - return Err(Error::from_code_int(libc::EBADF, Tag::close).with_fd(fd)); - } - Ok(()) + if rc < 0 { Err(last_errno()) } else { Ok(()) } + } + } + /// Closes `fd` and returns the error that callers see. Only EBADF surfaces. + #[inline] + pub(crate) fn close_error(fd: Fd) -> Option { + match close_once(fd) { + Err(libc::EBADF) => Some(Error::from_code_int(libc::EBADF, Tag::close).with_fd(fd)), + _ => None, + } + } + pub fn close(fd: Fd) -> Maybe<()> { + match close_error(fd) { + Some(err) => Err(err), + None => Ok(()), } } pub fn read(fd: Fd, buf: &mut [u8]) -> Maybe {