about summary refs log tree commit diff
path: root/library/std/src
diff options
context:
space:
mode:
authorAdam Reichold <adam.reichold@t-online.de>2020-08-01 14:18:11 +0200
committerAdam Reichold <adam.reichold@t-online.de>2020-08-05 16:57:02 +0200
commit94687525815cb2138779e17a766e24c826819d7c (patch)
treeb946ffc716e0a90a3122da17b5ece437b070fe20 /library/std/src
parent8b84156c6ee2b4e707dc32f5a516e3143ab924d3 (diff)
downloadrust-94687525815cb2138779e17a766e24c826819d7c.tar.gz
rust-94687525815cb2138779e17a766e24c826819d7c.zip
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.
Diffstat (limited to 'library/std/src')
-rw-r--r--library/std/src/sys/unix/fd.rs38
1 files 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 @@ const READ_LIMIT: usize = c_int::MAX as usize - 1;
 #[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 @@ impl FileDesc {
             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 @@ impl FileDesc {
             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 @@ impl Drop for FileDesc {
         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::<Vec<_>>();
+
+        assert!(stdout.write_vectored(&bufs).is_ok());
+    }
+}