Rollup merge of #147077 - joboet:mov_kernel_copy_sys, r=ibraheemdev
std: move `kernel_copy` to `sys` Part of rust-lang/rust#117276. The current organisation of the `kernel_copy` mechanism used to specialise `io::copy` on Linux necessitated circular links between the `io::copy` module and the implementation in `sys::pal::unix::kernel_copy`, as well as presenting an exception to the tidy PAL rule that forbids OS-based `#[cfg]`s outside of `sys` and `os`. This PR fixes this by moving `kernel_copy` to `sys` (as per rust-lang/rust#117276) and returning a `CopyState` from that function specifying whether `io::copy` should use its fallback. The `kernel_copy` function on other platforms just unconditionally returns `CopyState::Fallback`.
This commit is contained in:
commit
c3af6292ec
9 changed files with 54 additions and 31 deletions
|
|
@ -4,6 +4,7 @@ use crate::cmp;
|
|||
use crate::collections::VecDeque;
|
||||
use crate::io::IoSlice;
|
||||
use crate::mem::MaybeUninit;
|
||||
use crate::sys::io::{CopyState, kernel_copy};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
|
@ -63,19 +64,17 @@ where
|
|||
R: Read,
|
||||
W: Write,
|
||||
{
|
||||
cfg_select! {
|
||||
any(target_os = "linux", target_os = "android") => {
|
||||
crate::sys::kernel_copy::copy_spec(reader, writer)
|
||||
}
|
||||
_ => {
|
||||
generic_copy(reader, writer)
|
||||
match kernel_copy(reader, writer)? {
|
||||
CopyState::Ended(copied) => Ok(copied),
|
||||
CopyState::Fallback(copied) => {
|
||||
generic_copy(reader, writer).map(|additional| copied + additional)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The userspace read-write-loop implementation of `io::copy` that is used when
|
||||
/// OS-specific specializations for copy offloading are not available or not applicable.
|
||||
pub(crate) fn generic_copy<R: ?Sized, W: ?Sized>(reader: &mut R, writer: &mut W) -> Result<u64>
|
||||
fn generic_copy<R: ?Sized, W: ?Sized>(reader: &mut R, writer: &mut W) -> Result<u64>
|
||||
where
|
||||
R: Read,
|
||||
W: Write,
|
||||
|
|
@ -269,7 +268,7 @@ impl BufferedWriterSpec for Vec<u8> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn stack_buffer_copy<R: Read + ?Sized, W: Write + ?Sized>(
|
||||
fn stack_buffer_copy<R: Read + ?Sized, W: Write + ?Sized>(
|
||||
reader: &mut R,
|
||||
writer: &mut W,
|
||||
) -> Result<u64> {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ cfg_select! {
|
|||
pub use unix::chroot;
|
||||
pub(crate) use unix::debug_assert_fd_is_open;
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
pub(crate) use unix::CachedFileMetadata;
|
||||
pub(super) use unix::CachedFileMetadata;
|
||||
use crate::sys::common::small_c_string::run_path_with_cstr as with_native_path;
|
||||
}
|
||||
target_os = "windows" => {
|
||||
|
|
|
|||
|
|
@ -2302,7 +2302,7 @@ mod cfm {
|
|||
}
|
||||
}
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
pub(crate) use cfm::CachedFileMetadata;
|
||||
pub(in crate::sys) use cfm::CachedFileMetadata;
|
||||
|
||||
#[cfg(not(target_vendor = "apple"))]
|
||||
pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
|
||||
|
|
|
|||
|
|
@ -48,9 +48,9 @@ use libc::sendfile as sendfile64;
|
|||
use libc::sendfile64;
|
||||
use libc::{EBADF, EINVAL, ENOSYS, EOPNOTSUPP, EOVERFLOW, EPERM, EXDEV};
|
||||
|
||||
use super::CopyState;
|
||||
use crate::cmp::min;
|
||||
use crate::fs::{File, Metadata};
|
||||
use crate::io::copy::generic_copy;
|
||||
use crate::io::{
|
||||
BufRead, BufReader, BufWriter, Error, PipeReader, PipeWriter, Read, Result, StderrLock,
|
||||
StdinLock, StdoutLock, Take, Write,
|
||||
|
|
@ -70,10 +70,10 @@ use crate::sys::weak::syscall;
|
|||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub(crate) fn copy_spec<R: Read + ?Sized, W: Write + ?Sized>(
|
||||
pub fn kernel_copy<R: Read + ?Sized, W: Write + ?Sized>(
|
||||
read: &mut R,
|
||||
write: &mut W,
|
||||
) -> Result<u64> {
|
||||
) -> Result<CopyState> {
|
||||
let copier = Copier { read, write };
|
||||
SpecCopy::copy(copier)
|
||||
}
|
||||
|
|
@ -176,17 +176,17 @@ struct Copier<'a, 'b, R: Read + ?Sized, W: Write + ?Sized> {
|
|||
}
|
||||
|
||||
trait SpecCopy {
|
||||
fn copy(self) -> Result<u64>;
|
||||
fn copy(self) -> Result<CopyState>;
|
||||
}
|
||||
|
||||
impl<R: Read + ?Sized, W: Write + ?Sized> SpecCopy for Copier<'_, '_, R, W> {
|
||||
default fn copy(self) -> Result<u64> {
|
||||
generic_copy(self.read, self.write)
|
||||
default fn copy(self) -> Result<CopyState> {
|
||||
Ok(CopyState::Fallback(0))
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: CopyRead, W: CopyWrite> SpecCopy for Copier<'_, '_, R, W> {
|
||||
fn copy(self) -> Result<u64> {
|
||||
fn copy(self) -> Result<CopyState> {
|
||||
let (reader, writer) = (self.read, self.write);
|
||||
let r_cfg = reader.properties();
|
||||
let w_cfg = writer.properties();
|
||||
|
|
@ -214,7 +214,9 @@ impl<R: CopyRead, W: CopyWrite> SpecCopy for Copier<'_, '_, R, W> {
|
|||
result.update_take(reader);
|
||||
|
||||
match result {
|
||||
CopyResult::Ended(bytes_copied) => return Ok(bytes_copied + written),
|
||||
CopyResult::Ended(bytes_copied) => {
|
||||
return Ok(CopyState::Ended(bytes_copied + written));
|
||||
}
|
||||
CopyResult::Error(e, _) => return Err(e),
|
||||
CopyResult::Fallback(bytes) => written += bytes,
|
||||
}
|
||||
|
|
@ -231,7 +233,9 @@ impl<R: CopyRead, W: CopyWrite> SpecCopy for Copier<'_, '_, R, W> {
|
|||
result.update_take(reader);
|
||||
|
||||
match result {
|
||||
CopyResult::Ended(bytes_copied) => return Ok(bytes_copied + written),
|
||||
CopyResult::Ended(bytes_copied) => {
|
||||
return Ok(CopyState::Ended(bytes_copied + written));
|
||||
}
|
||||
CopyResult::Error(e, _) => return Err(e),
|
||||
CopyResult::Fallback(bytes) => written += bytes,
|
||||
}
|
||||
|
|
@ -244,7 +248,9 @@ impl<R: CopyRead, W: CopyWrite> SpecCopy for Copier<'_, '_, R, W> {
|
|||
result.update_take(reader);
|
||||
|
||||
match result {
|
||||
CopyResult::Ended(bytes_copied) => return Ok(bytes_copied + written),
|
||||
CopyResult::Ended(bytes_copied) => {
|
||||
return Ok(CopyState::Ended(bytes_copied + written));
|
||||
}
|
||||
CopyResult::Error(e, _) => return Err(e),
|
||||
CopyResult::Fallback(0) => { /* use the fallback below */ }
|
||||
CopyResult::Fallback(_) => {
|
||||
|
|
@ -255,10 +261,7 @@ impl<R: CopyRead, W: CopyWrite> SpecCopy for Copier<'_, '_, R, W> {
|
|||
}
|
||||
|
||||
// fallback if none of the more specialized syscalls wants to work with these file descriptors
|
||||
match generic_copy(reader, writer) {
|
||||
Ok(bytes) => Ok(bytes + written),
|
||||
err => err,
|
||||
}
|
||||
Ok(CopyState::Fallback(written))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -558,7 +561,7 @@ fn fd_to_meta<T: AsRawFd>(fd: &T) -> FdMeta {
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) enum CopyResult {
|
||||
enum CopyResult {
|
||||
Ended(u64),
|
||||
Error(Error, u64),
|
||||
Fallback(u64),
|
||||
|
|
@ -587,7 +590,7 @@ const INVALID_FD: RawFd = -1;
|
|||
/// Callers must handle fallback to a generic copy loop.
|
||||
/// `Fallback` may indicate non-zero number of bytes already written
|
||||
/// if one of the files' cursor +`max_len` would exceed u64::MAX (`EOVERFLOW`).
|
||||
pub(super) fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) -> CopyResult {
|
||||
fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) -> CopyResult {
|
||||
use crate::cmp;
|
||||
|
||||
const NOT_PROBED: u8 = 0;
|
||||
23
library/std/src/sys/io/kernel_copy/mod.rs
Normal file
23
library/std/src/sys/io/kernel_copy/mod.rs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
pub enum CopyState {
|
||||
#[cfg_attr(not(any(target_os = "linux", target_os = "android")), expect(dead_code))]
|
||||
Ended(u64),
|
||||
Fallback(u64),
|
||||
}
|
||||
|
||||
cfg_select! {
|
||||
any(target_os = "linux", target_os = "android") => {
|
||||
mod linux;
|
||||
pub use linux::kernel_copy;
|
||||
}
|
||||
_ => {
|
||||
use crate::io::{Result, Read, Write};
|
||||
|
||||
pub fn kernel_copy<R: ?Sized, W: ?Sized>(_reader: &mut R, _writer: &mut W) -> Result<CopyState>
|
||||
where
|
||||
R: Read,
|
||||
W: Write,
|
||||
{
|
||||
Ok(CopyState::Fallback(0))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -50,8 +50,11 @@ mod is_terminal {
|
|||
}
|
||||
}
|
||||
|
||||
mod kernel_copy;
|
||||
|
||||
pub use io_slice::{IoSlice, IoSliceMut};
|
||||
pub use is_terminal::is_terminal;
|
||||
pub use kernel_copy::{CopyState, kernel_copy};
|
||||
|
||||
// Bare metal platforms usually have very small amounts of RAM
|
||||
// (in the order of hundreds of KB)
|
||||
|
|
|
|||
|
|
@ -5,8 +5,6 @@ use crate::io::ErrorKind;
|
|||
#[cfg(target_os = "fuchsia")]
|
||||
pub mod fuchsia;
|
||||
pub mod futex;
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
pub mod kernel_copy;
|
||||
#[cfg(target_os = "linux")]
|
||||
pub mod linux;
|
||||
pub mod os;
|
||||
|
|
|
|||
|
|
@ -59,12 +59,9 @@ const EXCEPTION_PATHS: &[&str] = &[
|
|||
"library/std/src/os", // Platform-specific public interfaces
|
||||
// Temporary `std` exceptions
|
||||
// FIXME: platform-specific code should be moved to `sys`
|
||||
"library/std/src/io/copy.rs",
|
||||
"library/std/src/io/stdio.rs",
|
||||
"library/std/src/lib.rs", // for miniz_oxide leaking docs, which itself workaround
|
||||
"library/std/src/path.rs",
|
||||
"library/std/src/sys_common", // Should only contain abstractions over platforms
|
||||
"library/std/src/net/test.rs", // Utility helpers for tests
|
||||
"library/std/src/io/error.rs", // Repr unpacked needed for UEFI
|
||||
];
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue