Skip to content

Commit 57e14c8

Browse files
committed
Use weak! for setns, preadv64v2, and pwritev64v2 on GLIBC. (#556)
`setns`, `preadv64v2`, and `pwritev64v2` were introduced more recently than the earliest glibc we support, so use the `weak!` mechanism for them, with fallbacks using `syscall`.
1 parent 8a7cbfa commit 57e14c8

File tree

2 files changed

+116
-15
lines changed

2 files changed

+116
-15
lines changed

src/backend/libc/offset.rs

Lines changed: 109 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -213,8 +213,21 @@ pub(super) use c::posix_fadvise64 as libc_posix_fadvise;
213213
pub(super) use c::{pread as libc_pread, pwrite as libc_pwrite};
214214
#[cfg(any(target_os = "android", target_os = "linux", target_os = "emscripten"))]
215215
pub(super) use c::{pread64 as libc_pread, pwrite64 as libc_pwrite};
216+
#[cfg(not(any(
217+
windows,
218+
target_os = "android",
219+
target_os = "emscripten",
220+
target_os = "haiku",
221+
target_os = "ios",
222+
target_os = "linux",
223+
target_os = "macos",
224+
target_os = "redox",
225+
target_os = "solaris",
226+
)))]
227+
pub(super) use c::{preadv as libc_preadv, pwritev as libc_pwritev};
216228
#[cfg(any(target_os = "linux", target_os = "emscripten"))]
217229
pub(super) use c::{preadv64 as libc_preadv, pwritev64 as libc_pwritev};
230+
218231
#[cfg(target_os = "android")]
219232
mod readwrite_pv64 {
220233
use super::c;
@@ -302,20 +315,9 @@ mod readwrite_pv64 {
302315
}
303316
}
304317
}
305-
#[cfg(not(any(
306-
windows,
307-
target_os = "android",
308-
target_os = "emscripten",
309-
target_os = "haiku",
310-
target_os = "ios",
311-
target_os = "linux",
312-
target_os = "macos",
313-
target_os = "redox",
314-
target_os = "solaris",
315-
)))]
316-
pub(super) use c::{preadv as libc_preadv, pwritev as libc_pwritev};
317318
#[cfg(target_os = "android")]
318319
pub(super) use readwrite_pv64::{preadv64 as libc_preadv, pwritev64 as libc_pwritev};
320+
319321
// macOS added preadv and pwritev in version 11.0
320322
#[cfg(any(target_os = "ios", target_os = "macos"))]
321323
mod readwrite_pv {
@@ -337,11 +339,104 @@ mod readwrite_pv {
337339
) -> c::ssize_t
338340
}
339341
}
340-
#[cfg(all(target_os = "linux", target_env = "gnu"))]
341-
pub(super) use c::{preadv64v2 as libc_preadv2, pwritev64v2 as libc_pwritev2};
342342
#[cfg(any(target_os = "ios", target_os = "macos"))]
343343
pub(super) use readwrite_pv::{preadv as libc_preadv, pwritev as libc_pwritev};
344344

