Skip to content

Commit cc92b3f

Browse files
committed
yes: Add zero copy fast-path
1 parent 01c8d6e commit cc92b3f

File tree

5 files changed

+28
-0
lines changed

5 files changed

+28
-0
lines changed

.vscode/cspell.dictionaries/workspace.wordlist.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ advapi32-sys
88
aho-corasick
99
backtrace
1010
blake2b_simd
11+
rustix
1112

1213
# * uutils project
1314
uutils

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,7 @@ rlimit = "0.11.0"
428428
rstest = "0.26.0"
429429
rustc-hash = "2.1.1"
430430
rust-ini = "0.21.0"
431+
rustix = { version = "1.1.4", features = ["fs", "param", "pipe"] }
431432
same-file = "1.0.6"
432433
self_cell = "1.0.4"
433434
selinux = "=0.6.0"

src/uu/yes/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ path = "src/yes.rs"
2222
clap = { workspace = true }
2323
itertools = { workspace = true }
2424
fluent = { workspace = true }
25+
rustix = { workspace = true }
2526

2627
[target.'cfg(unix)'.dependencies]
2728
uucore = { workspace = true, features = ["pipes", "signals"] }

src/uu/yes/src/yes.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ fn prepare_buffer(buf: &mut Vec<u8>) {
111111
}
112112
}
113113

114+
#[cfg(not(target_os = "linux"))]
114115
pub fn exec(bytes: &[u8]) -> io::Result<()> {
115116
let stdout = io::stdout();
116117
let mut stdout = stdout.lock();
@@ -120,6 +121,29 @@ pub fn exec(bytes: &[u8]) -> io::Result<()> {
120121
}
121122
}
122123

124+
#[cfg(target_os = "linux")]
125+
pub fn exec(bytes: &[u8]) -> io::Result<()> {
126+
use rustix::fd::BorrowedFd;
127+
use rustix::param::page_size;
128+
use rustix::pipe::{IoSliceRaw, SpliceFlags, vmsplice};
129+
use std::os::unix::io::AsRawFd;
130+
131+
let stdout = io::stdout();
132+
//zero copy fast-path
133+
//todo: we should align instead of giving up fast-path
134+
let aligned = bytes.len().is_multiple_of(page_size());
135+
if aligned {
136+
let fd_raw = stdout.as_raw_fd();
137+
let fd = unsafe { BorrowedFd::borrow_raw(fd_raw) };
138+
let iovec = [IoSliceRaw::from_slice(bytes)];
139+
while unsafe { vmsplice(fd, &iovec, SpliceFlags::empty()) }.is_ok() {}
140+
}
141+
let mut stdout = stdout.lock();
142+
loop {
143+
stdout.write_all(bytes)?;
144+
}
145+
}
146+
123147
#[cfg(test)]
124148
mod tests {
125149
use super::*;

0 commit comments

Comments
 (0)