summaryrefslogtreecommitdiff
path: root/vendor/rustix/src/thread/futex.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/rustix/src/thread/futex.rs')
-rw-r--r--vendor/rustix/src/thread/futex.rs600
1 files changed, 0 insertions, 600 deletions
diff --git a/vendor/rustix/src/thread/futex.rs b/vendor/rustix/src/thread/futex.rs
deleted file mode 100644
index 7ac49e69..00000000
--- a/vendor/rustix/src/thread/futex.rs
+++ /dev/null
@@ -1,600 +0,0 @@
-//! Linux `futex`.
-//!
-//! Futex is a very low-level mechanism for implementing concurrency primitives
-//! such as mutexes, rwlocks, and condvars. For a higher-level API that
-//! provides those abstractions, see [rustix-futex-syntax].
-//!
-//! # Examples
-//!
-//! ```
-//! use rustix::thread::futex;
-//! use std::sync::atomic::AtomicU32;
-//!
-//! # fn test(futex: &AtomicU32) -> rustix::io::Result<()> {
-//! // Wake up one waiter.
-//! futex::wake(futex, futex::Flags::PRIVATE, 1)?;
-//! # Ok(())
-//! # }
-//! ```
-//!
-//! # References
-//! - [Linux `futex` system call]
-//! - [Linux `futex` feature]
-//!
-//! [Linux `futex` system call]: https://man7.org/linux/man-pages/man2/futex.2.html
-//! [Linux `futex` feature]: https://man7.org/linux/man-pages/man7/futex.7.html
-//! [rustix-futex-sync]: https://crates.io/crates/rustix-futex-sync
-#![allow(unsafe_code)]
-
-use core::ffi::c_void;
-use core::num::NonZeroU32;
-use core::ptr;
-use core::sync::atomic::AtomicU32;
-
-use crate::backend::thread::futex::Operation;
-use crate::backend::thread::syscalls::{futex_timeout, futex_val2};
-use crate::fd::{FromRawFd as _, OwnedFd, RawFd};
-use crate::{backend, io};
-
-pub use crate::clockid::ClockId;
-pub use crate::timespec::{Nsecs, Secs, Timespec};
-
-pub use backend::thread::futex::{Flags, WaitFlags, OWNER_DIED, WAITERS};
-
-/// `syscall(SYS_futex, uaddr, FUTEX_WAIT, val, timeout, NULL, 0)`
-///
-/// This is a very low-level feature for implementing synchronization
-/// primitives. See the references links.
-///
-/// # References
-/// - [Linux `futex` system call]
-/// - [Linux `futex` feature]
-///
-/// [Linux `futex` system call]: https://man7.org/linux/man-pages/man2/futex.2.html
-/// [Linux `futex` feature]: https://man7.org/linux/man-pages/man7/futex.7.html
-#[inline]
-pub fn wait(
- uaddr: &AtomicU32,
- flags: Flags,
- val: u32,
- timeout: Option<&Timespec>,
-) -> io::Result<()> {
- // SAFETY: The raw pointers come from references or null.
- unsafe {
- futex_timeout(uaddr, Operation::Wait, flags, val, timeout, ptr::null(), 0).map(|val| {
- debug_assert_eq!(
- val, 0,
- "The return value should always equal zero, if the call is successful"
- );
- })
- }
-}
-
-/// `syscall(SYS_futex, uaddr, FUTEX_WAKE, val, NULL, NULL, 0)`
-///
-/// This is a very low-level feature for implementing synchronization
-/// primitives. See the references links.
-///
-/// # References
-/// - [Linux `futex` system call]
-/// - [Linux `futex` feature]
-///
-/// [Linux `futex` system call]: https://man7.org/linux/man-pages/man2/futex.2.html
-/// [Linux `futex` feature]: https://man7.org/linux/man-pages/man7/futex.7.html
-#[inline]
-pub fn wake(uaddr: &AtomicU32, flags: Flags, val: u32) -> io::Result<usize> {
- // SAFETY: The raw pointers come from references or null.
- unsafe { futex_val2(uaddr, Operation::Wake, flags, val, 0, ptr::null(), 0) }
-}
-
-/// `syscall(SYS_futex, uaddr, FUTEX_FD, val, NULL, NULL, 0)`
-///
-/// This is a very low-level feature for implementing synchronization
-/// primitives. See the references links.
-///
-/// # References
-/// - [Linux `futex` system call]
-/// - [Linux `futex` feature]
-///
-/// [Linux `futex` system call]: https://man7.org/linux/man-pages/man2/futex.2.html
-/// [Linux `futex` feature]: https://man7.org/linux/man-pages/man7/futex.7.html
-#[inline]
-pub fn fd(uaddr: &AtomicU32, flags: Flags, val: u32) -> io::Result<OwnedFd> {
- // SAFETY: The raw pointers come from references or null.
- unsafe {
- futex_val2(uaddr, Operation::Fd, flags, val, 0, ptr::null(), 0).map(|val| {
- let fd = val as RawFd;
- debug_assert_eq!(fd as usize, val, "return value should be a valid fd");
- OwnedFd::from_raw_fd(fd)
- })
- }
-}
-
-/// `syscall(SYS_futex, uaddr, FUTEX_REQUEUE, val, val2, uaddr2, 0)`
-///
-/// This is a very low-level feature for implementing synchronization
-/// primitives. See the references links.
-///
-/// # References
-/// - [Linux `futex` system call]
-/// - [Linux `futex` feature]
-///
-/// [Linux `futex` system call]: https://man7.org/linux/man-pages/man2/futex.2.html
-/// [Linux `futex` feature]: https://man7.org/linux/man-pages/man7/futex.7.html
-#[inline]
-pub fn requeue(
- uaddr: &AtomicU32,
- flags: Flags,
- val: u32,
- val2: u32,
- uaddr2: &AtomicU32,
-) -> io::Result<usize> {
- // SAFETY: The raw pointers come from references or null.
- unsafe { futex_val2(uaddr, Operation::Requeue, flags, val, val2, uaddr2, 0) }
-}
-
-/// `syscall(SYS_futex, uaddr, FUTEX_CMP_REQUEUE, val, val2, uaddr2, val3)`
-///
-/// This is a very low-level feature for implementing synchronization
-/// primitives. See the references links.
-///
-/// # References
-/// - [Linux `futex` system call]
-/// - [Linux `futex` feature]
-///
-/// [Linux `futex` system call]: https://man7.org/linux/man-pages/man2/futex.2.html
-/// [Linux `futex` feature]: https://man7.org/linux/man-pages/man7/futex.7.html
-#[inline]
-pub fn cmp_requeue(
- uaddr: &AtomicU32,
- flags: Flags,
- val: u32,
- val2: u32,
- uaddr2: &AtomicU32,
- val3: u32,
-) -> io::Result<usize> {
- // SAFETY: The raw pointers come from references or null.
- unsafe { futex_val2(uaddr, Operation::CmpRequeue, flags, val, val2, uaddr2, val3) }
-}
-
-/// `FUTEX_OP_*` operations for use with [`wake_op`].
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-#[repr(u32)]
-#[allow(clippy::identity_op)]
-pub enum WakeOp {
- /// `FUTEX_OP_SET`: `uaddr2 = oparg;`
- Set = 0,
- /// `FUTEX_OP_ADD`: `uaddr2 += oparg;`
- Add = 1,
- /// `FUTEX_OP_OR`: `uaddr2 |= oparg;`
- Or = 2,
- /// `FUTEX_OP_ANDN`: `uaddr2 &= ~oparg;`
- AndN = 3,
- /// `FUTEX_OP_XOR`: `uaddr2 ^= oparg;`
- XOr = 4,
- /// `FUTEX_OP_SET | FUTEX_OP_ARG_SHIFT`: `uaddr2 = (oparg << 1);`
- SetShift = 0 | 8,
- /// `FUTEX_OP_ADD | FUTEX_OP_ARG_SHIFT`: `uaddr2 += (oparg << 1);`
- AddShift = 1 | 8,
- /// `FUTEX_OP_OR | FUTEX_OP_ARG_SHIFT`: `uaddr2 |= (oparg << 1);`
- OrShift = 2 | 8,
- /// `FUTEX_OP_ANDN | FUTEX_OP_ARG_SHIFT`: `uaddr2 &= !(oparg << 1);`
- AndNShift = 3 | 8,
- /// `FUTEX_OP_XOR | FUTEX_OP_ARG_SHIFT`: `uaddr2 ^= (oparg << 1);`
- XOrShift = 4 | 8,
-}
-
-/// `FUTEX_OP_CMP_*` operations for use with [`wake_op`].
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-#[repr(u32)]
-pub enum WakeOpCmp {
- /// `FUTEX_OP_CMP_EQ`: `if oldval == cmparg { wake(); }`
- Eq = 0,
- /// `FUTEX_OP_CMP_EQ`: `if oldval != cmparg { wake(); }`
- Ne = 1,
- /// `FUTEX_OP_CMP_EQ`: `if oldval < cmparg { wake(); }`
- Lt = 2,
- /// `FUTEX_OP_CMP_EQ`: `if oldval <= cmparg { wake(); }`
- Le = 3,
- /// `FUTEX_OP_CMP_EQ`: `if oldval > cmparg { wake(); }`
- Gt = 4,
- /// `FUTEX_OP_CMP_EQ`: `if oldval >= cmparg { wake(); }`
- Ge = 5,
-}
-
-/// `syscall(SYS_futex, uaddr, FUTEX_WAKE_OP, val, val2, uaddr2, val3)`
-///
-/// This is a very low-level feature for implementing synchronization
-/// primitives. See the references links.
-///
-/// # References
-/// - [Linux `futex` system call]
-/// - [Linux `futex` feature]
-///
-/// [Linux `futex` system call]: https://man7.org/linux/man-pages/man2/futex.2.html
-/// [Linux `futex` feature]: https://man7.org/linux/man-pages/man7/futex.7.html
-#[inline]
-#[allow(clippy::too_many_arguments)]
-pub fn wake_op(
- uaddr: &AtomicU32,
- flags: Flags,
- val: u32,
- val2: u32,
- uaddr2: &AtomicU32,
- op: WakeOp,
- cmp: WakeOpCmp,
- oparg: u16,
- cmparg: u16,
-) -> io::Result<usize> {
- if oparg >= 1 << 12 || cmparg >= 1 << 12 {
- return Err(io::Errno::INVAL);
- }
-
- let val3 =
- ((op as u32) << 28) | ((cmp as u32) << 24) | ((oparg as u32) << 12) | (cmparg as u32);
-
- // SAFETY: The raw pointers come from references or null.
- unsafe { futex_val2(uaddr, Operation::WakeOp, flags, val, val2, uaddr2, val3) }
-}
-
-/// `syscall(SYS_futex, uaddr, FUTEX_LOCK_PI, 0, timeout, NULL, 0)`
-///
-/// This is a very low-level feature for implementing synchronization
-/// primitives. See the references links.
-///
-/// # References
-/// - [Linux `futex` system call]
-/// - [Linux `futex` feature]
-///
-/// [Linux `futex` system call]: https://man7.org/linux/man-pages/man2/futex.2.html
-/// [Linux `futex` feature]: https://man7.org/linux/man-pages/man7/futex.7.html
-#[inline]
-pub fn lock_pi(uaddr: &AtomicU32, flags: Flags, timeout: Option<&Timespec>) -> io::Result<()> {
- // SAFETY: The raw pointers come from references or null.
- unsafe {
- futex_timeout(uaddr, Operation::LockPi, flags, 0, timeout, ptr::null(), 0).map(|val| {
- debug_assert_eq!(
- val, 0,
- "The return value should always equal zero, if the call is successful"
- );
- })
- }
-}
-
-/// `syscall(SYS_futex, uaddr, FUTEX_UNLOCK_PI, 0, NULL, NULL, 0)`
-///
-/// This is a very low-level feature for implementing synchronization
-/// primitives. See the references links.
-///
-/// # References
-/// - [Linux `futex` system call]
-/// - [Linux `futex` feature]
-///
-/// [Linux `futex` system call]: https://man7.org/linux/man-pages/man2/futex.2.html
-/// [Linux `futex` feature]: https://man7.org/linux/man-pages/man7/futex.7.html
-#[inline]
-pub fn unlock_pi(uaddr: &AtomicU32, flags: Flags) -> io::Result<()> {
- // SAFETY: The raw pointers come from references or null.
- unsafe {
- futex_val2(uaddr, Operation::UnlockPi, flags, 0, 0, ptr::null(), 0).map(|val| {
- debug_assert_eq!(
- val, 0,
- "The return value should always equal zero, if the call is successful"
- );
- })
- }
-}
-
-/// `syscall(SYS_futex, uaddr, FUTEX_TRYLOCK_PI, 0, NULL, NULL, 0)`
-///
-/// This is a very low-level feature for implementing synchronization
-/// primitives. See the references links.
-///
-/// # References
-/// - [Linux `futex` system call]
-/// - [Linux `futex` feature]
-///
-/// [Linux `futex` system call]: https://man7.org/linux/man-pages/man2/futex.2.html
-/// [Linux `futex` feature]: https://man7.org/linux/man-pages/man7/futex.7.html
-#[inline]
-pub fn trylock_pi(uaddr: &AtomicU32, flags: Flags) -> io::Result<bool> {
- // SAFETY: The raw pointers come from references or null.
- unsafe {
- futex_val2(uaddr, Operation::TrylockPi, flags, 0, 0, ptr::null(), 0).map(|ret| ret == 0)
- }
-}
-
-/// `syscall(SYS_futex, uaddr, FUTEX_WAIT_BITSET, val, timeout, NULL, val3)`
-///
-/// This is a very low-level feature for implementing synchronization
-/// primitives. See the references links.
-///
-/// # References
-/// - [Linux `futex` system call]
-/// - [Linux `futex` feature]
-///
-/// [Linux `futex` system call]: https://man7.org/linux/man-pages/man2/futex.2.html
-/// [Linux `futex` feature]: https://man7.org/linux/man-pages/man7/futex.7.html
-#[inline]
-pub fn wait_bitset(
- uaddr: &AtomicU32,
- flags: Flags,
- val: u32,
- timeout: Option<&Timespec>,
- val3: NonZeroU32,
-) -> io::Result<()> {
- // SAFETY: The raw pointers come from references or null.
- unsafe {
- futex_timeout(
- uaddr,
- Operation::WaitBitset,
- flags,
- val,
- timeout,
- ptr::null(),
- val3.get(),
- )
- .map(|val| {
- debug_assert_eq!(
- val, 0,
- "The return value should always equal zero, if the call is successful"
- );
- })
- }
-}
-
-/// `syscall(SYS_futex, uaddr, FUTEX_WAKE_BITSET, val, NULL, NULL, val3)`
-///
-/// This is a very low-level feature for implementing synchronization
-/// primitives. See the references links.
-///
-/// # References
-/// - [Linux `futex` system call]
-/// - [Linux `futex` feature]
-///
-/// [Linux `futex` system call]: https://man7.org/linux/man-pages/man2/futex.2.html
-/// [Linux `futex` feature]: https://man7.org/linux/man-pages/man7/futex.7.html
-#[inline]
-pub fn wake_bitset(
- uaddr: &AtomicU32,
- flags: Flags,
- val: u32,
- val3: NonZeroU32,
-) -> io::Result<usize> {
- // SAFETY: The raw pointers come from references or null.
- unsafe {
- futex_val2(
- uaddr,
- Operation::WakeBitset,
- flags,
- val,
- 0,
- ptr::null(),
- val3.get(),
- )
- }
-}
-
-/// `syscall(SYS_futex, uaddr, FUTEX_WAIT_REQUEUE_PI, val, timeout, uaddr2, 0)`
-///
-/// This is a very low-level feature for implementing synchronization
-/// primitives. See the references links.
-///
-/// # References
-/// - [Linux `futex` system call]
-/// - [Linux `futex` feature]
-///
-/// [Linux `futex` system call]: https://man7.org/linux/man-pages/man2/futex.2.html
-/// [Linux `futex` feature]: https://man7.org/linux/man-pages/man7/futex.7.html
-#[inline]
-pub fn wait_requeue_pi(
- uaddr: &AtomicU32,
- flags: Flags,
- val: u32,
- timeout: Option<&Timespec>,
- uaddr2: &AtomicU32,
-) -> io::Result<()> {
- // SAFETY: The raw pointers come from references or null.
- unsafe {
- futex_timeout(
- uaddr,
- Operation::WaitRequeuePi,
- flags,
- val,
- timeout,
- uaddr2,
- 0,
- )
- .map(|val| {
- debug_assert_eq!(
- val, 0,
- "The return value should always equal zero, if the call is successful"
- );
- })
- }
-}
-
-/// `syscall(SYS_futex, uaddr, FUTEX_CMP_REQUEUE_PI, 1, val2, uaddr2, val3)`
-///
-/// This is a very low-level feature for implementing synchronization
-/// primitives. See the references links.
-///
-/// # References
-/// - [Linux `futex` system call]
-/// - [Linux `futex` feature]
-///
-/// [Linux `futex` system call]: https://man7.org/linux/man-pages/man2/futex.2.html
-/// [Linux `futex` feature]: https://man7.org/linux/man-pages/man7/futex.7.html
-#[inline]
-pub fn cmp_requeue_pi(
- uaddr: &AtomicU32,
- flags: Flags,
- val2: u32,
- uaddr2: &AtomicU32,
- val3: u32,
-) -> io::Result<usize> {
- // SAFETY: The raw pointers come from references or null.
- unsafe { futex_val2(uaddr, Operation::CmpRequeuePi, flags, 1, val2, uaddr2, val3) }
-}
-
-/// `syscall(SYS_futex, uaddr, FUTEX_LOCK_PI2, 0, timeout, NULL, 0)`
-///
-/// This is a very low-level feature for implementing synchronization
-/// primitives. See the references links.
-///
-/// # References
-/// - [Linux `futex` system call]
-/// - [Linux `futex` feature]
-///
-/// [Linux `futex` system call]: https://man7.org/linux/man-pages/man2/futex.2.html
-/// [Linux `futex` feature]: https://man7.org/linux/man-pages/man7/futex.7.html
-#[inline]
-pub fn lock_pi2(uaddr: &AtomicU32, flags: Flags, timeout: Option<&Timespec>) -> io::Result<()> {
- // SAFETY: The raw pointers come from references or null.
- unsafe {
- futex_timeout(uaddr, Operation::LockPi2, flags, 0, timeout, ptr::null(), 0).map(|val| {
- debug_assert_eq!(
- val, 0,
- "The return value should always equal zero, if the call is successful"
- );
- })
- }
-}
-
-/// A pointer in the [`Wait`] struct.
-#[repr(C)]
-#[derive(Copy, Clone)]
-#[non_exhaustive]
-pub struct WaitPtr {
- #[cfg(all(target_pointer_width = "32", target_endian = "big"))]
- #[doc(hidden)]
- pub __pad32: u32,
- #[cfg(all(target_pointer_width = "16", target_endian = "big"))]
- #[doc(hidden)]
- pub __pad16: u16,
-
- /// The pointer value.
- pub ptr: *mut c_void,
-
- #[cfg(all(target_pointer_width = "16", target_endian = "little"))]
- #[doc(hidden)]
- pub __pad16: u16,
- #[cfg(all(target_pointer_width = "32", target_endian = "little"))]
- #[doc(hidden)]
- pub __pad32: u32,
-}
-
-impl WaitPtr {
- /// Construct a new `WaitPtr` holding the given raw pointer value.
- #[inline]
- pub const fn new(ptr: *mut c_void) -> Self {
- Self {
- ptr,
-
- #[cfg(target_pointer_width = "16")]
- __pad16: 0,
- #[cfg(any(target_pointer_width = "16", target_pointer_width = "32"))]
- __pad32: 0,
- }
- }
-}
-
-impl Default for WaitPtr {
- #[inline]
- fn default() -> Self {
- Self::new(ptr::null_mut())
- }
-}
-
-impl From<*mut c_void> for WaitPtr {
- #[inline]
- fn from(ptr: *mut c_void) -> Self {
- Self::new(ptr)
- }
-}
-
-impl core::fmt::Debug for WaitPtr {
- fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
- self.ptr.fmt(f)
- }
-}
-
-/// For use with [`waitv`].
-#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-#[non_exhaustive]
-pub struct Wait {
- /// The expected value.
- pub val: u64,
- /// The address to wait for.
- pub uaddr: WaitPtr,
- /// The type and size of futex to perform.
- pub flags: WaitFlags,
-
- /// Reserved for future use.
- pub(crate) __reserved: u32,
-}
-
-impl Wait {
- /// Construct a zero-initialized `Wait`.
- #[inline]
- pub const fn new() -> Self {
- Self {
- val: 0,
- uaddr: WaitPtr::new(ptr::null_mut()),
- flags: WaitFlags::empty(),
- __reserved: 0,
- }
- }
-}
-
-impl Default for Wait {
- #[inline]
- fn default() -> Self {
- Self::new()
- }
-}
-
-/// `futex_waitv(waiters.as_ptr(), waiters.len(), flags, timeout, clockd)`—
-/// Wait on an array of futexes, wake on any.
-///
-/// This requires Linux ≥ 5.16.
-///
-/// # References
-/// - [Linux]
-///
-/// [Linux]: https://www.kernel.org/doc/html/latest/userspace-api/futex2.html
-#[inline]
-pub fn waitv(
- waiters: &[Wait],
- flags: WaitvFlags,
- timeout: Option<&Timespec>,
- clockid: ClockId,
-) -> io::Result<usize> {
- backend::thread::syscalls::futex_waitv(waiters, flags, timeout, clockid)
-}
-
-bitflags::bitflags! {
- /// Flags for use with the flags argument in [`waitv`].
- ///
- /// At this time, no flags are defined.
- #[repr(transparent)]
- #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
- pub struct WaitvFlags: u32 {
- /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
- const _ = !0;
- }
-}
-
-#[cfg(linux_raw)]
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn test_layouts() {
- use crate::backend::c;
-
- check_renamed_struct!(Wait, futex_waitv, val, uaddr, flags, __reserved);
- }
-}