1//! The Linux `membarrier` syscall.
2//!
3//! # Safety
4//!
5//! This file defines an enum and a bitflags type that represent the same
6//! set of values and are kept in sync.
7#![allow(unsafe_code)]
8
9use crate::process::Cpuid;
10use crate::{backend, io};
11
12pub use backend::process::types::MembarrierCommand;
13
14#[cfg(any(target_os = "android", target_os = "linux"))]
15bitflags::bitflags! {
16    /// A result from [`membarrier_query`].
17    ///
18    /// These flags correspond to values of [`MembarrierCommand`] which are
19    /// supported in the OS.
20    pub struct MembarrierQuery: u32 {
21       /// `MEMBARRIER_CMD_GLOBAL`
22       #[doc(alias = "SHARED")]
23       #[doc(alias = "MEMBARRIER_CMD_SHARED")]
24       const GLOBAL = MembarrierCommand::Global as _;
25       /// `MEMBARRIER_CMD_GLOBAL_EXPEDITED`
26       const GLOBAL_EXPEDITED = MembarrierCommand::GlobalExpedited as _;
27       /// `MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED`
28       const REGISTER_GLOBAL_EXPEDITED = MembarrierCommand::RegisterGlobalExpedited as _;
29       /// `MEMBARRIER_CMD_PRIVATE_EXPEDITED`
30       const PRIVATE_EXPEDITED = MembarrierCommand::PrivateExpedited as _;
31       /// `MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED`
32       const REGISTER_PRIVATE_EXPEDITED = MembarrierCommand::RegisterPrivateExpedited as _;
33       /// `MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE`
34       const PRIVATE_EXPEDITED_SYNC_CORE = MembarrierCommand::PrivateExpeditedSyncCore as _;
35       /// `MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE`
36       const REGISTER_PRIVATE_EXPEDITED_SYNC_CORE = MembarrierCommand::RegisterPrivateExpeditedSyncCore as _;
37       /// `MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ` (since Linux 5.10)
38       const PRIVATE_EXPEDITED_RSEQ = MembarrierCommand::PrivateExpeditedRseq as _;
39       /// `MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ` (since Linux 5.10)
40       const REGISTER_PRIVATE_EXPEDITED_RSEQ = MembarrierCommand::RegisterPrivateExpeditedRseq as _;
41    }
42}
43
44#[cfg(any(target_os = "android", target_os = "linux"))]
45impl MembarrierQuery {
46    /// Test whether this query result contains the given command.
47    #[inline]
48    pub fn contains_command(self, cmd: MembarrierCommand) -> bool {
49        // Safety: `MembarrierCommand` is an enum that only contains values
50        // also valid in `MembarrierQuery`.
51        self.contains(unsafe { Self::from_bits_unchecked(cmd as _) })
52    }
53}
54
55/// `membarrier(MEMBARRIER_CMD_QUERY, 0, 0)`—Query the supported `membarrier`
56/// commands.
57///
58/// This function doesn't return a `Result` because it always succeeds; if
59/// the underlying OS doesn't support the `membarrier` syscall, it returns
60/// an empty `MembarrierQuery` value.
61///
62/// # References
63///  - [Linux]
64///
65/// [Linux]: https://man7.org/linux/man-pages/man2/membarrier.2.html
66#[inline]
67#[doc(alias = "MEMBARRIER_CMD_QUERY")]
68pub fn membarrier_query() -> MembarrierQuery {
69    backend::process::syscalls::membarrier_query()
70}
71
72/// `membarrier(cmd, 0, 0)`—Perform a memory barrier.
73///
74/// # References
75///  - [Linux]
76///
77/// [Linux]: https://man7.org/linux/man-pages/man2/membarrier.2.html
78#[inline]
79pub fn membarrier(cmd: MembarrierCommand) -> io::Result<()> {
80    backend::process::syscalls::membarrier(cmd)
81}
82
83/// `membarrier(cmd, MEMBARRIER_CMD_FLAG_CPU, cpu)`—Perform a memory barrier
84/// with a specific CPU.
85///
86/// # References
87///  - [Linux]
88///
89/// [Linux]: https://man7.org/linux/man-pages/man2/membarrier.2.html
90#[inline]
91pub fn membarrier_cpu(cmd: MembarrierCommand, cpu: Cpuid) -> io::Result<()> {
92    backend::process::syscalls::membarrier_cpu(cmd, cpu)
93}
94