mirror of
https://github.com/uutils/coreutils.git
synced 2026-06-10 15:48:22 -07:00
cat: replace copy_exact() with write_all
This commit is contained in:
@@ -479,10 +479,12 @@ fn get_input_type(path: &OsString) -> CatResult<InputType> {
|
||||
fn write_fast<R: FdReadable>(handle: &mut InputHandle<R>) -> CatResult<()> {
|
||||
let stdout = io::stdout();
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
let mut stdout = stdout;
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
{
|
||||
// If we're on Linux or Android, try to use the splice() system call
|
||||
// for faster writing. If it works, we're done.
|
||||
if !splice::write_fast_using_splice(handle, &stdout)? {
|
||||
if !splice::write_fast_using_splice(handle, &mut stdout)? {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,13 +4,11 @@
|
||||
// file that was distributed with this source code.
|
||||
use super::{CatResult, FdReadable, InputHandle};
|
||||
|
||||
use rustix::io::{read, write};
|
||||
use std::io::{Read, Write};
|
||||
use std::os::{fd::AsFd, unix::io::AsRawFd};
|
||||
|
||||
use uucore::pipes::{MAX_ROOTLESS_PIPE_SIZE, might_fuse, pipe, splice, splice_exact};
|
||||
|
||||
const BUF_SIZE: usize = 1024 * 16;
|
||||
|
||||
/// This function is called from `write_fast()` on Linux and Android. The
|
||||
/// function `splice()` is used to move data between two file descriptors
|
||||
/// without copying between kernel and user spaces. This results in a large
|
||||
@@ -19,14 +17,14 @@ const BUF_SIZE: usize = 1024 * 16;
|
||||
/// The `bool` in the result value indicates if we need to fall back to normal
|
||||
/// copying or not. False means we don't have to.
|
||||
#[inline]
|
||||
pub(super) fn write_fast_using_splice<R: FdReadable, S: AsRawFd + AsFd>(
|
||||
pub(super) fn write_fast_using_splice<R: FdReadable, S: AsRawFd + AsFd + Write>(
|
||||
handle: &InputHandle<R>,
|
||||
write_fd: &S,
|
||||
write_fd: &mut S,
|
||||
) -> CatResult<bool> {
|
||||
if splice(&handle.reader, &write_fd, MAX_ROOTLESS_PIPE_SIZE).is_ok() {
|
||||
// fcntl improves throughput
|
||||
// todo: avoid fcntl overhead for small input, but don't fcntl inside of the loop
|
||||
let _ = rustix::pipe::fcntl_setpipe_size(write_fd, MAX_ROOTLESS_PIPE_SIZE);
|
||||
let _ = rustix::pipe::fcntl_setpipe_size(&mut *write_fd, MAX_ROOTLESS_PIPE_SIZE);
|
||||
loop {
|
||||
match splice(&handle.reader, &write_fd, MAX_ROOTLESS_PIPE_SIZE) {
|
||||
Ok(1..) => {}
|
||||
@@ -46,7 +44,9 @@ pub(super) fn write_fast_using_splice<R: FdReadable, S: AsRawFd + AsFd>(
|
||||
// we can recover by copying the data that we have from the
|
||||
// intermediate pipe to stdout using normal read/write. Then
|
||||
// we tell the caller to fall back.
|
||||
copy_exact(&pipe_rd, write_fd, n)?;
|
||||
let mut drain = Vec::with_capacity(n); // bounded by pipe size
|
||||
pipe_rd.take(n as u64).read_to_end(&mut drain)?;
|
||||
write_fd.write_all(&drain)?;
|
||||
return Ok(true);
|
||||
}
|
||||
}
|
||||
@@ -57,24 +57,3 @@ pub(super) fn write_fast_using_splice<R: FdReadable, S: AsRawFd + AsFd>(
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
|
||||
/// Move exactly `num_bytes` bytes from `read_fd` to `write_fd`.
|
||||
///
|
||||
/// Panics if not enough bytes can be read.
|
||||
fn copy_exact(read_fd: &impl AsFd, write_fd: &impl AsFd, num_bytes: usize) -> std::io::Result<()> {
|
||||
let mut left = num_bytes;
|
||||
let mut buf = [0; BUF_SIZE];
|
||||
while left > 0 {
|
||||
let n = read(read_fd, &mut buf)?;
|
||||
assert_ne!(n, 0, "unexpected end of pipe");
|
||||
let mut written = 0;
|
||||
while written < n {
|
||||
match write(write_fd, &buf[written..n])? {
|
||||
0 => unreachable!("fd should be writable"),
|
||||
w => written += w,
|
||||
}
|
||||
}
|
||||
left -= n;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user