From 94687525815cb2138779e17a766e24c826819d7c Mon Sep 17 00:00:00 2001 From: Adam Reichold Date: Sat, 1 Aug 2020 14:18:11 +0200 Subject: [PATCH] Query maximum vector count on Linux and macOS Both Linux and MacOS enforce limits on the vector count when performing vectored I/O via the readv and writev system calls and return EINVAL when these limits are exceeded. This changes the standard library to handle those limits as short reads and writes to avoid forcing its users to query these limits using platform specific mechanisms. --- library/std/src/sys/unix/fd.rs | 38 ++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs index 84c4d662161..675528bd526 100644 --- a/library/std/src/sys/unix/fd.rs +++ b/library/std/src/sys/unix/fd.rs @@ -26,6 +26,27 @@ pub struct FileDesc { #[cfg(not(target_os = "macos"))] const READ_LIMIT: usize = libc::ssize_t::MAX as usize; +#[cfg(any(target_os = "linux", target_os = "macos"))] +fn max_iov() -> c_int { + let ret = unsafe { + libc::sysconf( + #[cfg(target_os = "linux")] + libc::_SC_IOV_MAX, + #[cfg(target_os = "macos")] + libc::_SC_UIO_MAXIOV, + ) + }; + + // 1024 is the default value on modern Linux systems + // and hopefully more useful than `c_int::MAX`. + if ret > 0 { ret as c_int } else { 1024 } +} + +#[cfg(not(any(target_os = "linux", target_os = "macos")))] +fn max_iov() -> c_int { + c_int::MAX +} + impl FileDesc { pub fn new(fd: c_int) -> FileDesc { FileDesc { fd } @@ -54,7 +75,7 @@ pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { libc::readv( self.fd, bufs.as_ptr() as *const libc::iovec, - cmp::min(bufs.len(), c_int::MAX as usize) as c_int, + cmp::min(bufs.len(), max_iov() as usize) as c_int, ) })?; Ok(ret as usize) @@ -111,7 +132,7 @@ pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { libc::writev( self.fd, bufs.as_ptr() as *const libc::iovec, - cmp::min(bufs.len(), c_int::MAX as usize) as c_int, + cmp::min(bufs.len(), max_iov() as usize) as c_int, ) })?; Ok(ret as usize) @@ -256,3 +277,16 @@ fn drop(&mut self) { let _ = unsafe { libc::close(self.fd) }; } } + +#[cfg(test)] +mod tests { + use super::{FileDesc, IoSlice}; + + #[test] + fn limit_vector_count() { + let stdout = FileDesc { fd: 1 }; + let bufs = (0..1500).map(|_| IoSlice::new(&[])).collect::>(); + + assert!(stdout.write_vectored(&bufs).is_ok()); + } +} -- 2.44.0