Skip to content

Commit 9468752

Browse files
committed
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.
1 parent 8b84156 commit 9468752

File tree

1 file changed

+36
-2
lines changed
  • library/std/src/sys/unix

1 file changed

+36
-2
lines changed

library/std/src/sys/unix/fd.rs

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,27 @@ const READ_LIMIT: usize = c_int::MAX as usize - 1;
2626
#[cfg(not(target_os = "macos"))]
2727
const READ_LIMIT: usize = libc::ssize_t::MAX as usize;
2828

29+
#[cfg(any(target_os = "linux", target_os = "macos"))]
30+
fn max_iov() -> c_int {
31+
let ret = unsafe {
32+
libc::sysconf(
33+
#[cfg(target_os = "linux")]
34+
libc::_SC_IOV_MAX,
35+
#[cfg(target_os = "macos")]
36+
libc::_SC_UIO_MAXIOV,
37+
)
38+
};
39+
40+
// 1024 is the default value on modern Linux systems
41+
// and hopefully more useful than `c_int::MAX`.
42+
if ret > 0 { ret as c_int } else { 1024 }
43+
}
44+
45+
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
46+
fn max_iov() -> c_int {
47+
c_int::MAX
48+
}
49+
2950
impl FileDesc {
3051
pub fn new(fd: c_int) -> FileDesc {
3152
FileDesc { fd }
@@ -54,7 +75,7 @@ impl FileDesc {
5475
libc::readv(
5576
self.fd,
5677
bufs.as_ptr() as *const libc::iovec,
57-
cmp::min(bufs.len(), c_int::MAX as usize) as c_int,
78+
cmp::min(bufs.len(), max_iov() as usize) as c_int,
5879
)
5980
})?;
6081
Ok(ret as usize)
@@ -111,7 +132,7 @@ impl FileDesc {
111132
libc::writev(
112133
self.fd,
113134
bufs.as_ptr() as *const libc::iovec,
114-
cmp::min(bufs.len(), c_int::MAX as usize) as c_int,
135+
cmp::min(bufs.len(), max_iov() as usize) as c_int,
115136
)
116137
})?;
117138
Ok(ret as usize)
@@ -256,3 +277,16 @@ impl Drop for FileDesc {
256277
let _ = unsafe { libc::close(self.fd) };
257278
}
258279
}
280+
281+
#[cfg(test)]
282+
mod tests {
283+
use super::{FileDesc, IoSlice};
284+
285+
#[test]
286+
fn limit_vector_count() {
287+
let stdout = FileDesc { fd: 1 };
288+
let bufs = (0..1500).map(|_| IoSlice::new(&[])).collect::<Vec<_>>();
289+
290+
assert!(stdout.write_vectored(&bufs).is_ok());
291+
}
292+
}

0 commit comments

Comments
 (0)