pub struct AtomicTaggedPtr<T> { /* private fields */ }Expand description
A platform-adaptive atomic tagged pointer supporting thread-safe ABA protection.
Implementations§
Source§impl<T> AtomicTaggedPtr<T>
impl<T> AtomicTaggedPtr<T>
Sourcepub fn new(val: impl Into<TaggedPtr<T>>) -> Self
pub fn new(val: impl Into<TaggedPtr<T>>) -> Self
Creates a new AtomicTaggedPtr initialized with the given tagged pointer.
§Examples
use std::ptr::NonNull;
use atomic_tagged_ptr::{AtomicTaggedPtr, TaggedPtr, Tag};
let value = 42;
let ptr = NonNull::new(&value as *const i32 as *mut i32);
let atom = AtomicTaggedPtr::new(TaggedPtr::new(ptr, Tag::new(0)));Sourcepub fn load(&self, order: Ordering) -> TaggedPtr<T>
pub fn load(&self, order: Ordering) -> TaggedPtr<T>
Loads the current values of the pointer and tag atomically.
§Panics
Panics if order is Release or AcqRel.
Sourcepub fn compare_exchange(
&self,
current: impl Into<TaggedPtr<T>>,
new: impl Into<TaggedPtr<T>>,
success: Ordering,
failure: Ordering,
) -> Result<TaggedPtr<T>, TaggedPtr<T>>
pub fn compare_exchange( &self, current: impl Into<TaggedPtr<T>>, new: impl Into<TaggedPtr<T>>, success: Ordering, failure: Ordering, ) -> Result<TaggedPtr<T>, TaggedPtr<T>>
Stores a value into the pointer if the current value is the same as the current value.
The return value is a result that indicates whether the new value was written and contains
the previous value. On success, this value is guaranteed to be equal to current.
compare_exchange takes two Ordering arguments to describe the memory model of this operation.
The success ordering describes the memory ordering of the read-modify-write operation if the comparison
succeeds. The failure ordering describes the memory ordering of the read operation if the comparison fails.
§Panics
Panics if failure is Release or AcqRel.
§Examples
use atomic_tagged_ptr::{AtomicTaggedPtr, TaggedPtr, Tag};
use std::sync::atomic::Ordering;
use std::ptr::NonNull;
let val1 = 10;
let val2 = 20;
let ptr1 = NonNull::new(&val1 as *const i32 as *mut i32);
let ptr2 = NonNull::new(&val2 as *const i32 as *mut i32);
let atom = AtomicTaggedPtr::new(TaggedPtr::new(ptr1, Tag::new(1)));
// Successful compare_exchange
let res = atom.compare_exchange(
TaggedPtr::new(ptr1, Tag::new(1)),
TaggedPtr::new(ptr2, Tag::new(2)),
Ordering::SeqCst,
Ordering::SeqCst,
);
assert_eq!(res, Ok(TaggedPtr::new(ptr1, Tag::new(1))));
assert_eq!(atom.load(Ordering::SeqCst), TaggedPtr::new(ptr2, Tag::new(2)));
// Failed compare_exchange
let res = atom.compare_exchange(
TaggedPtr::new(ptr1, Tag::new(1)),
TaggedPtr::new(ptr1, Tag::new(3)),
Ordering::SeqCst,
Ordering::SeqCst,
);
assert_eq!(res, Err(TaggedPtr::new(ptr2, Tag::new(2))));Sourcepub fn compare_exchange_weak(
&self,
current: impl Into<TaggedPtr<T>>,
new: impl Into<TaggedPtr<T>>,
success: Ordering,
failure: Ordering,
) -> Result<TaggedPtr<T>, TaggedPtr<T>>
pub fn compare_exchange_weak( &self, current: impl Into<TaggedPtr<T>>, new: impl Into<TaggedPtr<T>>, success: Ordering, failure: Ordering, ) -> Result<TaggedPtr<T>, TaggedPtr<T>>
Stores a value into the pointer if the current value is the same as the current value.
Unlike [compare_exchange], this function is allowed to spuriously fail even when the comparison
succeeds, which can result in more efficient code generation on architectures that use load-link/store-conditional
instructions (like ARM).
compare_exchange_weak takes two Ordering arguments to describe the memory model of this operation.
The success ordering describes the memory ordering of the read-modify-write operation if the comparison
succeeds. The failure ordering describes the memory ordering of the read operation if the comparison fails.
§Panics
Panics if failure is Release or AcqRel.
§Examples
use atomic_tagged_ptr::{AtomicTaggedPtr, TaggedPtr, Tag};
use std::sync::atomic::Ordering;
use std::ptr::NonNull;
let val1 = 10;
let val2 = 20;
let ptr1 = NonNull::new(&val1 as *const i32 as *mut i32);
let ptr2 = NonNull::new(&val2 as *const i32 as *mut i32);
let atom = AtomicTaggedPtr::new(TaggedPtr::new(ptr1, Tag::new(1)));
let mut old = atom.load(Ordering::Relaxed);
loop {
let new = TaggedPtr::new(ptr2, Tag::new(2));
match atom.compare_exchange_weak(old, new, Ordering::SeqCst, Ordering::SeqCst) {
Ok(_) => break,
Err(actual) => old = actual,
}
}
assert_eq!(atom.load(Ordering::SeqCst), TaggedPtr::new(ptr2, Tag::new(2)));Sourcepub fn swap(
&self,
val: impl Into<TaggedPtr<T>>,
order: Ordering,
) -> TaggedPtr<T>
pub fn swap( &self, val: impl Into<TaggedPtr<T>>, order: Ordering, ) -> TaggedPtr<T>
Atomically exchanges the value and returns the old value.
This method replaces the stored pointer and tag with val and returns the previously
stored TaggedPtr.
§Panics
Panics if order is AcqRel.
§Examples
use atomic_tagged_ptr::{AtomicTaggedPtr, TaggedPtr, Tag};
use std::sync::atomic::Ordering;
use std::ptr::NonNull;
let val1 = 10;
let val2 = 20;
let ptr1 = NonNull::new(&val1 as *const i32 as *mut i32);
let ptr2 = NonNull::new(&val2 as *const i32 as *mut i32);
let atom = AtomicTaggedPtr::new(TaggedPtr::new(ptr1, Tag::new(1)));
let old = atom.swap(TaggedPtr::new(ptr2, Tag::new(2)), Ordering::SeqCst);
assert_eq!(old, TaggedPtr::new(ptr1, Tag::new(1)));
assert_eq!(atom.load(Ordering::SeqCst), TaggedPtr::new(ptr2, Tag::new(2)));Sourcepub fn into_inner(self) -> TaggedPtr<T>
pub fn into_inner(self) -> TaggedPtr<T>
Consumes the atomic and returns the inner value.
This is safe because consuming self guarantees no other threads can concurrently
access it, and therefore no synchronization is required.
§Examples
use atomic_tagged_ptr::{AtomicTaggedPtr, TaggedPtr, Tag};
use std::ptr::NonNull;
let val = 42;
let ptr = NonNull::new(&val as *const i32 as *mut i32);
let atom = AtomicTaggedPtr::new(TaggedPtr::new(ptr, Tag::new(100)));
let inner = atom.into_inner();
assert_eq!(inner.ptr.option(), ptr);
assert_eq!(inner.tag.value(), 100);Sourcepub fn fetch_update<F>(
&self,
set_order: Ordering,
fetch_order: Ordering,
f: F,
) -> Result<TaggedPtr<T>, TaggedPtr<T>>
pub fn fetch_update<F>( &self, set_order: Ordering, fetch_order: Ordering, f: F, ) -> Result<TaggedPtr<T>, TaggedPtr<T>>
Fetches the value, applies a function to it, and attempts to store the result.
This is a convenience method for compare-and-swap loops. The function f is called with
the current value, and can return Some(new_value) to attempt a CAS, or None to abort the update.
On success, it returns Ok(old_value). On failure (when f returns None), it returns Err(old_value).
fetch_update takes two Ordering arguments: set_order for the write ordering, and fetch_order for
the read/load ordering.
§Examples
use atomic_tagged_ptr::{AtomicTaggedPtr, TaggedPtr, Tag};
use std::sync::atomic::Ordering;
let atom = AtomicTaggedPtr::<i32>::default();
// Increment the tag only if the tag is less than 5
let res = atom.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |curr| {
if curr.tag.value() < 5 {
Some(curr.with_tag(curr.tag.wrapping_add(1)))
} else {
None
}
});
assert!(res.is_ok());
assert_eq!(atom.load(Ordering::SeqCst).tag.value(), 1);Sourcepub fn fetch_add_tag(&self, val: usize, order: Ordering) -> TaggedPtr<T>
pub fn fetch_add_tag(&self, val: usize, order: Ordering) -> TaggedPtr<T>
Atomically adds val to the tag of the current tagged pointer, returning the previous tagged pointer.
This operation uses a CAS loop to perform the update.
§Examples
use atomic_tagged_ptr::{AtomicTaggedPtr, TaggedPtr, Tag};
use std::sync::atomic::Ordering;
let atom = AtomicTaggedPtr::<i32>::default();
let old = atom.fetch_add_tag(5, Ordering::SeqCst);
assert_eq!(old.tag.value(), 0);
assert_eq!(atom.load(Ordering::SeqCst).tag.value(), 5);Sourcepub fn fetch_sub_tag(&self, val: usize, order: Ordering) -> TaggedPtr<T>
pub fn fetch_sub_tag(&self, val: usize, order: Ordering) -> TaggedPtr<T>
Atomically subtracts val from the tag of the current tagged pointer, returning the previous tagged pointer.
This operation uses a CAS loop to perform the update.
§Examples
use atomic_tagged_ptr::{AtomicTaggedPtr, TaggedPtr, Tag};
use std::sync::atomic::Ordering;
let atom = AtomicTaggedPtr::<i32>::new(TaggedPtr::new(None, Tag::new(10)));
let old = atom.fetch_sub_tag(3, Ordering::SeqCst);
assert_eq!(old.tag.value(), 10);
assert_eq!(atom.load(Ordering::SeqCst).tag.value(), 7);Sourcepub fn fetch_and_tag(&self, val: usize, order: Ordering) -> TaggedPtr<T>
pub fn fetch_and_tag(&self, val: usize, order: Ordering) -> TaggedPtr<T>
Atomically performs a bitwise AND on the tag of the current tagged pointer, returning the previous tagged pointer.
This operation uses a CAS loop to perform the update.
§Examples
use atomic_tagged_ptr::{AtomicTaggedPtr, TaggedPtr, Tag};
use std::sync::atomic::Ordering;
let atom = AtomicTaggedPtr::<i32>::new(TaggedPtr::new(None, Tag::new(0b1111)));
let old = atom.fetch_and_tag(0b1010, Ordering::SeqCst);
assert_eq!(old.tag.value(), 0b1111);
assert_eq!(atom.load(Ordering::SeqCst).tag.value(), 0b1010);Sourcepub fn fetch_or_tag(&self, val: usize, order: Ordering) -> TaggedPtr<T>
pub fn fetch_or_tag(&self, val: usize, order: Ordering) -> TaggedPtr<T>
Atomically performs a bitwise OR on the tag of the current tagged pointer, returning the previous tagged pointer.
This operation uses a CAS loop to perform the update.
§Examples
use atomic_tagged_ptr::{AtomicTaggedPtr, TaggedPtr, Tag};
use std::sync::atomic::Ordering;
let atom = AtomicTaggedPtr::<i32>::new(TaggedPtr::new(None, Tag::new(0b0101)));
let old = atom.fetch_or_tag(0b1010, Ordering::SeqCst);
assert_eq!(old.tag.value(), 0b0101);
assert_eq!(atom.load(Ordering::SeqCst).tag.value(), 0b1111);Sourcepub fn fetch_xor_tag(&self, val: usize, order: Ordering) -> TaggedPtr<T>
pub fn fetch_xor_tag(&self, val: usize, order: Ordering) -> TaggedPtr<T>
Atomically performs a bitwise XOR on the tag of the current tagged pointer, returning the previous tagged pointer.
This operation uses a CAS loop to perform the update.
§Examples
use atomic_tagged_ptr::{AtomicTaggedPtr, TaggedPtr, Tag};
use std::sync::atomic::Ordering;
let atom = AtomicTaggedPtr::<i32>::new(TaggedPtr::new(None, Tag::new(0b0101)));
let old = atom.fetch_xor_tag(0b1100, Ordering::SeqCst);
assert_eq!(old.tag.value(), 0b0101);
assert_eq!(atom.load(Ordering::SeqCst).tag.value(), 0b1001);Sourcepub fn fetch_set_ptr(
&self,
ptr: impl Into<Ptr<T>>,
order: Ordering,
) -> TaggedPtr<T>
pub fn fetch_set_ptr( &self, ptr: impl Into<Ptr<T>>, order: Ordering, ) -> TaggedPtr<T>
Atomically updates the pointer part of the current tagged pointer, returning the previous tagged pointer.
This operation uses a CAS loop to perform the update.
§Examples
use atomic_tagged_ptr::{AtomicTaggedPtr, TaggedPtr, Tag, Ptr};
use std::sync::atomic::Ordering;
use std::ptr::NonNull;
let val1 = 42;
let val2 = 84;
let ptr1 = NonNull::new(&val1 as *const i32 as *mut i32);
let ptr2 = NonNull::new(&val2 as *const i32 as *mut i32);
let atom = AtomicTaggedPtr::new(TaggedPtr::new(ptr1, Tag::new(10)));
let old = atom.fetch_set_ptr(ptr2, Ordering::SeqCst);
assert_eq!(old.ptr.option(), ptr1);
assert_eq!(old.tag.value(), 10);
assert_eq!(atom.load(Ordering::SeqCst).ptr.option(), ptr2);
assert_eq!(atom.load(Ordering::SeqCst).tag.value(), 10);Sourcepub fn fetch_set_tag(&self, tag: Tag, order: Ordering) -> TaggedPtr<T>
pub fn fetch_set_tag(&self, tag: Tag, order: Ordering) -> TaggedPtr<T>
Atomically updates the tag part of the current tagged pointer, returning the previous tagged pointer.
This operation uses a CAS loop to perform the update.
§Examples
use atomic_tagged_ptr::{AtomicTaggedPtr, TaggedPtr, Tag, Ptr};
use std::sync::atomic::Ordering;
let atom = AtomicTaggedPtr::<i32>::default();
let old = atom.fetch_set_tag(Tag::new(99), Ordering::SeqCst);
assert_eq!(old.tag.value(), 0);
assert_eq!(atom.load(Ordering::SeqCst).tag.value(), 99);