Skip to content

Commit ab3be66

Browse files
committed
Trusty: Implement write_vectored and write_all for stdio
Currently, `write` for stdout and stderr on Trusty is implemented with the semantics of `write_all`. Instead, implement `write_all` and call the underlying syscall only once in `write`. Also, implement `write_vectored` by adding support for `IoSlice`. Refactor stdin to reuse the unsupported type like #136769.
1 parent 7290b04 commit ab3be66

File tree

3 files changed

+65
-26
lines changed

3 files changed

+65
-26
lines changed

library/std/src/sys/io/io_slice/iovec.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#[cfg(target_os = "hermit")]
22
use hermit_abi::iovec;
3-
#[cfg(target_family = "unix")]
3+
#[cfg(any(target_family = "unix", target_os = "trusty"))]
44
use libc::iovec;
55

66
use crate::ffi::c_void;

library/std/src/sys/io/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
mod io_slice {
44
cfg_if::cfg_if! {
5-
if #[cfg(any(target_family = "unix", target_os = "hermit", target_os = "solid_asp3"))] {
5+
if #[cfg(any(target_family = "unix", target_os = "hermit", target_os = "solid_asp3", target_os = "trusty"))] {
66
mod iovec;
77
pub use iovec::*;
88
} else if #[cfg(target_os = "windows")] {

library/std/src/sys/stdio/trusty.rs

+63-24
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,14 @@
1-
use crate::io;
1+
#[expect(dead_code)]
2+
#[path = "unsupported.rs"]
3+
mod unsupported_stdio;
24

3-
pub struct Stdin;
5+
use crate::cmp;
6+
use crate::io::{self, IoSlice};
7+
8+
pub type Stdin = unsupported_stdio::Stdin;
49
pub struct Stdout;
510
pub struct Stderr;
611

7-
impl Stdin {
8-
pub const fn new() -> Stdin {
9-
Stdin
10-
}
11-
}
12-
13-
impl io::Read for Stdin {
14-
fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
15-
Ok(0)
16-
}
17-
}
18-
1912
impl Stdout {
2013
pub const fn new() -> Stdout {
2114
Stdout
@@ -24,7 +17,20 @@ impl Stdout {
2417

2518
impl io::Write for Stdout {
2619
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
27-
_write(libc::STDOUT_FILENO, buf)
20+
write(libc::STDOUT_FILENO, buf)
21+
}
22+
23+
fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
24+
write_vectored(libc::STDOUT_FILENO, bufs)
25+
}
26+
27+
#[inline]
28+
fn is_write_vectored(&self) -> bool {
29+
true
30+
}
31+
32+
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
33+
write_all(libc::STDOUT_FILENO, buf)
2834
}
2935

3036
fn flush(&mut self) -> io::Result<()> {
@@ -40,15 +46,28 @@ impl Stderr {
4046

4147
impl io::Write for Stderr {
4248
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
43-
_write(libc::STDERR_FILENO, buf)
49+
write(libc::STDERR_FILENO, buf)
50+
}
51+
52+
fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
53+
write_vectored(libc::STDERR_FILENO, bufs)
54+
}
55+
56+
#[inline]
57+
fn is_write_vectored(&self) -> bool {
58+
true
59+
}
60+
61+
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
62+
write_all(libc::STDERR_FILENO, buf)
4463
}
4564

4665
fn flush(&mut self) -> io::Result<()> {
4766
Ok(())
4867
}
4968
}
5069

51-
pub const STDIN_BUF_SIZE: usize = 0;
70+
pub const STDIN_BUF_SIZE: usize = unsupported_stdio::STDIN_BUF_SIZE;
5271

5372
pub fn is_ebadf(_err: &io::Error) -> bool {
5473
true
@@ -58,20 +77,40 @@ pub fn panic_output() -> Option<impl io::Write> {
5877
Some(Stderr)
5978
}
6079

61-
fn _write(fd: i32, message: &[u8]) -> io::Result<usize> {
62-
let mut iov = libc::iovec { iov_base: message.as_ptr() as *mut _, iov_len: message.len() };
80+
fn write(fd: i32, buf: &[u8]) -> io::Result<usize> {
81+
let iov = libc::iovec { iov_base: buf.as_ptr() as *mut _, iov_len: buf.len() };
82+
// SAFETY: syscall, safe arguments.
83+
let ret = unsafe { libc::writev(fd, &iov, 1) };
84+
// This check includes ret < 0, since the length is at most isize::MAX.
85+
if ret as usize > iov.iov_len {
86+
return Err(io::Error::last_os_error());
87+
}
88+
Ok(ret as usize)
89+
}
90+
91+
fn write_vectored(fd: i32, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
92+
let iov = bufs.as_ptr() as *const libc::iovec;
93+
let len = cmp::min(bufs.len(), libc::c_int::MAX as usize) as libc::c_int;
94+
// SAFETY: syscall, safe arguments.
95+
let ret = unsafe { libc::writev(fd, iov, len) };
96+
if ret < 0 {
97+
return Err(io::Error::last_os_error());
98+
}
99+
Ok(ret as usize)
100+
}
101+
102+
fn write_all(fd: i32, buf: &[u8]) -> io::Result<()> {
103+
let mut iov = libc::iovec { iov_base: buf.as_ptr() as *mut _, iov_len: buf.len() };
63104
loop {
64105
// SAFETY: syscall, safe arguments.
65106
let ret = unsafe { libc::writev(fd, &iov, 1) };
66-
if ret < 0 {
107+
// This check includes ret < 0, since the length is at most isize::MAX.
108+
if ret as usize > iov.iov_len {
67109
return Err(io::Error::last_os_error());
68110
}
69111
let ret = ret as usize;
70-
if ret > iov.iov_len {
71-
return Err(io::Error::last_os_error());
72-
}
73112
if ret == iov.iov_len {
74-
return Ok(message.len());
113+
return Ok(());
75114
}
76115
// SAFETY: ret has been checked to be less than the length of
77116
// the buffer

0 commit comments

Comments
 (0)