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