Skip to content

Commit c392f50

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 rust-lang#136769.
1 parent b672659 commit c392f50

File tree

3 files changed

+67
-26
lines changed

3 files changed

+67
-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

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

3-
pub struct Stdin;
5+
use crate::io::{self, IoSlice};
6+
7+
pub type Stdin = unsupported_stdio::Stdin;
48
pub struct Stdout;
59
pub struct Stderr;
610

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-
1911
impl Stdout {
2012
pub const fn new() -> Stdout {
2113
Stdout
@@ -24,7 +16,20 @@ impl Stdout {
2416

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

3035
fn flush(&mut self) -> io::Result<()> {
@@ -40,15 +45,28 @@ impl Stderr {
4045

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

4664
fn flush(&mut self) -> io::Result<()> {
4765
Ok(())
4866
}
4967
}
5068

51-
pub const STDIN_BUF_SIZE: usize = 0;
69+
pub const STDIN_BUF_SIZE: usize = unsupported_stdio::STDIN_BUF_SIZE;
5270

5371
pub fn is_ebadf(_err: &io::Error) -> bool {
5472
true
@@ -58,20 +76,43 @@ pub fn panic_output() -> Option<impl io::Write> {
5876
Some(Stderr)
5977
}
6078

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() };
79+
// FIXME: This should be in libc with a proper value. Several platforms use
80+
// 1024, but it may not be appropriate for Trusty.
81+
const IOV_MAX: usize = 1024;
82+
83+
fn write(fd: i32, buf: &[u8]) -> io::Result<usize> {
84+
let iov = libc::iovec { iov_base: buf.as_ptr() as *mut _, iov_len: buf.len() };
85+
// SAFETY: syscall, safe arguments.
86+
let ret = unsafe { libc::writev(fd, &iov, 1) };
87+
// This check includes ret < 0, since the length is at most isize::MAX.
88+
if ret as usize > iov.iov_len {
89+
return Err(io::Error::last_os_error());
90+
}
91+
Ok(ret as usize)
92+
}
93+
94+
fn write_vectored(fd: i32, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
95+
let iov = bufs.as_ptr() as *const libc::iovec;
96+
// SAFETY: syscall, safe arguments.
97+
let ret = unsafe { libc::writev(fd, iov, bufs.len().min(IOV_MAX) as libc::c_int) };
98+
if ret < 0 {
99+
return Err(io::Error::last_os_error());
100+
}
101+
Ok(ret as usize)
102+
}
103+
104+
fn write_all(fd: i32, buf: &[u8]) -> io::Result<()> {
105+
let mut iov = libc::iovec { iov_base: buf.as_ptr() as *mut _, iov_len: buf.len() };
63106
loop {
64107
// SAFETY: syscall, safe arguments.
65108
let ret = unsafe { libc::writev(fd, &iov, 1) };
66-
if ret < 0 {
109+
// This check includes ret < 0, since the length is at most isize::MAX.
110+
if ret as usize > iov.iov_len {
67111
return Err(io::Error::last_os_error());
68112
}
69113
let ret = ret as usize;
70-
if ret > iov.iov_len {
71-
return Err(io::Error::last_os_error());
72-
}
73114
if ret == iov.iov_len {
74-
return Ok(message.len());
115+
return Ok(());
75116
}
76117
// SAFETY: ret has been checked to be less than the length of
77118
// the buffer

0 commit comments

Comments
 (0)