mirror of
https://github.com/wez/wezterm.git
synced 2024-12-23 21:32:13 +03:00
filedescriptor: probe and remember filetype at construction
This avoids a deadlock waiting for the named pipe information to be returned if we're probing during drop(). This does make the OwnedHandle struct slightly larger on windows.
This commit is contained in:
parent
5f9bb5c3b0
commit
33933ec523
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "filedescriptor"
|
name = "filedescriptor"
|
||||||
version = "0.4.0"
|
version = "0.5.0"
|
||||||
authors = ["Wez Furlong"]
|
authors = ["Wez Furlong"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
repository = "https://github.com/wez/wzsh"
|
repository = "https://github.com/wez/wzsh"
|
||||||
|
@ -97,6 +97,7 @@
|
|||||||
//! # Ok::<(), Error>(())
|
//! # Ok::<(), Error>(())
|
||||||
//! ```
|
//! ```
|
||||||
use failure::Fallible;
|
use failure::Fallible;
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
mod unix;
|
mod unix;
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
@ -147,6 +148,7 @@ pub trait FromRawSocketDescriptor {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct OwnedHandle {
|
pub struct OwnedHandle {
|
||||||
handle: RawFileDescriptor,
|
handle: RawFileDescriptor,
|
||||||
|
handle_type: HandleType,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OwnedHandle {
|
impl OwnedHandle {
|
||||||
@ -154,8 +156,10 @@ impl OwnedHandle {
|
|||||||
/// the system `RawFileDescriptor` type. This consumes the parameter
|
/// the system `RawFileDescriptor` type. This consumes the parameter
|
||||||
/// and replaces it with an `OwnedHandle` instance.
|
/// and replaces it with an `OwnedHandle` instance.
|
||||||
pub fn new<F: IntoRawFileDescriptor>(f: F) -> Self {
|
pub fn new<F: IntoRawFileDescriptor>(f: F) -> Self {
|
||||||
|
let handle = f.into_raw_file_descriptor();
|
||||||
Self {
|
Self {
|
||||||
handle: f.into_raw_file_descriptor(),
|
handle,
|
||||||
|
handle_type: Self::probe_handle_type(handle),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,7 +170,7 @@ impl OwnedHandle {
|
|||||||
/// The returned handle has a separate lifetime from the source, but
|
/// The returned handle has a separate lifetime from the source, but
|
||||||
/// references the same object at the kernel level.
|
/// references the same object at the kernel level.
|
||||||
pub fn try_clone(&self) -> Fallible<Self> {
|
pub fn try_clone(&self) -> Fallible<Self> {
|
||||||
Self::dup(self)
|
Self::dup_impl(self, self.handle_type)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempt to duplicate the underlying handle from an object that is
|
/// Attempt to duplicate the underlying handle from an object that is
|
||||||
@ -177,7 +181,7 @@ impl OwnedHandle {
|
|||||||
/// The returned handle has a separate lifetime from the source, but
|
/// The returned handle has a separate lifetime from the source, but
|
||||||
/// references the same object at the kernel level.
|
/// references the same object at the kernel level.
|
||||||
pub fn dup<F: AsRawFileDescriptor>(f: &F) -> Fallible<Self> {
|
pub fn dup<F: AsRawFileDescriptor>(f: &F) -> Fallible<Self> {
|
||||||
Self::dup_impl(f)
|
Self::dup_impl(f, Default::default())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,8 @@ use crate::{
|
|||||||
use failure::{bail, Fallible};
|
use failure::{bail, Fallible};
|
||||||
use std::os::unix::prelude::*;
|
use std::os::unix::prelude::*;
|
||||||
|
|
||||||
|
pub(crate) type HandleType = ();
|
||||||
|
|
||||||
/// `RawFileDescriptor` is a platform independent type alias for the
|
/// `RawFileDescriptor` is a platform independent type alias for the
|
||||||
/// underlying platform file descriptor type. It is primarily useful
|
/// underlying platform file descriptor type. It is primarily useful
|
||||||
/// for avoiding using `cfg` blocks in platform independent code.
|
/// for avoiding using `cfg` blocks in platform independent code.
|
||||||
@ -75,7 +77,10 @@ impl IntoRawFd for OwnedHandle {
|
|||||||
|
|
||||||
impl FromRawFd for OwnedHandle {
|
impl FromRawFd for OwnedHandle {
|
||||||
unsafe fn from_raw_fd(fd: RawFd) -> Self {
|
unsafe fn from_raw_fd(fd: RawFd) -> Self {
|
||||||
Self { handle: fd }
|
Self {
|
||||||
|
handle: fd,
|
||||||
|
handle_type: (),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,14 +113,20 @@ impl OwnedHandle {
|
|||||||
std::io::Error::last_os_error()
|
std::io::Error::last_os_error()
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
let mut owned = OwnedHandle { handle: duped };
|
let mut owned = OwnedHandle {
|
||||||
|
handle: duped,
|
||||||
|
handle_type: (),
|
||||||
|
};
|
||||||
owned.cloexec()?;
|
owned.cloexec()?;
|
||||||
Ok(owned)
|
Ok(owned)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn dup_impl<F: AsRawFileDescriptor>(fd: &F) -> Fallible<Self> {
|
pub(crate) fn dup_impl<F: AsRawFileDescriptor>(
|
||||||
|
fd: &F,
|
||||||
|
handle_type: HandleType,
|
||||||
|
) -> Fallible<Self> {
|
||||||
let fd = fd.as_raw_file_descriptor();
|
let fd = fd.as_raw_file_descriptor();
|
||||||
let duped = unsafe { libc::fcntl(fd, libc::F_DUPFD_CLOEXEC, 0) };
|
let duped = unsafe { libc::fcntl(fd, libc::F_DUPFD_CLOEXEC, 0) };
|
||||||
if duped == -1 {
|
if duped == -1 {
|
||||||
@ -128,9 +139,16 @@ impl OwnedHandle {
|
|||||||
bail!("dup of fd {} failed: {:?}", fd, err)
|
bail!("dup of fd {} failed: {:?}", fd, err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Ok(OwnedHandle { handle: duped })
|
Ok(OwnedHandle {
|
||||||
|
handle: duped,
|
||||||
|
handle_type,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn probe_handle_type(_handle: RawFileDescriptor) -> HandleType {
|
||||||
|
()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::io::Read for FileDescriptor {
|
impl std::io::Read for FileDescriptor {
|
||||||
@ -200,10 +218,16 @@ impl Pipe {
|
|||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
let read = FileDescriptor {
|
let read = FileDescriptor {
|
||||||
handle: OwnedHandle { handle: fds[0] },
|
handle: OwnedHandle {
|
||||||
|
handle: fds[0],
|
||||||
|
handle_type: (),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
let write = FileDescriptor {
|
let write = FileDescriptor {
|
||||||
handle: OwnedHandle { handle: fds[1] },
|
handle: OwnedHandle {
|
||||||
|
handle: fds[1],
|
||||||
|
handle_type: (),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
Ok(Pipe { read, write })
|
Ok(Pipe { read, write })
|
||||||
}
|
}
|
||||||
@ -251,10 +275,16 @@ pub fn socketpair_impl() -> Fallible<(FileDescriptor, FileDescriptor)> {
|
|||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
let read = FileDescriptor {
|
let read = FileDescriptor {
|
||||||
handle: OwnedHandle { handle: fds[0] },
|
handle: OwnedHandle {
|
||||||
|
handle: fds[0],
|
||||||
|
handle_type: (),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
let write = FileDescriptor {
|
let write = FileDescriptor {
|
||||||
handle: OwnedHandle { handle: fds[1] },
|
handle: OwnedHandle {
|
||||||
|
handle: fds[1],
|
||||||
|
handle_type: (),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
Ok((read, write))
|
Ok((read, write))
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,21 @@ pub type RawFileDescriptor = RawHandle;
|
|||||||
/// for avoiding using `cfg` blocks in platform independent code.
|
/// for avoiding using `cfg` blocks in platform independent code.
|
||||||
pub type SocketDescriptor = SOCKET;
|
pub type SocketDescriptor = SOCKET;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub(crate) enum HandleType {
|
||||||
|
Char,
|
||||||
|
Disk,
|
||||||
|
Pipe,
|
||||||
|
Socket,
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for HandleType {
|
||||||
|
fn default() -> Self {
|
||||||
|
HandleType::Unknown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: AsRawHandle> AsRawFileDescriptor for T {
|
impl<T: AsRawHandle> AsRawFileDescriptor for T {
|
||||||
fn as_raw_file_descriptor(&self) -> RawFileDescriptor {
|
fn as_raw_file_descriptor(&self) -> RawFileDescriptor {
|
||||||
self.as_raw_handle()
|
self.as_raw_handle()
|
||||||
@ -72,34 +87,43 @@ impl<T: FromRawSocket> FromRawSocketDescriptor for T {
|
|||||||
|
|
||||||
unsafe impl Send for OwnedHandle {}
|
unsafe impl Send for OwnedHandle {}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
impl OwnedHandle {
|
||||||
enum HandleType {
|
fn probe_handle_type_if_unknown(handle: HANDLE, handle_type: HandleType) -> HandleType {
|
||||||
Char,
|
match handle_type {
|
||||||
Disk,
|
HandleType::Unknown => Self::probe_handle_type(handle),
|
||||||
Pipe,
|
t => t,
|
||||||
Socket,
|
}
|
||||||
Unknown,
|
}
|
||||||
}
|
|
||||||
|
pub(crate) fn probe_handle_type(handle: HANDLE) -> HandleType {
|
||||||
fn handle_type(handle: HANDLE) -> HandleType {
|
match unsafe { GetFileType(handle) } {
|
||||||
match unsafe { GetFileType(handle) } {
|
FILE_TYPE_CHAR => HandleType::Char,
|
||||||
FILE_TYPE_CHAR => HandleType::Char,
|
FILE_TYPE_DISK => HandleType::Disk,
|
||||||
FILE_TYPE_DISK => HandleType::Disk,
|
FILE_TYPE_PIPE => {
|
||||||
FILE_TYPE_PIPE => {
|
// Could be a pipe or a socket. Test if for pipeness
|
||||||
// Could be a pipe or a socket. Test if for pipeness
|
let mut flags = 0;
|
||||||
let mut flags = 0;
|
let mut out_buf = 0;
|
||||||
let mut out_buf = 0;
|
let mut in_buf = 0;
|
||||||
let mut in_buf = 0;
|
let mut inst = 0;
|
||||||
let mut inst = 0;
|
if unsafe {
|
||||||
if unsafe { GetNamedPipeInfo(handle, &mut flags, &mut out_buf, &mut in_buf, &mut inst) }
|
GetNamedPipeInfo(handle, &mut flags, &mut out_buf, &mut in_buf, &mut inst)
|
||||||
!= 0
|
} != 0
|
||||||
{
|
{
|
||||||
HandleType::Pipe
|
HandleType::Pipe
|
||||||
} else {
|
} else {
|
||||||
HandleType::Socket
|
HandleType::Socket
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
_ => HandleType::Unknown,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_socket_handle(&self) -> bool {
|
||||||
|
match self.handle_type {
|
||||||
|
HandleType::Socket => true,
|
||||||
|
HandleType::Unknown => Self::probe_handle_type(self.handle) == HandleType::Socket,
|
||||||
|
_ => false,
|
||||||
}
|
}
|
||||||
_ => HandleType::Unknown,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,7 +131,7 @@ impl Drop for OwnedHandle {
|
|||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if self.handle != INVALID_HANDLE_VALUE as _ && !self.handle.is_null() {
|
if self.handle != INVALID_HANDLE_VALUE as _ && !self.handle.is_null() {
|
||||||
unsafe {
|
unsafe {
|
||||||
if handle_type(self.handle as _) == HandleType::Socket {
|
if self.is_socket_handle() {
|
||||||
closesocket(self.handle as _);
|
closesocket(self.handle as _);
|
||||||
} else {
|
} else {
|
||||||
CloseHandle(self.handle as _);
|
CloseHandle(self.handle as _);
|
||||||
@ -119,18 +143,29 @@ impl Drop for OwnedHandle {
|
|||||||
|
|
||||||
impl FromRawHandle for OwnedHandle {
|
impl FromRawHandle for OwnedHandle {
|
||||||
unsafe fn from_raw_handle(handle: RawHandle) -> Self {
|
unsafe fn from_raw_handle(handle: RawHandle) -> Self {
|
||||||
OwnedHandle { handle }
|
OwnedHandle {
|
||||||
|
handle,
|
||||||
|
handle_type: Self::probe_handle_type(handle),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OwnedHandle {
|
impl OwnedHandle {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn dup_impl<F: AsRawFileDescriptor>(f: &F) -> Fallible<Self> {
|
pub(crate) fn dup_impl<F: AsRawFileDescriptor>(
|
||||||
|
f: &F,
|
||||||
|
handle_type: HandleType,
|
||||||
|
) -> Fallible<Self> {
|
||||||
let handle = f.as_raw_file_descriptor();
|
let handle = f.as_raw_file_descriptor();
|
||||||
if handle == INVALID_HANDLE_VALUE as _ || handle.is_null() {
|
if handle == INVALID_HANDLE_VALUE as _ || handle.is_null() {
|
||||||
return Ok(OwnedHandle { handle });
|
return Ok(OwnedHandle {
|
||||||
|
handle,
|
||||||
|
handle_type,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let handle_type = Self::probe_handle_type_if_unknown(handle, handle_type);
|
||||||
|
|
||||||
let proc = unsafe { GetCurrentProcess() };
|
let proc = unsafe { GetCurrentProcess() };
|
||||||
let mut duped = INVALID_HANDLE_VALUE;
|
let mut duped = INVALID_HANDLE_VALUE;
|
||||||
let ok = unsafe {
|
let ok = unsafe {
|
||||||
@ -149,6 +184,7 @@ impl OwnedHandle {
|
|||||||
} else {
|
} else {
|
||||||
Ok(OwnedHandle {
|
Ok(OwnedHandle {
|
||||||
handle: duped as *mut _,
|
handle: duped as *mut _,
|
||||||
|
handle_type,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -201,10 +237,7 @@ impl FromRawHandle for FileDescriptor {
|
|||||||
impl IntoRawSocket for FileDescriptor {
|
impl IntoRawSocket for FileDescriptor {
|
||||||
fn into_raw_socket(self) -> RawSocket {
|
fn into_raw_socket(self) -> RawSocket {
|
||||||
// FIXME: this isn't a guaranteed conversion!
|
// FIXME: this isn't a guaranteed conversion!
|
||||||
debug_assert_eq!(
|
debug_assert!(self.handle.is_socket_handle());
|
||||||
handle_type(self.handle.as_raw_handle() as _),
|
|
||||||
HandleType::Socket
|
|
||||||
);
|
|
||||||
self.handle.into_raw_handle() as RawSocket
|
self.handle.into_raw_handle() as RawSocket
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -212,10 +245,7 @@ impl IntoRawSocket for FileDescriptor {
|
|||||||
impl AsRawSocket for FileDescriptor {
|
impl AsRawSocket for FileDescriptor {
|
||||||
fn as_raw_socket(&self) -> RawSocket {
|
fn as_raw_socket(&self) -> RawSocket {
|
||||||
// FIXME: this isn't a guaranteed conversion!
|
// FIXME: this isn't a guaranteed conversion!
|
||||||
debug_assert_eq!(
|
debug_assert!(self.handle.is_socket_handle());
|
||||||
handle_type(self.handle.as_raw_handle() as _),
|
|
||||||
HandleType::Socket
|
|
||||||
);
|
|
||||||
self.handle.as_raw_handle() as RawSocket
|
self.handle.as_raw_handle() as RawSocket
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -290,10 +320,16 @@ impl Pipe {
|
|||||||
}
|
}
|
||||||
Ok(Pipe {
|
Ok(Pipe {
|
||||||
read: FileDescriptor {
|
read: FileDescriptor {
|
||||||
handle: OwnedHandle { handle: read as _ },
|
handle: OwnedHandle {
|
||||||
|
handle: read as _,
|
||||||
|
handle_type: HandleType::Pipe,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
write: FileDescriptor {
|
write: FileDescriptor {
|
||||||
handle: OwnedHandle { handle: write as _ },
|
handle: OwnedHandle {
|
||||||
|
handle: write as _,
|
||||||
|
handle_type: HandleType::Pipe,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -326,7 +362,10 @@ fn socket(af: i32, sock_type: i32, proto: i32) -> Fallible<FileDescriptor> {
|
|||||||
bail!("socket failed: {}", IoError::last_os_error());
|
bail!("socket failed: {}", IoError::last_os_error());
|
||||||
}
|
}
|
||||||
Ok(FileDescriptor {
|
Ok(FileDescriptor {
|
||||||
handle: OwnedHandle { handle: s as _ },
|
handle: OwnedHandle {
|
||||||
|
handle: s as _,
|
||||||
|
handle_type: HandleType::Socket,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -392,6 +431,7 @@ pub fn socketpair_impl() -> Fallible<(FileDescriptor, FileDescriptor)> {
|
|||||||
let server = FileDescriptor {
|
let server = FileDescriptor {
|
||||||
handle: OwnedHandle {
|
handle: OwnedHandle {
|
||||||
handle: server as _,
|
handle: server as _,
|
||||||
|
handle_type: HandleType::Socket,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user