about summary refs log tree commit diff
diff options
context:
space:
mode:
authorThalia Archibald <thalia@archibald.dev>2025-03-23 19:45:27 -0700
committerThalia Archibald <thalia@archibald.dev>2025-03-27 16:49:30 -0700
commit41b04653f3d2fd9cd6451a586354257d661385e2 (patch)
tree7e31fa8376304695620b923eacc1c8902bc1d213
parent7290b04b0a46de2118968aa556bfc0970aac6661 (diff)
downloadrust-41b04653f3d2fd9cd6451a586354257d661385e2.tar.gz
rust-41b04653f3d2fd9cd6451a586354257d661385e2.zip
Trusty: Implement write_vectored for stdio
Currently, `write` for stdout and stderr on Trusty is implemented with
the semantics of `write_all`. Instead, call the underlying syscall only
once in `write` and use the default implementation of `write_all` like
other platforms. Also, implement `write_vectored` by adding support for
`IoSlice`.

Refactor stdin to reuse the unsupported type like #136769.
-rw-r--r--library/std/src/sys/io/io_slice/iovec.rs2
-rw-r--r--library/std/src/sys/io/mod.rs2
-rw-r--r--library/std/src/sys/stdio/trusty.rs83
3 files changed, 49 insertions, 38 deletions
diff --git a/library/std/src/sys/io/io_slice/iovec.rs b/library/std/src/sys/io/io_slice/iovec.rs
index 072191315f7..df56358969a 100644
--- a/library/std/src/sys/io/io_slice/iovec.rs
+++ b/library/std/src/sys/io/io_slice/iovec.rs
@@ -1,6 +1,6 @@
 #[cfg(target_os = "hermit")]
 use hermit_abi::iovec;
-#[cfg(target_family = "unix")]
+#[cfg(any(target_family = "unix", target_os = "trusty"))]
 use libc::iovec;
 
 use crate::ffi::c_void;
diff --git a/library/std/src/sys/io/mod.rs b/library/std/src/sys/io/mod.rs
index e00b479109f..4d0365d42fd 100644
--- a/library/std/src/sys/io/mod.rs
+++ b/library/std/src/sys/io/mod.rs
@@ -2,7 +2,7 @@
 
 mod io_slice {
     cfg_if::cfg_if! {
-        if #[cfg(any(target_family = "unix", target_os = "hermit", target_os = "solid_asp3"))] {
+        if #[cfg(any(target_family = "unix", target_os = "hermit", target_os = "solid_asp3", target_os = "trusty"))] {
             mod iovec;
             pub use iovec::*;
         } else if #[cfg(target_os = "windows")] {
diff --git a/library/std/src/sys/stdio/trusty.rs b/library/std/src/sys/stdio/trusty.rs
index d393e95394d..e05461aa44a 100644
--- a/library/std/src/sys/stdio/trusty.rs
+++ b/library/std/src/sys/stdio/trusty.rs
@@ -1,21 +1,14 @@
-use crate::io;
+#[expect(dead_code)]
+#[path = "unsupported.rs"]
+mod unsupported_stdio;
 
-pub struct Stdin;
+use crate::cmp;
+use crate::io::{self, IoSlice};
+
+pub type Stdin = unsupported_stdio::Stdin;
 pub struct Stdout;
 pub struct Stderr;
 
-impl Stdin {
-    pub const fn new() -> Stdin {
-        Stdin
-    }
-}
-
-impl io::Read for Stdin {
-    fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
-        Ok(0)
-    }
-}
-
 impl Stdout {
     pub const fn new() -> Stdout {
         Stdout
@@ -24,7 +17,16 @@ impl Stdout {
 
 impl io::Write for Stdout {
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        _write(libc::STDOUT_FILENO, buf)
+        write(libc::STDOUT_FILENO, buf)
+    }
+
+    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        write_vectored(libc::STDOUT_FILENO, bufs)
+    }
+
+    #[inline]
+    fn is_write_vectored(&self) -> bool {
+        true
     }
 
     fn flush(&mut self) -> io::Result<()> {
@@ -40,7 +42,16 @@ impl Stderr {
 
 impl io::Write for Stderr {
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        _write(libc::STDERR_FILENO, buf)
+        write(libc::STDERR_FILENO, buf)
+    }
+
+    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        write_vectored(libc::STDERR_FILENO, bufs)
+    }
+
+    #[inline]
+    fn is_write_vectored(&self) -> bool {
+        true
     }
 
     fn flush(&mut self) -> io::Result<()> {
@@ -48,7 +59,7 @@ impl io::Write for Stderr {
     }
 }
 
-pub const STDIN_BUF_SIZE: usize = 0;
+pub const STDIN_BUF_SIZE: usize = unsupported_stdio::STDIN_BUF_SIZE;
 
 pub fn is_ebadf(_err: &io::Error) -> bool {
     true
@@ -58,24 +69,24 @@ pub fn panic_output() -> Option<impl io::Write> {
     Some(Stderr)
 }
 
-fn _write(fd: i32, message: &[u8]) -> io::Result<usize> {
-    let mut iov = libc::iovec { iov_base: message.as_ptr() as *mut _, iov_len: message.len() };
-    loop {
-        // SAFETY: syscall, safe arguments.
-        let ret = unsafe { libc::writev(fd, &iov, 1) };
-        if ret < 0 {
-            return Err(io::Error::last_os_error());
-        }
-        let ret = ret as usize;
-        if ret > iov.iov_len {
-            return Err(io::Error::last_os_error());
-        }
-        if ret == iov.iov_len {
-            return Ok(message.len());
-        }
-        // SAFETY: ret has been checked to be less than the length of
-        // the buffer
-        iov.iov_base = unsafe { iov.iov_base.add(ret) };
-        iov.iov_len -= ret;
+fn write(fd: i32, buf: &[u8]) -> io::Result<usize> {
+    let iov = libc::iovec { iov_base: buf.as_ptr() as *mut _, iov_len: buf.len() };
+    // SAFETY: syscall, safe arguments.
+    let ret = unsafe { libc::writev(fd, &iov, 1) };
+    // This check includes ret < 0, since the length is at most isize::MAX.
+    if ret as usize > iov.iov_len {
+        return Err(io::Error::last_os_error());
+    }
+    Ok(ret as usize)
+}
+
+fn write_vectored(fd: i32, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+    let iov = bufs.as_ptr() as *const libc::iovec;
+    let len = cmp::min(bufs.len(), libc::c_int::MAX as usize) as libc::c_int;
+    // SAFETY: syscall, safe arguments.
+    let ret = unsafe { libc::writev(fd, iov, len) };
+    if ret < 0 {
+        return Err(io::Error::last_os_error());
     }
+    Ok(ret as usize)
 }