Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 4 additions & 50 deletions src/sys/fd.rs
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -102,46 +100,10 @@ impl FdExt for Fd {
};

let result: Option<sys::Error> = {
#[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)]
{
Expand Down Expand Up @@ -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<c_int, MakeLibUvOwnedError> {
let out = bun_core::fd::uv_open_osfhandle(in_);
Expand Down
34 changes: 20 additions & 14 deletions src/sys/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Error> {
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<usize> {
Expand Down
Loading