summaryrefslogtreecommitdiff
path: root/src/backend/libc/pipe
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/libc/pipe')
-rw-r--r--src/backend/libc/pipe/mod.rs2
-rw-r--r--src/backend/libc/pipe/syscalls.rs125
-rw-r--r--src/backend/libc/pipe/types.rs103
3 files changed, 230 insertions, 0 deletions
diff --git a/src/backend/libc/pipe/mod.rs b/src/backend/libc/pipe/mod.rs
new file mode 100644
index 0000000..1e0181a
--- /dev/null
+++ b/src/backend/libc/pipe/mod.rs
@@ -0,0 +1,2 @@
+pub(crate) mod syscalls;
+pub(crate) mod types;
diff --git a/src/backend/libc/pipe/syscalls.rs b/src/backend/libc/pipe/syscalls.rs
new file mode 100644
index 0000000..cff932d
--- /dev/null
+++ b/src/backend/libc/pipe/syscalls.rs
@@ -0,0 +1,125 @@
+use crate::backend::c;
+use crate::backend::conv::ret;
+use crate::fd::OwnedFd;
+use crate::io;
+#[cfg(not(any(
+ apple,
+ target_os = "aix",
+ target_os = "espidf",
+ target_os = "haiku",
+ target_os = "nto",
+ target_os = "wasi"
+)))]
+use crate::pipe::PipeFlags;
+use core::mem::MaybeUninit;
+#[cfg(linux_kernel)]
+use {
+ crate::backend::conv::{borrowed_fd, ret_c_int, ret_usize},
+ crate::backend::MAX_IOV,
+ crate::fd::BorrowedFd,
+ crate::pipe::{IoSliceRaw, SpliceFlags},
+ crate::utils::option_as_mut_ptr,
+ core::cmp::min,
+};
+
+#[cfg(not(target_os = "wasi"))]
+pub(crate) fn pipe() -> io::Result<(OwnedFd, OwnedFd)> {
+ unsafe {
+ let mut result = MaybeUninit::<[OwnedFd; 2]>::uninit();
+ ret(c::pipe(result.as_mut_ptr().cast::<i32>()))?;
+ let [p0, p1] = result.assume_init();
+ Ok((p0, p1))
+ }
+}
+
+#[cfg(not(any(
+ apple,
+ target_os = "aix",
+ target_os = "espidf",
+ target_os = "haiku",
+ target_os = "nto",
+ target_os = "wasi"
+)))]
+pub(crate) fn pipe_with(flags: PipeFlags) -> io::Result<(OwnedFd, OwnedFd)> {
+ unsafe {
+ let mut result = MaybeUninit::<[OwnedFd; 2]>::uninit();
+ ret(c::pipe2(
+ result.as_mut_ptr().cast::<i32>(),
+ bitflags_bits!(flags),
+ ))?;
+ let [p0, p1] = result.assume_init();
+ Ok((p0, p1))
+ }
+}
+
+#[cfg(linux_kernel)]
+#[inline]
+pub fn splice(
+ fd_in: BorrowedFd<'_>,
+ off_in: Option<&mut u64>,
+ fd_out: BorrowedFd<'_>,
+ off_out: Option<&mut u64>,
+ len: usize,
+ flags: SpliceFlags,
+) -> io::Result<usize> {
+ let off_in = option_as_mut_ptr(off_in).cast();
+ let off_out = option_as_mut_ptr(off_out).cast();
+
+ unsafe {
+ ret_usize(c::splice(
+ borrowed_fd(fd_in),
+ off_in,
+ borrowed_fd(fd_out),
+ off_out,
+ len,
+ flags.bits(),
+ ))
+ }
+}
+
+#[cfg(linux_kernel)]
+#[inline]
+pub unsafe fn vmsplice(
+ fd: BorrowedFd<'_>,
+ bufs: &[IoSliceRaw<'_>],
+ flags: SpliceFlags,
+) -> io::Result<usize> {
+ ret_usize(c::vmsplice(
+ borrowed_fd(fd),
+ bufs.as_ptr().cast::<c::iovec>(),
+ min(bufs.len(), MAX_IOV),
+ flags.bits(),
+ ))
+}
+
+#[cfg(linux_kernel)]
+#[inline]
+pub fn tee(
+ fd_in: BorrowedFd<'_>,
+ fd_out: BorrowedFd<'_>,
+ len: usize,
+ flags: SpliceFlags,
+) -> io::Result<usize> {
+ unsafe {
+ ret_usize(c::tee(
+ borrowed_fd(fd_in),
+ borrowed_fd(fd_out),
+ len,
+ flags.bits(),
+ ))
+ }
+}
+
+#[cfg(linux_kernel)]
+#[inline]
+pub(crate) fn fcntl_getpipe_sz(fd: BorrowedFd<'_>) -> io::Result<usize> {
+ unsafe { ret_c_int(c::fcntl(borrowed_fd(fd), c::F_GETPIPE_SZ)).map(|size| size as usize) }
+}
+
+#[cfg(linux_kernel)]
+#[inline]
+pub(crate) fn fcntl_setpipe_sz(fd: BorrowedFd<'_>, size: usize) -> io::Result<()> {
+ let size: c::c_int = size.try_into().map_err(|_| io::Errno::PERM)?;
+
+ unsafe { ret(c::fcntl(borrowed_fd(fd), c::F_SETPIPE_SZ, size)) }
+}
diff --git a/src/backend/libc/pipe/types.rs b/src/backend/libc/pipe/types.rs
new file mode 100644
index 0000000..78fc2fc
--- /dev/null
+++ b/src/backend/libc/pipe/types.rs
@@ -0,0 +1,103 @@
+#[cfg(linux_kernel)]
+use core::marker::PhantomData;
+#[cfg(not(any(apple, target_os = "wasi")))]
+use {crate::backend::c, bitflags::bitflags};
+
+#[cfg(not(any(apple, target_os = "wasi")))]
+bitflags! {
+ /// `O_*` constants for use with [`pipe_with`].
+ ///
+ /// [`pipe_with`]: crate::pipe::pipe_with
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct PipeFlags: u32 {
+ /// `O_CLOEXEC`
+ const CLOEXEC = bitcast!(c::O_CLOEXEC);
+ /// `O_DIRECT`
+ #[cfg(not(any(
+ solarish,
+ target_os = "espidf",
+ target_os = "haiku",
+ target_os = "nto",
+ target_os = "openbsd",
+ target_os = "redox",
+ target_os = "vita",
+ )))]
+ const DIRECT = bitcast!(c::O_DIRECT);
+ /// `O_NONBLOCK`
+ const NONBLOCK = bitcast!(c::O_NONBLOCK);
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+#[cfg(linux_kernel)]
+bitflags! {
+ /// `SPLICE_F_*` constants for use with [`splice`], [`vmsplice`], and
+ /// [`tee`].
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct SpliceFlags: c::c_uint {
+ /// `SPLICE_F_MOVE`
+ const MOVE = c::SPLICE_F_MOVE;
+ /// `SPLICE_F_NONBLOCK`
+ const NONBLOCK = c::SPLICE_F_NONBLOCK;
+ /// `SPLICE_F_MORE`
+ const MORE = c::SPLICE_F_MORE;
+ /// `SPLICE_F_GIFT`
+ const GIFT = c::SPLICE_F_GIFT;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+/// A buffer type for use with [`vmsplice`].
+///
+/// It is guaranteed to be ABI compatible with the iovec type on Unix platforms
+/// and `WSABUF` on Windows. Unlike `IoSlice` and `IoSliceMut` it is
+/// semantically like a raw pointer, and therefore can be shared or mutated as
+/// needed.
+///
+/// [`vmsplice`]: crate::pipe::vmsplice
+#[cfg(linux_kernel)]
+#[repr(transparent)]
+pub struct IoSliceRaw<'a> {
+ _buf: c::iovec,
+ _lifetime: PhantomData<&'a ()>,
+}
+
+#[cfg(linux_kernel)]
+impl<'a> IoSliceRaw<'a> {
+ /// Creates a new `IoSlice` wrapping a byte slice.
+ pub fn from_slice(buf: &'a [u8]) -> Self {
+ IoSliceRaw {
+ _buf: c::iovec {
+ iov_base: buf.as_ptr() as *mut u8 as *mut c::c_void,
+ iov_len: buf.len() as _,
+ },
+ _lifetime: PhantomData,
+ }
+ }
+
+ /// Creates a new `IoSlice` wrapping a mutable byte slice.
+ pub fn from_slice_mut(buf: &'a mut [u8]) -> Self {
+ IoSliceRaw {
+ _buf: c::iovec {
+ iov_base: buf.as_mut_ptr() as *mut c::c_void,
+ iov_len: buf.len() as _,
+ },
+ _lifetime: PhantomData,
+ }
+ }
+}
+
+#[cfg(not(any(apple, target_os = "wasi")))]
+#[test]
+fn test_types() {
+ assert_eq_size!(PipeFlags, c::c_int);
+
+ #[cfg(linux_kernel)]
+ assert_eq_size!(SpliceFlags, c::c_int);
+}