Fix watchOS and visionOS for pread64 and pwrite64 calls

* Refactor apple OSs  to use pwritev and preadv rather pwritev64 and preadv64
* Updated the comments for preadv and pwritev
This commit is contained in:
Sebastian Imlay 2024-04-17 14:33:03 -04:00
parent 38104f3a88
commit fa53b9f39c
2 changed files with 66 additions and 38 deletions

View File

@ -45,13 +45,9 @@ const READ_LIMIT: usize = libc::ssize_t::MAX as usize;
#[cfg(any( #[cfg(any(
target_os = "dragonfly", target_os = "dragonfly",
target_os = "freebsd", target_os = "freebsd",
target_os = "ios",
target_os = "tvos",
target_os = "macos",
target_os = "netbsd", target_os = "netbsd",
target_os = "openbsd", target_os = "openbsd",
target_os = "watchos", target_vendor = "apple",
target_os = "visionos",
))] ))]
const fn max_iov() -> usize { const fn max_iov() -> usize {
libc::IOV_MAX as usize libc::IOV_MAX as usize
@ -72,17 +68,13 @@ const fn max_iov() -> usize {
target_os = "dragonfly", target_os = "dragonfly",
target_os = "emscripten", target_os = "emscripten",
target_os = "freebsd", target_os = "freebsd",
target_os = "ios",
target_os = "tvos",
target_os = "linux", target_os = "linux",
target_os = "macos",
target_os = "netbsd", target_os = "netbsd",
target_os = "nto", target_os = "nto",
target_os = "openbsd", target_os = "openbsd",
target_os = "horizon", target_os = "horizon",
target_os = "vita", target_os = "vita",
target_os = "watchos", target_vendor = "apple",
target_os = "visionos",
)))] )))]
const fn max_iov() -> usize { const fn max_iov() -> usize {
16 // The minimum value required by POSIX. 16 // The minimum value required by POSIX.
@ -201,13 +193,10 @@ impl FileDesc {
target_os = "fuchsia", target_os = "fuchsia",
target_os = "hurd", target_os = "hurd",
target_os = "illumos", target_os = "illumos",
target_os = "ios",
target_os = "tvos",
target_os = "linux", target_os = "linux",
target_os = "macos",
target_os = "netbsd", target_os = "netbsd",
target_os = "openbsd", target_os = "openbsd",
target_os = "watchos", target_vendor = "apple",
)))] )))]
pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> { pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
io::default_read_vectored(|b| self.read_at(b, offset), bufs) io::default_read_vectored(|b| self.read_at(b, offset), bufs)
@ -241,15 +230,7 @@ impl FileDesc {
Ok(ret as usize) Ok(ret as usize)
} }
// We support old MacOS and iOS versions that do not have `preadv`. There is #[cfg(all(target_os = "android", target_pointer_width = "32"))]
// no `syscall` possible in these platform.
#[cfg(any(
all(target_os = "android", target_pointer_width = "32"),
target_os = "ios", // ios 14.0
target_os = "tvos", // tvos 14.0
target_os = "macos", // macos 11.0
target_os = "watchos", // watchos 7.0
))]
pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> { pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
super::weak::weak!(fn preadv64(libc::c_int, *const libc::iovec, libc::c_int, off64_t) -> isize); super::weak::weak!(fn preadv64(libc::c_int, *const libc::iovec, libc::c_int, off64_t) -> isize);
@ -269,6 +250,35 @@ impl FileDesc {
} }
} }
// We support old MacOS, iOS, watchOS, tvOS and visionOS. `preadv` was added in the following
// Apple OS versions:
// ios 14.0
// tvos 14.0
// macos 11.0
// watchos 7.0
//
// These versions may be newer than the minimum supported versions of OS's we support so we must
// use "weak" linking.
#[cfg(target_vendor = "apple")]
pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
super::weak::weak!(fn preadv(libc::c_int, *const libc::iovec, libc::c_int, off64_t) -> isize);
match preadv.get() {
Some(preadv) => {
let ret = cvt(unsafe {
preadv(
self.as_raw_fd(),
bufs.as_mut_ptr() as *mut libc::iovec as *const libc::iovec,
cmp::min(bufs.len(), max_iov()) as libc::c_int,
offset as _,
)
})?;
Ok(ret as usize)
}
None => io::default_read_vectored(|b| self.read_at(b, offset), bufs),
}
}
pub fn write(&self, buf: &[u8]) -> io::Result<usize> { pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
let ret = cvt(unsafe { let ret = cvt(unsafe {
libc::write( libc::write(
@ -360,13 +370,10 @@ impl FileDesc {
target_os = "fuchsia", target_os = "fuchsia",
target_os = "hurd", target_os = "hurd",
target_os = "illumos", target_os = "illumos",
target_os = "ios",
target_os = "tvos",
target_os = "linux", target_os = "linux",
target_os = "macos",
target_os = "netbsd", target_os = "netbsd",
target_os = "openbsd", target_os = "openbsd",
target_os = "watchos", target_vendor = "apple",
)))] )))]
pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> { pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
io::default_write_vectored(|b| self.write_at(b, offset), bufs) io::default_write_vectored(|b| self.write_at(b, offset), bufs)
@ -400,15 +407,7 @@ impl FileDesc {
Ok(ret as usize) Ok(ret as usize)
} }
// We support old MacOS and iOS versions that do not have `pwritev`. There is #[cfg(all(target_os = "android", target_pointer_width = "32"))]
// no `syscall` possible in these platform.
#[cfg(any(
all(target_os = "android", target_pointer_width = "32"),
target_os = "ios", // ios 14.0
target_os = "tvos", // tvos 14.0
target_os = "macos", // macos 11.0
target_os = "watchos", // watchos 7.0
))]
pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> { pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
super::weak::weak!(fn pwritev64(libc::c_int, *const libc::iovec, libc::c_int, off64_t) -> isize); super::weak::weak!(fn pwritev64(libc::c_int, *const libc::iovec, libc::c_int, off64_t) -> isize);
@ -428,6 +427,35 @@ impl FileDesc {
} }
} }
// We support old MacOS, iOS, watchOS, tvOS and visionOS. `pwritev` was added in the following
// Apple OS versions:
// ios 14.0
// tvos 14.0
// macos 11.0
// watchos 7.0
//
// These versions may be newer than the minimum supported versions of OS's we support so we must
// use "weak" linking.
#[cfg(target_vendor = "apple")]
pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
super::weak::weak!(fn pwritev(libc::c_int, *const libc::iovec, libc::c_int, off64_t) -> isize);
match pwritev.get() {
Some(pwritev) => {
let ret = cvt(unsafe {
pwritev(
self.as_raw_fd(),
bufs.as_ptr() as *const libc::iovec,
cmp::min(bufs.len(), max_iov()) as libc::c_int,
offset as _,
)
})?;
Ok(ret as usize)
}
None => io::default_write_vectored(|b| self.write_at(b, offset), bufs),
}
}
#[cfg(not(any( #[cfg(not(any(
target_env = "newlib", target_env = "newlib",
target_os = "solaris", target_os = "solaris",

View File

@ -28,7 +28,7 @@ use crate::ptr;
use crate::sync::atomic::{self, AtomicPtr, Ordering}; use crate::sync::atomic::{self, AtomicPtr, Ordering};
// We can use true weak linkage on ELF targets. // We can use true weak linkage on ELF targets.
#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "tvos")))] #[cfg(all(unix, not(target_vendor = "apple")))]
pub(crate) macro weak { pub(crate) macro weak {
(fn $name:ident($($t:ty),*) -> $ret:ty) => ( (fn $name:ident($($t:ty),*) -> $ret:ty) => (
let ref $name: ExternWeak<unsafe extern "C" fn($($t),*) -> $ret> = { let ref $name: ExternWeak<unsafe extern "C" fn($($t),*) -> $ret> = {
@ -43,7 +43,7 @@ pub(crate) macro weak {
} }
// On non-ELF targets, use the dlsym approximation of weak linkage. // On non-ELF targets, use the dlsym approximation of weak linkage.
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos"))] #[cfg(target_vendor = "apple")]
pub(crate) use self::dlsym as weak; pub(crate) use self::dlsym as weak;
pub(crate) struct ExternWeak<F: Copy> { pub(crate) struct ExternWeak<F: Copy> {