1 use std
::marker
::PhantomData
;
4 use std
::sync
::atomic
::{self, Ordering}
;
6 use super::{Owned, Shared, Guard}
;
8 /// Like `std::sync::atomic::AtomicPtr`.
10 /// Provides atomic access to a (nullable) pointer of type `T`, interfacing with
11 /// the `Owned` and `Shared` types.
13 pub struct Atomic
<T
> {
14 ptr
: atomic
::AtomicPtr
<T
>,
15 _marker
: PhantomData
<*const ()>,
18 unsafe impl<T
: Sync
> Send
for Atomic
<T
> {}
19 unsafe impl<T
: Sync
> Sync
for Atomic
<T
> {}
21 fn opt_shared_into_raw
<T
>(val
: Option
<Shared
<T
>>) -> *mut T
{
22 val
.map(|p
| p
.as_raw()).unwrap_or(ptr
::null_mut())
25 fn opt_owned_as_raw
<T
>(val
: &Option
<Owned
<T
>>) -> *mut T
{
26 val
.as_ref().map(Owned
::as_raw
).unwrap_or(ptr
::null_mut())
29 fn opt_owned_into_raw
<T
>(val
: Option
<Owned
<T
>>) -> *mut T
{
30 let ptr
= val
.as_ref().map(Owned
::as_raw
).unwrap_or(ptr
::null_mut());
36 /// Create a new, null atomic pointer.
37 #[cfg(feature = "nightly")]
38 pub const fn null() -> Atomic
<T
> {
40 ptr
: atomic
::AtomicPtr
::new(0 as *mut _
),
45 #[cfg(not(feature = "nightly"))]
46 pub fn null() -> Atomic
<T
> {
48 ptr
: atomic
::AtomicPtr
::new(0 as *mut _
),
53 /// Create a new atomic pointer
54 pub fn new(data
: T
) -> Atomic
<T
> {
56 ptr
: atomic
::AtomicPtr
::new(Box
::into_raw(Box
::new(data
))),
61 /// Do an atomic load with the given memory ordering.
63 /// In order to perform the load, we must pass in a borrow of a
64 /// `Guard`. This is a way of guaranteeing that the thread has pinned the
65 /// epoch for the entire lifetime `'a`. In return, you get an optional
66 /// `Shared` pointer back (`None` if the `Atomic` is currently null), with
67 /// lifetime tied to the guard.
71 /// Panics if `ord` is `Release` or `AcqRel`.
72 pub fn load
<'a
>(&self, ord
: Ordering
, _
: &'a Guard
) -> Option
<Shared
<'a
, T
>> {
73 unsafe { Shared::from_raw(self.ptr.load(ord)) }
76 /// Do an atomic store with the given memory ordering.
78 /// Transfers ownership of the given `Owned` pointer, if any. Since no
79 /// lifetime information is acquired, no `Guard` value is needed.
83 /// Panics if `ord` is `Acquire` or `AcqRel`.
84 pub fn store(&self, val
: Option
<Owned
<T
>>, ord
: Ordering
) {
85 self.ptr
.store(opt_owned_into_raw(val
), ord
)
88 /// Do an atomic store with the given memory ordering, immediately yielding
89 /// a shared reference to the pointer that was stored.
91 /// Transfers ownership of the given `Owned` pointer, yielding a `Shared`
92 /// reference to it. Since the reference is valid only for the curent epoch,
93 /// it's lifetime is tied to a `Guard` value.
97 /// Panics if `ord` is `Acquire` or `AcqRel`.
98 pub fn store_and_ref
<'a
>(&self, val
: Owned
<T
>, ord
: Ordering
, _
: &'a Guard
)
102 let shared
= Shared
::from_owned(val
);
103 self.store_shared(Some(shared
), ord
);
108 /// Do an atomic store of a `Shared` pointer with the given memory ordering.
110 /// This operation does not require a guard, because it does not yield any
111 /// new information about the lifetime of a pointer.
115 /// Panics if `ord` is `Acquire` or `AcqRel`.
116 pub fn store_shared(&self, val
: Option
<Shared
<T
>>, ord
: Ordering
) {
117 self.ptr
.store(opt_shared_into_raw(val
), ord
)
120 /// Do a compare-and-set from a `Shared` to an `Owned` pointer with the
121 /// given memory ordering.
123 /// As with `store`, this operation does not require a guard; it produces no new
124 /// lifetime information. The `Result` indicates whether the CAS succeeded; if
125 /// not, ownership of the `new` pointer is returned to the caller.
126 pub fn cas(&self, old
: Option
<Shared
<T
>>, new
: Option
<Owned
<T
>>, ord
: Ordering
)
127 -> Result
<(), Option
<Owned
<T
>>>
129 if self.ptr
.compare_and_swap(opt_shared_into_raw(old
),
130 opt_owned_as_raw(&new
),
131 ord
) == opt_shared_into_raw(old
)
140 /// Do a compare-and-set from a `Shared` to an `Owned` pointer with the
141 /// given memory ordering, immediatley acquiring a new `Shared` reference to
142 /// the previously-owned pointer if successful.
144 /// This operation is analogous to `store_and_ref`.
145 pub fn cas_and_ref
<'a
>(&self, old
: Option
<Shared
<T
>>, new
: Owned
<T
>,
146 ord
: Ordering
, _
: &'a Guard
)
147 -> Result
<Shared
<'a
, T
>, Owned
<T
>>
149 if self.ptr
.compare_and_swap(opt_shared_into_raw(old
), new
.as_raw(), ord
)
150 == opt_shared_into_raw(old
)
152 Ok(unsafe { Shared::from_owned(new) }
)
158 /// Do a compare-and-set from a `Shared` to another `Shared` pointer with
159 /// the given memory ordering.
161 /// The boolean return value is `true` when the CAS is successful.
162 pub fn cas_shared(&self, old
: Option
<Shared
<T
>>, new
: Option
<Shared
<T
>>, ord
: Ordering
)
165 self.ptr
.compare_and_swap(opt_shared_into_raw(old
),
166 opt_shared_into_raw(new
),
167 ord
) == opt_shared_into_raw(old
)
170 /// Do an atomic swap with an `Owned` pointer with the given memory ordering.
171 pub fn swap
<'a
>(&self, new
: Option
<Owned
<T
>>, ord
: Ordering
, _
: &'a Guard
)
172 -> Option
<Shared
<'a
, T
>> {
173 unsafe { Shared::from_raw(self.ptr.swap(opt_owned_into_raw(new), ord)) }
176 /// Do an atomic swap with a `Shared` pointer with the given memory ordering.
177 pub fn swap_shared
<'a
>(&self, new
: Option
<Shared
<T
>>, ord
: Ordering
, _
: &'a Guard
)
178 -> Option
<Shared
<'a
, T
>> {
179 unsafe { Shared::from_raw(self.ptr.swap(opt_shared_into_raw(new), ord)) }