pub struct LowFdGuard { /* private fields */ }Expand description
Occupies every currently-free descriptor below [FIRST_INTERNAL_FD] so that
opens performed while it is alive are pushed above the user’s fd range.
Releases them on drop.
Descriptors that are ALREADY open are left alone — they may be the user’s
(zshrs 3>&1 -c '…' is legal), and stealing them would be the very bug this
exists to prevent.
§Thread safety
Claiming is done exclusively through fcntl(F_DUPFD_CLOEXEC), which asks the
kernel for the lowest free descriptor and allocates it in one atomic step.
The guard therefore only ever owns descriptors the kernel just handed it, and
never names a target descriptor.
The previous implementation probed each slot with fcntl(fd, F_GETFD) and
then dup2’d onto it. Those are two syscalls with a gap in between, and
dup2 silently closes whatever occupies its target. Under the interactive
boot — where compinit ships its cache rebuild to a zshrs-worker-N thread
(ext_builtins.rs, worker_pool.submit) while the main thread is still
sourcing the user’s rc files — a concurrent File::open could land on a slot
this guard had already probed as free. The dup2 then closed a live
OwnedFd out from under its owner, and drop on that owner tripped std’s
debug_assert_fd_is_open, aborting with
IO Safety violation: owned file descriptor already closed.
Implementations§
Source§impl LowFdGuard
impl LowFdGuard
Trait Implementations§
Source§impl Default for LowFdGuard
impl Default for LowFdGuard
Source§impl Drop for LowFdGuard
impl Drop for LowFdGuard
Auto Trait Implementations§
impl Freeze for LowFdGuard
impl RefUnwindSafe for LowFdGuard
impl Send for LowFdGuard
impl Sync for LowFdGuard
impl Unpin for LowFdGuard
impl UnsafeUnpin for LowFdGuard
impl UnwindSafe for LowFdGuard
Blanket Implementations§
Source§impl<T> ArchivePointee for T
impl<T> ArchivePointee for T
Source§type ArchivedMetadata = ()
type ArchivedMetadata = ()
Source§fn pointer_metadata(
_: &<T as ArchivePointee>::ArchivedMetadata,
) -> <T as Pointee>::Metadata
fn pointer_metadata( _: &<T as ArchivePointee>::ArchivedMetadata, ) -> <T as Pointee>::Metadata
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<F, W, T, D> Deserialize<With<T, W>, D> for F
impl<F, W, T, D> Deserialize<With<T, W>, D> for F
impl<A, B, T> HttpServerConnExec<A, B> for Twhere
B: Body,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more