    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93

    //! The Linux `membarrier` syscall.
    //!
    //! # Safety
    //!
    //! This file defines an enum and a bitflags type that represent the same
    //! set of values and are kept in sync.
    #![allow(unsafe_code)]

    use crate::process::Cpuid;
    use crate::{backend, io};

    pub use backend::process::types::MembarrierCommand;

    #[cfg(any(target_os = "android", target_os = "linux"))]
    bitflags::bitflags! {
        /// A result from [`membarrier_query`].
        ///
        /// These flags correspond to values of [`MembarrierCommand`] which are
        /// supported in the OS.
        pub struct MembarrierQuery: u32 {
           /// `MEMBARRIER_CMD_GLOBAL`
           #[doc(alias = "SHARED")]
           #[doc(alias = "MEMBARRIER_CMD_SHARED")]
           const GLOBAL = MembarrierCommand::Global as _;
           /// `MEMBARRIER_CMD_GLOBAL_EXPEDITED`
           const GLOBAL_EXPEDITED = MembarrierCommand::GlobalExpedited as _;
           /// `MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED`
           const REGISTER_GLOBAL_EXPEDITED = MembarrierCommand::RegisterGlobalExpedited as _;
           /// `MEMBARRIER_CMD_PRIVATE_EXPEDITED`
           const PRIVATE_EXPEDITED = MembarrierCommand::PrivateExpedited as _;
           /// `MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED`
           const REGISTER_PRIVATE_EXPEDITED = MembarrierCommand::RegisterPrivateExpedited as _;
           /// `MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE`
           const PRIVATE_EXPEDITED_SYNC_CORE = MembarrierCommand::PrivateExpeditedSyncCore as _;
           /// `MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE`
           const REGISTER_PRIVATE_EXPEDITED_SYNC_CORE = MembarrierCommand::RegisterPrivateExpeditedSyncCore as _;
           /// `MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ` (since Linux 5.10)
           const PRIVATE_EXPEDITED_RSEQ = MembarrierCommand::PrivateExpeditedRseq as _;
           /// `MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ` (since Linux 5.10)
           const REGISTER_PRIVATE_EXPEDITED_RSEQ = MembarrierCommand::RegisterPrivateExpeditedRseq as _;
        }
    }

    #[cfg(any(target_os = "android", target_os = "linux"))]
    impl MembarrierQuery {
        /// Test whether this query result contains the given command.
        #[inline]
        pub fn contains_command(self, cmd: MembarrierCommand) -> bool {
            // Safety: `MembarrierCommand` is an enum that only contains values
            // also valid in `MembarrierQuery`.
            self.contains(unsafe { Self::from_bits_unchecked(cmd as _) })
        }
    }

    /// `membarrier(MEMBARRIER_CMD_QUERY, 0, 0)`—Query the supported `membarrier`
    /// commands.
    ///
    /// This function doesn't return a `Result` because it always succeeds; if
    /// the underlying OS doesn't support the `membarrier` syscall, it returns
    /// an empty `MembarrierQuery` value.
    ///
    /// # References
    ///  - [Linux]
    ///
    /// [Linux]: https://man7.org/linux/man-pages/man2/membarrier.2.html
    #[inline]
    #[doc(alias = "MEMBARRIER_CMD_QUERY")]
    pub fn membarrier_query() -> MembarrierQuery {
        backend::process::syscalls::membarrier_query()
    }

    /// `membarrier(cmd, 0, 0)`—Perform a memory barrier.
    ///
    /// # References
    ///  - [Linux]
    ///
    /// [Linux]: https://man7.org/linux/man-pages/man2/membarrier.2.html
    #[inline]
    pub fn membarrier(cmd: MembarrierCommand) -> io::Result<()> {
        backend::process::syscalls::membarrier(cmd)
    }

    /// `membarrier(cmd, MEMBARRIER_CMD_FLAG_CPU, cpu)`—Perform a memory barrier
    /// with a specific CPU.
    ///
    /// # References
    ///  - [Linux]
    ///
    /// [Linux]: https://man7.org/linux/man-pages/man2/membarrier.2.html
    #[inline]
    pub fn membarrier_cpu(cmd: MembarrierCommand, cpu: Cpuid) -> io::Result<()> {
        backend::process::syscalls::membarrier_cpu(cmd, cpu)
    }