Skip to content

Commit d3a662d

Browse files
authored
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 b855bd0 commit d3a662d

File tree

2 files changed

+115
-14
lines changed

2 files changed

+115
-14
lines changed

src/backend/libc/offset.rs

Lines changed: 108 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,20 @@ pub(super) use c::posix_fadvise64 as libc_posix_fadvise;
141141
pub(super) use c::{pread as libc_pread, pwrite as libc_pwrite};
142142
#[cfg(any(target_os = "android", target_os = "linux", target_os = "emscripten"))]
143143
pub(super) use c::{pread64 as libc_pread, pwrite64 as libc_pwrite};
144+
#[cfg(not(any(
145+
apple,
146+
windows,
147+
target_os = "android",
148+
target_os = "emscripten",
149+
target_os = "haiku",
150+
target_os = "linux",
151+
target_os = "redox",
152+
target_os = "solaris",
153+
)))]
154+
pub(super) use c::{preadv as libc_preadv, pwritev as libc_pwritev};
144155
#[cfg(any(target_os = "linux", target_os = "emscripten"))]
145156
pub(super) use c::{preadv64 as libc_preadv, pwritev64 as libc_pwritev};
157+
146158
#[cfg(target_os = "android")]
147159
mod readwrite_pv64 {
148160
use super::c;
@@ -230,19 +242,9 @@ mod readwrite_pv64 {
230242
}
231243
}
232244
}
233-
#[cfg(not(any(
234-
apple,
235-
windows,
236-
target_os = "android",
237-
target_os = "emscripten",
238-
target_os = "haiku",
239-
target_os = "linux",
240-
target_os = "redox",
241-
target_os = "solaris",
242-
)))]
243-
pub(super) use c::{preadv as libc_preadv, pwritev as libc_pwritev};
244245
#[cfg(target_os = "android")]
245246
pub(super) use readwrite_pv64::{preadv64 as libc_preadv, pwritev64 as libc_pwritev};
247+
246248
// macOS added preadv and pwritev in version 11.0
247249
#[cfg(apple)]
248250
mod readwrite_pv {
@@ -264,11 +266,104 @@ mod readwrite_pv {
264266
) -> c::ssize_t
265267
}
266268
}
267-
#[cfg(all(target_os = "linux", target_env = "gnu"))]
268-
pub(super) use c::{preadv64v2 as libc_preadv2, pwritev64v2 as libc_pwritev2};
269269
#[cfg(apple)]
270270
pub(super) use readwrite_pv::{preadv as libc_preadv, pwritev as libc_pwritev};
271271

272+
// GLIBC added `preadv64v2` and `pwritev64v2` in version 2.26.
273+
#[cfg(all(target_os = "linux", target_env = "gnu"))]
274+
mod readwrite_pv64v2 {
275+
use super::c;
276+
277+
// 64-bit offsets on 32-bit platforms are passed in endianness-specific
278+
// lo/hi pairs. See src/backend/linux_raw/conv.rs for details.
279+
#[cfg(all(target_endian = "little", target_pointer_width = "32"))]
280+
fn lo(x: u64) -> usize {
281+
(x >> 32) as usize
282+
}
283+
#[cfg(all(target_endian = "little", target_pointer_width = "32"))]
284+
fn hi(x: u64) -> usize {
285+
(x & 0xffff_ffff) as usize
286+
}
287+
#[cfg(all(target_endian = "big", target_pointer_width = "32"))]
288+
fn lo(x: u64) -> usize {
289+
(x & 0xffff_ffff) as usize
290+
}
291+
#[cfg(all(target_endian = "big", target_pointer_width = "32"))]
292+
fn hi(x: u64) -> usize {
293+
(x >> 32) as usize
294+
}
295+
296+
pub(in super::super) unsafe fn preadv64v2(
297+
fd: c::c_int,
298+
iov: *const c::iovec,
299+
iovcnt: c::c_int,
300+
offset: c::off64_t,
301+
flags: c::c_int,
302+
) -> c::ssize_t {
303+
// Older GLIBC lacks `preadv64v2`, so use the `weak!` mechanism to
304+
// test for it, and call back to `c::syscall`. We don't use
305+
// `weak_or_syscall` here because we need to pass the 64-bit offset
306+
// specially.
307+
weak! {
308+
fn preadv64v2(c::c_int, *const c::iovec, c::c_int, c::off64_t, c::c_int) -> c::ssize_t
309+
}
310+
if let Some(fun) = preadv64v2.get() {
311+
fun(fd, iov, iovcnt, offset, flags)
312+
} else {
313+
#[cfg(target_pointer_width = "32")]
314+
{
315+
c::syscall(
316+
c::SYS_preadv,
317+
fd,
318+
iov,
319+
iovcnt,
320+
hi(offset as u64),
321+
lo(offset as u64),
322+
flags,
323+
) as c::ssize_t
324+
}
325+
#[cfg(target_pointer_width = "64")]
326+
{
327+
c::syscall(c::SYS_preadv2, fd, iov, iovcnt, offset, flags) as c::ssize_t
328+
}
329+
}
330+
}
331+
pub(in super::super) unsafe fn pwritev64v2(
332+
fd: c::c_int,
333+
iov: *const c::iovec,
334+
iovcnt: c::c_int,
335+
offset: c::off64_t,
336+
flags: c::c_int,
337+
) -> c::ssize_t {
338+
// See the comments in `preadv64v2`.
339+
weak! {
340+
fn pwritev64v2(c::c_int, *const c::iovec, c::c_int, c::off64_t, c::c_int) -> c::ssize_t
341+
}
342+
if let Some(fun) = pwritev64v2.get() {
343+
fun(fd, iov, iovcnt, offset, flags)
344+
} else {
345+
#[cfg(target_pointer_width = "32")]
346+
{
347+
c::syscall(
348+
c::SYS_pwritev,
349+
fd,
350+
iov,
351+
iovcnt,
352+
hi(offset as u64),
353+
lo(offset as u64),
354+
flags,
355+
) as c::ssize_t
356+
}
357+
#[cfg(target_pointer_width = "64")]
358+
{
359+
c::syscall(c::SYS_pwritev2, fd, iov, iovcnt, offset, flags) as c::ssize_t
360+
}
361+
}
362+
}
363+
}
364+
#[cfg(all(target_os = "linux", target_env = "gnu"))]
365+
pub(super) use readwrite_pv64v2::{preadv64v2 as libc_preadv2, pwritev64v2 as libc_pwritev2};
366+
272367
#[cfg(not(any(
273368
apple,
274369
netbsdlike,

src/backend/libc/thread/syscalls.rs

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

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

0 commit comments

Comments
 (0)