345+
// GLIBC added `preadv64v2` and `pwritev64v2` in version 2.26.
346+
#[cfg(all(target_os = "linux", target_env = "gnu"))]
347+
mod readwrite_pv64v2 {
348+
use super::c;
349+
350+
// 64-bit offsets on 32-bit platforms are passed in endianness-specific
351+
// lo/hi pairs. See src/backend/linux_raw/conv.rs for details.
352+
#[cfg(all(target_endian = "little", target_pointer_width = "32"))]
353+
fn lo(x: u64) -> usize {
354+
(x >> 32) as usize
355+
}
356+
#[cfg(all(target_endian = "little", target_pointer_width = "32"))]
357+
fn hi(x: u64) -> usize {
358+
(x & 0xffff_ffff) as usize
359+
}
360+
#[cfg(all(target_endian = "big", target_pointer_width = "32"))]
361+
fn lo(x: u64) -> usize {
362+
(x & 0xffff_ffff) as usize
363+
}
364+
#[cfg(all(target_endian = "big", target_pointer_width = "32"))]
365+
fn hi(x: u64) -> usize {
366+
(x >> 32) as usize
367+
}
368+
369+
pub(in super::super) unsafe fn preadv64v2(
370+
fd: c::c_int,
371+
iov: *const c::iovec,
372+
iovcnt: c::c_int,
373+
offset: c::off64_t,
374+
flags: c::c_int,
375+
) -> c::ssize_t {
376+
// Older GLIBC lacks `preadv64v2`, so use the `weak!` mechanism to
377+
// test for it, and call back to `c::syscall`. We don't use
378+
// `weak_or_syscall` here because we need to pass the 64-bit offset
379+
// specially.
380+
weak! {
381+
fn preadv64v2(c::c_int, *const c::iovec, c::c_int, c::off64_t, c::c_int) -> c::ssize_t
382+
}
383+
if let Some(fun) = preadv64v2.get() {
384+
fun(fd, iov, iovcnt, offset, flags)
385+
} else {
386+
#[cfg(target_pointer_width = "32")]
387+
{
388+
c::syscall(
389+
c::SYS_preadv,
390+
fd,
391+
iov,
392+
iovcnt,
393+
hi(offset as u64),
394+
lo(offset as u64),
395+
flags,
396+
) as c::ssize_t
397+
}
398+
#[cfg(target_pointer_width = "64")]
399+
{
400+
c::syscall(c::SYS_preadv2, fd, iov, iovcnt, offset, flags) as c::ssize_t
401+
}
402+
}
403+
}
404+
pub(in super::super) unsafe fn pwritev64v2(
405+
fd: c::c_int,
406+
iov: *const c::iovec,
407+
iovcnt: c::c_int,
408+
offset: c::off64_t,
409+
flags: c::c_int,
410+
) -> c::ssize_t {
411+
// See the comments in `preadv64v2`.
412+
weak! {
413+
fn pwritev64v2(c::c_int, *const c::iovec, c::c_int, c::off64_t, c::c_int) -> c::ssize_t
414+
}
415+
if let Some(fun) = pwritev64v2.get() {
416+
fun(fd, iov, iovcnt, offset, flags)
417+
} else {
418+
#[cfg(target_pointer_width = "32")]
419+
{
420+
c::syscall(
421+
c::SYS_pwritev,
422+
fd,
423+
iov,
424+
iovcnt,
425+
hi(offset as u64),
426+
lo(offset as u64),
427+
flags,
428+
) as c::ssize_t
429+
}
430+
#[cfg(target_pointer_width = "64")]
431+
{
432+
c::syscall(c::SYS_pwritev2, fd, iov, iovcnt, offset, flags) as c::ssize_t
433+
}
434+
}
435+
}
436+
}
437+
#[cfg(all(target_os = "linux", target_env = "gnu"))]
438+
pub(super) use readwrite_pv64v2::{preadv64v2 as libc_preadv2, pwritev64v2 as libc_pwritev2};
439+
345440
#[cfg(not(any(
346441
windows,
347442
target_os = "aix",

src/backend/libc/thread/syscalls.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,13 @@ pub(crate) fn gettid() -> Pid {
291291
#[cfg(any(target_os = "android", target_os = "linux"))]
292292
#[inline]
293293
pub(crate) fn setns(fd: BorrowedFd, nstype: c::c_int) -> io::Result<c::c_int> {
294-
unsafe { ret_c_int(c::setns(borrowed_fd(fd), nstype)) }
294+
// `setns` wasn't supported in glibc until 2.14, and musl until 0.9.5,
295+
// so use `syscall`.
296+
weak_or_syscall! {
297+
fn setns(fd: c::c_int, nstype: c::c_int) via SYS_setns -> c::c_int
298+
}
299+
300+
unsafe { ret_c_int(setns(borrowed_fd(fd), nstype)) }
295301
}
296302

297303
#[cfg(any(target_os = "android", target_os = "linux"))]

0 commit comments

Comments
 (0)