From 0b58f2977252739629b5175043d705f7fc76ea8d Mon Sep 17 00:00:00 2001 From: not_a_seagull Date: Sun, 23 Jan 2022 11:43:25 -0800 Subject: Replace the IoVec type with IoSlice and IoSliceMut --- src/sys/sendfile.rs | 16 ++--- src/sys/socket/mod.rs | 44 +++++++------- src/sys/uio.rs | 163 +++++++++++++++++++++++++++++--------------------- 3 files changed, 124 insertions(+), 99 deletions(-) (limited to 'src/sys') diff --git a/src/sys/sendfile.rs b/src/sys/sendfile.rs index 5ec0b526..2ebcdf48 100644 --- a/src/sys/sendfile.rs +++ b/src/sys/sendfile.rs @@ -68,13 +68,13 @@ cfg_if! { target_os = "freebsd", target_os = "ios", target_os = "macos"))] { - use crate::sys::uio::IoVec; + use std::io::IoSlice; - #[derive(Clone, Debug, Eq, Hash, PartialEq)] + #[derive(Clone, Debug)] struct SendfileHeaderTrailer<'a>( libc::sf_hdtr, - Option>>, - Option>>, + Option>>, + Option>>, ); impl<'a> SendfileHeaderTrailer<'a> { @@ -82,10 +82,10 @@ cfg_if! { headers: Option<&'a [&'a [u8]]>, trailers: Option<&'a [&'a [u8]]> ) -> SendfileHeaderTrailer<'a> { - let header_iovecs: Option>> = - headers.map(|s| s.iter().map(|b| IoVec::from_slice(b)).collect()); - let trailer_iovecs: Option>> = - trailers.map(|s| s.iter().map(|b| IoVec::from_slice(b)).collect()); + let header_iovecs: Option>> = + headers.map(|s| s.iter().map(|b| IoSlice::new(b)).collect()); + let trailer_iovecs: Option>> = + trailers.map(|s| s.iter().map(|b| IoSlice::new(b)).collect()); SendfileHeaderTrailer( libc::sf_hdtr { headers: { diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 8dac6eda..c6613892 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -14,10 +14,8 @@ use std::net; #[cfg(feature = "uio")] use crate::sys::time::TimeSpec; #[cfg(feature = "uio")] -use crate::sys::{ - time::TimeVal, - uio::IoVec -}; +use crate::sys::time::TimeVal; +use std::io::{IoSlice, IoSliceMut}; #[deny(missing_docs)] mod addr; @@ -657,8 +655,8 @@ pub enum ControlMessageOwned { /// ``` /// # #[macro_use] extern crate nix; /// # use nix::sys::socket::*; - /// # use nix::sys::uio::IoVec; /// # use nix::sys::time::*; + /// # use std::io::{IoSlice, IoSliceMut}; /// # use std::time::*; /// # use std::str::FromStr; /// # fn main() { @@ -676,15 +674,15 @@ pub enum ControlMessageOwned { /// // Get initial time /// let time0 = SystemTime::now(); /// // Send the message - /// let iov = [IoVec::from_slice(message)]; + /// let iov = [IoSlice::new(message)]; /// let flags = MsgFlags::empty(); /// let l = sendmsg(in_socket, &iov, &[], flags, Some(&address)).unwrap(); /// assert_eq!(message.len(), l); /// // Receive the message /// let mut buffer = vec![0u8; message.len()]; /// let mut cmsgspace = cmsg_space!(TimeVal); - /// let iov = [IoVec::from_mut_slice(&mut buffer)]; - /// let r = recvmsg::(in_socket, &iov, Some(&mut cmsgspace), flags) + /// let mut iov = [IoSliceMut::new(&mut buffer)]; + /// let r = recvmsg::(in_socket, &mut iov, Some(&mut cmsgspace), flags) /// .unwrap(); /// let rtime = match r.cmsgs().next() { /// Some(ControlMessageOwned::ScmTimestamp(rtime)) => rtime, @@ -1367,13 +1365,13 @@ impl<'a> ControlMessage<'a> { /// ``` /// # use nix::sys::socket::*; /// # use nix::unistd::pipe; -/// # use nix::sys::uio::IoVec; +/// # use std::io::IoSlice; /// let (fd1, fd2) = socketpair(AddressFamily::Unix, SockType::Stream, None, /// SockFlag::empty()) /// .unwrap(); /// let (r, w) = pipe().unwrap(); /// -/// let iov = [IoVec::from_slice(b"hello")]; +/// let iov = [IoSlice::new(b"hello")]; /// let fds = [r]; /// let cmsg = ControlMessage::ScmRights(&fds); /// sendmsg::<()>(fd1, &iov, &[cmsg], MsgFlags::empty(), None).unwrap(); @@ -1382,19 +1380,19 @@ impl<'a> ControlMessage<'a> { /// ``` /// # use nix::sys::socket::*; /// # use nix::unistd::pipe; -/// # use nix::sys::uio::IoVec; +/// # use std::io::IoSlice; /// # use std::str::FromStr; /// let localhost = SockaddrIn::from_str("1.2.3.4:8080").unwrap(); /// let fd = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), /// None).unwrap(); /// let (r, w) = pipe().unwrap(); /// -/// let iov = [IoVec::from_slice(b"hello")]; +/// let iov = [IoSlice::new(b"hello")]; /// let fds = [r]; /// let cmsg = ControlMessage::ScmRights(&fds); /// sendmsg(fd, &iov, &[cmsg], MsgFlags::empty(), Some(&localhost)).unwrap(); /// ``` -pub fn sendmsg(fd: RawFd, iov: &[IoVec<&[u8]>], cmsgs: &[ControlMessage], +pub fn sendmsg(fd: RawFd, iov: &[IoSlice<'_>], cmsgs: &[ControlMessage], flags: MsgFlags, addr: Option<&S>) -> Result where S: SockaddrLike { @@ -1420,7 +1418,7 @@ pub fn sendmsg(fd: RawFd, iov: &[IoVec<&[u8]>], cmsgs: &[ControlMessage], #[derive(Debug)] pub struct SendMmsgData<'a, I, C, S> where - I: AsRef<[IoVec<&'a [u8]>]>, + I: AsRef<[IoSlice<'a>]>, C: AsRef<[ControlMessage<'a>]>, S: SockaddrLike + 'a { @@ -1459,7 +1457,7 @@ pub fn sendmmsg<'a, I, C, S>( flags: MsgFlags ) -> Result> where - I: AsRef<[IoVec<&'a [u8]>]> + 'a, + I: AsRef<[IoSlice<'a>]> + 'a, C: AsRef<[ControlMessage<'a>]> + 'a, S: SockaddrLike + 'a { @@ -1510,7 +1508,7 @@ pub fn sendmmsg<'a, I, C, S>( #[derive(Debug)] pub struct RecvMmsgData<'a, I> where - I: AsRef<[IoVec<&'a mut [u8]>]> + 'a, + I: AsRef<[IoSliceMut<'a>]> + 'a, { pub iov: I, pub cmsg_buffer: Option<&'a mut Vec>, @@ -1557,7 +1555,7 @@ pub fn recvmmsg<'a, I, S>( timeout: Option ) -> Result>> where - I: AsRef<[IoVec<&'a mut [u8]>]> + 'a, + I: AsRef<[IoSliceMut<'a>]> + 'a, S: Copy + SockaddrLike + 'a { let iter = data.into_iter(); @@ -1653,14 +1651,14 @@ unsafe fn read_mhdr<'a, 'b, S>( } } -unsafe fn pack_mhdr_to_receive<'a, I, S>( +unsafe fn pack_mhdr_to_receive<'outer, 'inner, I, S>( iov: I, cmsg_buffer: &mut Option<&mut Vec>, address: *mut S, ) -> (usize, msghdr) where - I: AsRef<[IoVec<&'a mut [u8]>]> + 'a, - S: SockaddrLike + 'a + I: AsRef<[IoSliceMut<'inner>]> + 'outer, + S: SockaddrLike + 'outer { let (msg_control, msg_controllen) = cmsg_buffer.as_mut() .map(|v| (v.as_mut_ptr(), v.capacity())) @@ -1691,7 +1689,7 @@ fn pack_mhdr_to_send<'a, I, C, S>( addr: Option<&S> ) -> msghdr where - I: AsRef<[IoVec<&'a [u8]>]>, + I: AsRef<[IoSlice<'a>]>, C: AsRef<[ControlMessage<'a>]>, S: SockaddrLike + 'a { @@ -1751,7 +1749,7 @@ fn pack_mhdr_to_send<'a, I, C, S>( /// /// # References /// [recvmsg(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html) -pub fn recvmsg<'a, S>(fd: RawFd, iov: &[IoVec<&mut [u8]>], +pub fn recvmsg<'a, 'outer, 'inner, S>(fd: RawFd, iov: &'outer mut [IoSliceMut<'inner>], mut cmsg_buffer: Option<&'a mut Vec>, flags: MsgFlags) -> Result> where S: SockaddrLike + 'a @@ -1759,7 +1757,7 @@ pub fn recvmsg<'a, S>(fd: RawFd, iov: &[IoVec<&mut [u8]>], let mut address = mem::MaybeUninit::uninit(); let (msg_controllen, mut mhdr) = unsafe { - pack_mhdr_to_receive(&iov, &mut cmsg_buffer, address.as_mut_ptr()) + pack_mhdr_to_receive::<_, S>(iov, &mut cmsg_buffer, address.as_mut_ptr()) }; let ret = unsafe { libc::recvmsg(fd, &mut mhdr, flags.bits()) }; diff --git a/src/sys/uio.rs b/src/sys/uio.rs index 42298300..ba6c64ef 100644 --- a/src/sys/uio.rs +++ b/src/sys/uio.rs @@ -3,13 +3,21 @@ use crate::Result; use crate::errno::Errno; use libc::{self, c_int, c_void, size_t, off_t}; +use std::io::{IoSlice, IoSliceMut}; use std::marker::PhantomData; use std::os::unix::io::RawFd; /// Low-level vectored write to a raw file descriptor /// /// See also [writev(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/writev.html) -pub fn writev(fd: RawFd, iov: &[IoVec<&[u8]>]) -> Result { +pub fn writev(fd: RawFd, iov: &[IoSlice<'_>]) -> Result { + // SAFETY: to quote the documentation for `IoSlice`: + // + // [IoSlice] is semantically a wrapper around a &[u8], but is + // guaranteed to be ABI compatible with the iovec type on Unix + // platforms. + // + // Because it is ABI compatible, a pointer cast here is valid let res = unsafe { libc::writev(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int) }; Errno::result(res).map(|r| r as usize) @@ -18,7 +26,8 @@ pub fn writev(fd: RawFd, iov: &[IoVec<&[u8]>]) -> Result { /// Low-level vectored read from a raw file descriptor /// /// See also [readv(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/readv.html) -pub fn readv(fd: RawFd, iov: &mut [IoVec<&mut [u8]>]) -> Result { +pub fn readv(fd: RawFd, iov: &mut [IoSliceMut<'_>]) -> Result { + // SAFETY: same as in writev(), IoSliceMut is ABI-compatible with iovec let res = unsafe { libc::readv(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int) }; Errno::result(res).map(|r| r as usize) @@ -32,10 +41,13 @@ pub fn readv(fd: RawFd, iov: &mut [IoVec<&mut [u8]>]) -> Result { /// See also: [`writev`](fn.writev.html) and [`pwrite`](fn.pwrite.html) #[cfg(not(target_os = "redox"))] #[cfg_attr(docsrs, doc(cfg(all())))] -pub fn pwritev(fd: RawFd, iov: &[IoVec<&[u8]>], +pub fn pwritev(fd: RawFd, iov: &[IoSlice<'_>], offset: off_t) -> Result { + #[cfg(target_env = "uclibc")] let offset = offset as libc::off64_t; // uclibc doesn't use off_t + + // SAFETY: same as in writev() let res = unsafe { libc::pwritev(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int, offset) }; @@ -52,10 +64,12 @@ pub fn pwritev(fd: RawFd, iov: &[IoVec<&[u8]>], /// See also: [`readv`](fn.readv.html) and [`pread`](fn.pread.html) #[cfg(not(target_os = "redox"))] #[cfg_attr(docsrs, doc(cfg(all())))] -pub fn preadv(fd: RawFd, iov: &[IoVec<&mut [u8]>], +pub fn preadv(fd: RawFd, iov: &mut [IoSliceMut<'_>], offset: off_t) -> Result { #[cfg(target_env = "uclibc")] let offset = offset as libc::off64_t; // uclibc doesn't use off_t + + // SAFETY: same as in readv() let res = unsafe { libc::preadv(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int, offset) }; @@ -92,9 +106,9 @@ pub fn pread(fd: RawFd, buf: &mut [u8], offset: off_t) -> Result{ /// A slice of memory in a remote process, starting at address `base` /// and consisting of `len` bytes. /// -/// This is the same underlying C structure as [`IoVec`](struct.IoVec.html), +/// This is the same underlying C structure as `IoSlice`, /// except that it refers to memory in some other process, and is -/// therefore not represented in Rust by an actual slice as `IoVec` is. It +/// therefore not represented in Rust by an actual slice as `IoSlice` is. It /// is used with [`process_vm_readv`](fn.process_vm_readv.html) /// and [`process_vm_writev`](fn.process_vm_writev.html). #[cfg(any(target_os = "linux", target_os = "android"))] @@ -108,13 +122,82 @@ pub struct RemoteIoVec { pub len: usize, } +/// A vector of buffers. +/// +/// Vectored I/O methods like [`writev`] and [`readv`] use this structure for +/// both reading and writing. Each `IoVec` specifies the base address and +/// length of an area in memory. +#[deprecated( + since = "0.24.0", + note = "`IoVec` is no longer used in the public interface, use `IoSlice` or `IoSliceMut` instead" +)] +#[repr(transparent)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub struct IoVec(pub(crate) libc::iovec, PhantomData); + +#[allow(deprecated)] +impl IoVec { + /// View the `IoVec` as a Rust slice. + #[deprecated( + since = "0.24.0", + note = "Use the `Deref` impl of `IoSlice` or `IoSliceMut` instead" + )] + #[inline] + pub fn as_slice(&self) -> &[u8] { + use std::slice; + + unsafe { + slice::from_raw_parts( + self.0.iov_base as *const u8, + self.0.iov_len as usize) + } + } +} + +#[allow(deprecated)] +impl<'a> IoVec<&'a [u8]> { + /// Create an `IoVec` from a Rust slice. + #[deprecated( + since = "0.24.0", + note = "Use `IoSlice::new` instead" + )] + pub fn from_slice(buf: &'a [u8]) -> IoVec<&'a [u8]> { + IoVec(libc::iovec { + iov_base: buf.as_ptr() as *mut c_void, + iov_len: buf.len() as size_t, + }, PhantomData) + } +} + +#[allow(deprecated)] +impl<'a> IoVec<&'a mut [u8]> { + /// Create an `IoVec` from a mutable Rust slice. + #[deprecated( + since = "0.24.0", + note = "Use `IoSliceMut::new` instead" + )] + pub fn from_mut_slice(buf: &'a mut [u8]) -> IoVec<&'a mut [u8]> { + IoVec(libc::iovec { + iov_base: buf.as_ptr() as *mut c_void, + iov_len: buf.len() as size_t, + }, PhantomData) + } +} + +// The only reason IoVec isn't automatically Send+Sync is because libc::iovec +// contains raw pointers. +#[allow(deprecated)] +unsafe impl Send for IoVec where T: Send {} +#[allow(deprecated)] +unsafe impl Sync for IoVec where T: Sync {} + feature! { #![feature = "process"] /// Write data directly to another process's virtual memory /// (see [`process_vm_writev`(2)]). /// -/// `local_iov` is a list of [`IoVec`]s containing the data to be written, +/// `local_iov` is a list of [`IoSlice`]s containing the data to be written, /// and `remote_iov` is a list of [`RemoteIoVec`]s identifying where the /// data should be written in the target process. On success, returns the /// number of bytes written, which will always be a whole @@ -129,12 +212,12 @@ feature! { /// /// [`process_vm_writev`(2)]: https://man7.org/linux/man-pages/man2/process_vm_writev.2.html /// [ptrace]: ../ptrace/index.html -/// [`IoVec`]: struct.IoVec.html +/// [`IoSlice`]: https://doc.rust-lang.org/std/io/struct.IoSlice.html /// [`RemoteIoVec`]: struct.RemoteIoVec.html #[cfg(all(any(target_os = "linux", target_os = "android"), not(target_env = "uclibc")))] pub fn process_vm_writev( pid: crate::unistd::Pid, - local_iov: &[IoVec<&[u8]>], + local_iov: &[IoSlice<'_>], remote_iov: &[RemoteIoVec]) -> Result { let res = unsafe { @@ -149,7 +232,7 @@ pub fn process_vm_writev( /// Read data directly from another process's virtual memory /// (see [`process_vm_readv`(2)]). /// -/// `local_iov` is a list of [`IoVec`]s containing the buffer to copy +/// `local_iov` is a list of [`IoSliceMut`]s containing the buffer to copy /// data into, and `remote_iov` is a list of [`RemoteIoVec`]s identifying /// where the source data is in the target process. On success, /// returns the number of bytes written, which will always be a whole @@ -164,12 +247,12 @@ pub fn process_vm_writev( /// /// [`process_vm_readv`(2)]: https://man7.org/linux/man-pages/man2/process_vm_readv.2.html /// [`ptrace`]: ../ptrace/index.html -/// [`IoVec`]: struct.IoVec.html +/// [`IoSliceMut`]: https://doc.rust-lang.org/std/io/struct.IoSliceMut.html /// [`RemoteIoVec`]: struct.RemoteIoVec.html #[cfg(all(any(target_os = "linux", target_os = "android"), not(target_env = "uclibc")))] pub fn process_vm_readv( pid: crate::unistd::Pid, - local_iov: &[IoVec<&mut [u8]>], + local_iov: &mut [IoSliceMut<'_>], remote_iov: &[RemoteIoVec]) -> Result { let res = unsafe { @@ -181,59 +264,3 @@ pub fn process_vm_readv( Errno::result(res).map(|r| r as usize) } } - -/// A vector of buffers. -/// -/// Vectored I/O methods like [`writev`] and [`readv`] use this structure for -/// both reading and writing. Each `IoVec` specifies the base address and -/// length of an area in memory. -#[repr(transparent)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub struct IoVec(pub(crate) libc::iovec, PhantomData); - -impl IoVec { - /// View the `IoVec` as a Rust slice. - #[inline] - pub fn as_slice(&self) -> &[u8] { - use std::slice; - - unsafe { - slice::from_raw_parts( - self.0.iov_base as *const u8, - self.0.iov_len as usize) - } - } -} - -impl<'a> IoVec<&'a [u8]> { - #[cfg(all(feature = "mount", target_os = "freebsd"))] - pub(crate) fn from_raw_parts(base: *mut c_void, len: usize) -> Self { - IoVec(libc::iovec { - iov_base: base, - iov_len: len - }, PhantomData) - } - - /// Create an `IoVec` from a Rust slice. - pub fn from_slice(buf: &'a [u8]) -> IoVec<&'a [u8]> { - IoVec(libc::iovec { - iov_base: buf.as_ptr() as *mut c_void, - iov_len: buf.len() as size_t, - }, PhantomData) - } -} - -impl<'a> IoVec<&'a mut [u8]> { - /// Create an `IoVec` from a mutable Rust slice. - pub fn from_mut_slice(buf: &'a mut [u8]) -> IoVec<&'a mut [u8]> { - IoVec(libc::iovec { - iov_base: buf.as_ptr() as *mut c_void, - iov_len: buf.len() as size_t, - }, PhantomData) - } -} - -// The only reason IoVec isn't automatically Send+Sync is because libc::iovec -// contains raw pointers. -unsafe impl Send for IoVec where T: Send {} -unsafe impl Sync for IoVec where T: Sync {} -- cgit v1.2.3