Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Use weak linkage on Android
  • Loading branch information
a1phyr committed Mar 2, 2023
commit 2fc23c2dfe664850231f1691ef56cde6e467aa6a
100 changes: 96 additions & 4 deletions library/std/src/sys/unix/fd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,6 @@ impl FileDesc {
}

#[cfg(any(
target_os = "android",
target_os = "emscripten",
target_os = "freebsd",
target_os = "fuchsia",
Expand All @@ -171,7 +170,6 @@ impl FileDesc {
}

#[cfg(not(any(
target_os = "android",
target_os = "emscripten",
target_os = "freebsd",
target_os = "fuchsia",
Expand All @@ -185,6 +183,54 @@ impl FileDesc {
io::default_read_vectored(|b| self.read_at(b, offset), bufs)
}

// We support some old Android versions that do not have `preadv` in libc,
// so we use weak linkage and fallback to a direct syscall if not available.
//
// On 32-bit targets, we don't want to deal with weird ABI issues around
// passing 64-bits parameters to syscalls, so we fallback to the default
// implementation.
#[cfg(all(target_os = "android", target_pointer_width = "64"))]
pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
super::weak::syscall! {
fn preadv(
fd: libc::c_int,
iovec: *const libc::iovec,
n_iovec: libc::c_int,
offset: off64_t
) -> isize
}

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)
}

#[cfg(all(target_os = "android", target_pointer_width = "32"))]
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);

match preadv64.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> {
let ret = cvt(unsafe {
libc::write(
Expand Down Expand Up @@ -236,7 +282,6 @@ impl FileDesc {
}

#[cfg(any(
target_os = "android",
target_os = "emscripten",
target_os = "freebsd",
target_os = "fuchsia",
Expand All @@ -259,7 +304,6 @@ impl FileDesc {
}

#[cfg(not(any(
target_os = "android",
target_os = "emscripten",
target_os = "freebsd",
target_os = "fuchsia",
Expand All @@ -273,6 +317,54 @@ impl FileDesc {
io::default_write_vectored(|b| self.write_at(b, offset), bufs)
}

// We support some old Android versions that do not have `pwritev` in libc,
// so we use weak linkage and fallback to a direct syscall if not available.
//
// On 32-bit targets, we don't want to deal with weird ABI issues around
// passing 64-bits parameters to syscalls, so we fallback to the default
// implementation.
#[cfg(all(target_os = "android", target_pointer_width = "64"))]
pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
super::weak::syscall! {
fn pwritev(
fd: libc::c_int,
iovec: *const libc::iovec,
n_iovec: libc::c_int,
offset: off64_t
) -> isize
}

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)
}

#[cfg(all(target_os = "android", target_pointer_width = "32"))]
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);

match pwritev64.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(
target_env = "newlib",
target_os = "solaris",
Expand Down