shuttle_std/sync/atomic/ptr.rs
1use crate::sync::atomic::Atomic;
2#[cfg(test)]
3use crate::sync::ResourceSignature;
4use std::sync::atomic::Ordering;
5
6/// A raw pointer type which can be safely shared between threads.
7pub struct AtomicPtr<T> {
8 inner: Atomic<*mut T>,
9}
10
11impl<T> Default for AtomicPtr<T> {
12 fn default() -> Self {
13 Self::new(std::ptr::null_mut())
14 }
15}
16
17impl<T> From<*mut T> for AtomicPtr<T> {
18 fn from(p: *mut T) -> Self {
19 Self::new(p)
20 }
21}
22
23impl<T> std::fmt::Debug for AtomicPtr<T> {
24 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
25 std::fmt::Debug::fmt(unsafe { &self.raw_load() }, f)
26 }
27}
28
29// Atomic operations make it safe to Send + Sync this shared raw pointer (establishing the safety of
30// *using* the raw pointer is still up to the caller)
31unsafe impl<T> Send for AtomicPtr<T> {}
32unsafe impl<T> Sync for AtomicPtr<T> {}
33
34impl<T> AtomicPtr<T> {
35 /// Creates a new `AtomicPtr`.
36 #[track_caller]
37 pub const fn new(v: *mut T) -> Self {
38 Self { inner: Atomic::new(v) }
39 }
40
41 /// Returns a mutable reference to the underlying pointer.
42 pub fn get_mut(&mut self) -> &mut *mut T {
43 self.inner.get_mut()
44 }
45
46 /// Consumes the atomic and returns the contained value.
47 pub fn into_inner(self) -> *mut T {
48 self.inner.into_inner()
49 }
50
51 /// Loads a value from the pointer.
52 pub fn load(&self, order: Ordering) -> *mut T {
53 self.inner.load(order)
54 }
55
56 /// Stores a value into the pointer.
57 pub fn store(&self, val: *mut T, order: Ordering) {
58 self.inner.store(val, order)
59 }
60
61 /// Stores a value into the atomic pointer, returning the previous value.
62 pub fn swap(&self, val: *mut T, order: Ordering) -> *mut T {
63 self.inner.swap(val, order)
64 }
65
66 /// Fetches the value, and applies a function to it that returns an optional new value.
67 /// Returns a `Result` of `Ok(previous_value)` if the function returned `Some(_)`, else
68 /// `Err(previous_value)`.
69 pub fn fetch_update<F>(&self, set_order: Ordering, fetch_order: Ordering, f: F) -> Result<*mut T, *mut T>
70 where
71 F: FnMut(*mut T) -> Option<*mut T>,
72 {
73 self.inner.fetch_update(set_order, fetch_order, f)
74 }
75
76 /// Stores a value into the atomic pointer if the current value is the same as the
77 /// `current` value.
78 #[deprecated(since = "0.0.6", note = "Use `compare_exchange` or `compare_exchange_weak` instead")]
79 pub fn compare_and_swap(&self, current: *mut T, new: *mut T, order: Ordering) -> *mut T {
80 match self.compare_exchange(current, new, order, order) {
81 Ok(v) => v,
82 Err(v) => v,
83 }
84 }
85
86 /// Stores a value into the atomic pointer if the current value is the same as the
87 /// `current` value.
88 ///
89 /// The return value is a result indicating whether the new value was written and
90 /// containing the previous value. On success this value is guaranteed to be equal to
91 /// `current`.
92 pub fn compare_exchange(
93 &self,
94 current: *mut T,
95 new: *mut T,
96 success: Ordering,
97 failure: Ordering,
98 ) -> Result<*mut T, *mut T> {
99 self.fetch_update(success, failure, |val| (val == current).then_some(new))
100 }
101
102 /// Stores a value into the atomic pointer if the current value is the same as the
103 /// `current` value.
104 ///
105 /// Unlike [`AtomicPtr::compare_exchange`], this function is allowed to spuriously fail
106 /// even when the comparison succeeds, which can result in more efficient code on some
107 /// platforms. The return value is a result indicating whether the new value was written
108 /// and containing the previous value.
109 // TODO actually produce spurious failures
110 pub fn compare_exchange_weak(
111 &self,
112 current: *mut T,
113 new: *mut T,
114 success: Ordering,
115 failure: Ordering,
116 ) -> Result<*mut T, *mut T> {
117 self.compare_exchange(current, new, success, failure)
118 }
119
120 /// Load the atomic value directly without triggering any Shuttle context switches.
121 ///
122 /// # Safety
123 ///
124 /// Shuttle does not consider potential concurrent interleavings of this function call,
125 /// and so it should be used when those interleavings aren't important (primarily in
126 /// debugging scenarios where we might want to just print this atomic's value).
127 pub unsafe fn raw_load(&self) -> *mut T {
128 self.inner.raw_load()
129 }
130
131 #[cfg(test)]
132 pub(crate) fn signature(&self) -> ResourceSignature {
133 self.inner.signature()
134 }
135}