AtomicTaggedPtr compareexchange ptr part, remove unsafe nonnull conversions
This commit is contained in:
parent
1ea8bcb3ed
commit
c2f1d8d749
158
src/ptr.rs
158
src/ptr.rs
|
@ -183,17 +183,15 @@ impl<T, const BITS: u8> TaggedAtomicPtr<T, BITS> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ptr(&self, order: atomic::Ordering) -> NonNull<T> {
|
#[doc(alias = "load_ptr")]
|
||||||
unsafe {
|
pub fn ptr(&self, order: atomic::Ordering) -> *mut T {
|
||||||
NonNull::new_unchecked(
|
self.ptr
|
||||||
self.ptr
|
.load(order)
|
||||||
.load(order)
|
.map_addr(|addr| addr & !Self::mask())
|
||||||
.map_addr(|addr| addr & !Self::mask())
|
.cast()
|
||||||
.cast(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[doc(alias = "load_tag")]
|
||||||
pub fn tag(&self, order: atomic::Ordering) -> usize {
|
pub fn tag(&self, order: atomic::Ordering) -> usize {
|
||||||
self.ptr.load(order).addr() & Self::mask()
|
self.ptr.load(order).addr() & Self::mask()
|
||||||
}
|
}
|
||||||
|
@ -238,6 +236,68 @@ impl<T, const BITS: u8> TaggedAtomicPtr<T, BITS> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// returns tag
|
||||||
|
#[inline(always)]
|
||||||
|
fn compare_exchange_ptr_inner(
|
||||||
|
&self,
|
||||||
|
old: *mut T,
|
||||||
|
new: *mut T,
|
||||||
|
success: atomic::Ordering,
|
||||||
|
failure: atomic::Ordering,
|
||||||
|
cmpxchg: fn(
|
||||||
|
&AtomicPtr<()>,
|
||||||
|
*mut (),
|
||||||
|
*mut (),
|
||||||
|
atomic::Ordering,
|
||||||
|
atomic::Ordering,
|
||||||
|
) -> Result<*mut (), *mut ()>,
|
||||||
|
) -> Result<*mut T, *mut T> {
|
||||||
|
let mask = Self::mask();
|
||||||
|
let old_tag = self.ptr.load(failure).addr() & mask;
|
||||||
|
|
||||||
|
// old and new must be aligned to the mask, so no need to & with the mask.
|
||||||
|
let old = old.map_addr(|addr| addr | old_tag).cast();
|
||||||
|
let new = new.map_addr(|addr| addr | old_tag).cast();
|
||||||
|
|
||||||
|
let result = cmpxchg(&self.ptr, old, new, success, failure);
|
||||||
|
|
||||||
|
result
|
||||||
|
.map(|ptr| ptr.map_addr(|addr| addr & !mask).cast())
|
||||||
|
.map_err(|ptr| ptr.map_addr(|addr| addr & !mask).cast())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compare_exchange_ptr(
|
||||||
|
&self,
|
||||||
|
old: *mut T,
|
||||||
|
new: *mut T,
|
||||||
|
success: atomic::Ordering,
|
||||||
|
failure: atomic::Ordering,
|
||||||
|
) -> Result<*mut T, *mut T> {
|
||||||
|
self.compare_exchange_ptr_inner(
|
||||||
|
old,
|
||||||
|
new,
|
||||||
|
success,
|
||||||
|
failure,
|
||||||
|
AtomicPtr::<()>::compare_exchange,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compare_exchange_weak_ptr(
|
||||||
|
&self,
|
||||||
|
old: *mut T,
|
||||||
|
new: *mut T,
|
||||||
|
success: atomic::Ordering,
|
||||||
|
failure: atomic::Ordering,
|
||||||
|
) -> Result<*mut T, *mut T> {
|
||||||
|
self.compare_exchange_ptr_inner(
|
||||||
|
old,
|
||||||
|
new,
|
||||||
|
success,
|
||||||
|
failure,
|
||||||
|
AtomicPtr::<()>::compare_exchange_weak,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// returns tag
|
/// returns tag
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn compare_exchange_tag_inner(
|
fn compare_exchange_tag_inner(
|
||||||
|
@ -268,7 +328,6 @@ impl<T, const BITS: u8> TaggedAtomicPtr<T, BITS> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// returns tag
|
/// returns tag
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn compare_exchange_tag(
|
pub fn compare_exchange_tag(
|
||||||
&self,
|
&self,
|
||||||
old: usize,
|
old: usize,
|
||||||
|
@ -302,7 +361,7 @@ impl<T, const BITS: u8> TaggedAtomicPtr<T, BITS> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[doc(alias = "store_ptr")]
|
||||||
pub fn set_ptr(&self, ptr: *mut T, success: atomic::Ordering, failure: atomic::Ordering) {
|
pub fn set_ptr(&self, ptr: *mut T, success: atomic::Ordering, failure: atomic::Ordering) {
|
||||||
let mask = Self::mask();
|
let mask = Self::mask();
|
||||||
let ptr = ptr.cast::<()>();
|
let ptr = ptr.cast::<()>();
|
||||||
|
@ -319,6 +378,7 @@ impl<T, const BITS: u8> TaggedAtomicPtr<T, BITS> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[doc(alias = "store_tag")]
|
||||||
pub fn set_tag(&self, tag: usize, success: atomic::Ordering, failure: atomic::Ordering) {
|
pub fn set_tag(&self, tag: usize, success: atomic::Ordering, failure: atomic::Ordering) {
|
||||||
let mask = Self::mask();
|
let mask = Self::mask();
|
||||||
loop {
|
loop {
|
||||||
|
@ -335,6 +395,42 @@ impl<T, const BITS: u8> TaggedAtomicPtr<T, BITS> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn swap_tag(
|
||||||
|
&self,
|
||||||
|
new: usize,
|
||||||
|
success: atomic::Ordering,
|
||||||
|
failure: atomic::Ordering,
|
||||||
|
) -> usize {
|
||||||
|
let mask = Self::mask();
|
||||||
|
loop {
|
||||||
|
let ptr = self.ptr.load(failure);
|
||||||
|
let new = ptr.map_addr(|addr| (addr & !mask) | (new & mask));
|
||||||
|
|
||||||
|
if let Ok(old) = self.ptr.compare_exchange_weak(ptr, new, success, failure) {
|
||||||
|
break old.addr() & mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn swap_ptr(
|
||||||
|
&self,
|
||||||
|
new: *mut T,
|
||||||
|
success: atomic::Ordering,
|
||||||
|
failure: atomic::Ordering,
|
||||||
|
) -> *mut T {
|
||||||
|
let mask = Self::mask();
|
||||||
|
let new = new.cast::<()>();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let old = self.ptr.load(failure);
|
||||||
|
let new = new.map_addr(|addr| (addr & !mask) | (old.addr() & mask));
|
||||||
|
|
||||||
|
if let Ok(old) = self.ptr.compare_exchange_weak(old, new, success, failure) {
|
||||||
|
break old.map_addr(|addr| addr & !mask).cast();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn ptr_and_tag(&self, order: atomic::Ordering) -> (NonNull<T>, usize) {
|
pub fn ptr_and_tag(&self, order: atomic::Ordering) -> (NonNull<T>, usize) {
|
||||||
let mask = Self::mask();
|
let mask = Self::mask();
|
||||||
let ptr = self.ptr.load(order);
|
let ptr = self.ptr.load(order);
|
||||||
|
@ -357,7 +453,7 @@ mod tests {
|
||||||
let ptr = Box::into_raw(Box::new(42u32));
|
let ptr = Box::into_raw(Box::new(42u32));
|
||||||
let tagged_ptr = TaggedAtomicPtr::<u32, 2>::new(ptr, 0);
|
let tagged_ptr = TaggedAtomicPtr::<u32, 2>::new(ptr, 0);
|
||||||
assert_eq!(tagged_ptr.tag(Ordering::Relaxed), 0);
|
assert_eq!(tagged_ptr.tag(Ordering::Relaxed), 0);
|
||||||
assert_eq!(tagged_ptr.ptr(Ordering::Relaxed).as_ptr(), ptr);
|
assert_eq!(tagged_ptr.ptr(Ordering::Relaxed), ptr);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
_ = Box::from_raw(ptr);
|
_ = Box::from_raw(ptr);
|
||||||
|
@ -369,11 +465,11 @@ mod tests {
|
||||||
let ptr = Box::into_raw(Box::new(42u32));
|
let ptr = Box::into_raw(Box::new(42u32));
|
||||||
let tagged_ptr = TaggedAtomicPtr::<u32, 2>::new(ptr, 0b11);
|
let tagged_ptr = TaggedAtomicPtr::<u32, 2>::new(ptr, 0b11);
|
||||||
assert_eq!(tagged_ptr.tag(Ordering::Relaxed), 0b11);
|
assert_eq!(tagged_ptr.tag(Ordering::Relaxed), 0b11);
|
||||||
assert_eq!(tagged_ptr.ptr(Ordering::Relaxed).as_ptr(), ptr);
|
assert_eq!(tagged_ptr.ptr(Ordering::Relaxed), ptr);
|
||||||
|
|
||||||
assert_eq!(tagged_ptr.take_tag(Ordering::Relaxed), 0b11);
|
assert_eq!(tagged_ptr.take_tag(Ordering::Relaxed), 0b11);
|
||||||
assert_eq!(tagged_ptr.tag(Ordering::Relaxed), 0);
|
assert_eq!(tagged_ptr.tag(Ordering::Relaxed), 0);
|
||||||
assert_eq!(tagged_ptr.ptr(Ordering::Relaxed).as_ptr(), ptr);
|
assert_eq!(tagged_ptr.ptr(Ordering::Relaxed), ptr);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
_ = Box::from_raw(ptr);
|
_ = Box::from_raw(ptr);
|
||||||
|
@ -385,11 +481,11 @@ mod tests {
|
||||||
let ptr = Box::into_raw(Box::new(42u32));
|
let ptr = Box::into_raw(Box::new(42u32));
|
||||||
let tagged_ptr = TaggedAtomicPtr::<u32, 2>::new(ptr, 0b11);
|
let tagged_ptr = TaggedAtomicPtr::<u32, 2>::new(ptr, 0b11);
|
||||||
assert_eq!(tagged_ptr.tag(Ordering::Relaxed), 0b11);
|
assert_eq!(tagged_ptr.tag(Ordering::Relaxed), 0b11);
|
||||||
assert_eq!(tagged_ptr.ptr(Ordering::Relaxed).as_ptr(), ptr);
|
assert_eq!(tagged_ptr.ptr(Ordering::Relaxed), ptr);
|
||||||
|
|
||||||
assert_eq!(tagged_ptr.fetch_or_tag(0b10, Ordering::Relaxed), 0b11);
|
assert_eq!(tagged_ptr.fetch_or_tag(0b10, Ordering::Relaxed), 0b11);
|
||||||
assert_eq!(tagged_ptr.tag(Ordering::Relaxed), 0b11 | 0b10);
|
assert_eq!(tagged_ptr.tag(Ordering::Relaxed), 0b11 | 0b10);
|
||||||
assert_eq!(tagged_ptr.ptr(Ordering::Relaxed).as_ptr(), ptr);
|
assert_eq!(tagged_ptr.ptr(Ordering::Relaxed), ptr);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
_ = Box::from_raw(ptr);
|
_ = Box::from_raw(ptr);
|
||||||
|
@ -397,11 +493,11 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn tagged_ptr_exchange() {
|
fn tagged_ptr_exchange_tag() {
|
||||||
let ptr = Box::into_raw(Box::new(42u32));
|
let ptr = Box::into_raw(Box::new(42u32));
|
||||||
let tagged_ptr = TaggedAtomicPtr::<u32, 2>::new(ptr, 0b11);
|
let tagged_ptr = TaggedAtomicPtr::<u32, 2>::new(ptr, 0b11);
|
||||||
assert_eq!(tagged_ptr.tag(Ordering::Relaxed), 0b11);
|
assert_eq!(tagged_ptr.tag(Ordering::Relaxed), 0b11);
|
||||||
assert_eq!(tagged_ptr.ptr(Ordering::Relaxed).as_ptr(), ptr);
|
assert_eq!(tagged_ptr.ptr(Ordering::Relaxed), ptr);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
tagged_ptr
|
tagged_ptr
|
||||||
|
@ -411,10 +507,34 @@ mod tests {
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(tagged_ptr.tag(Ordering::Relaxed), 0b10);
|
assert_eq!(tagged_ptr.tag(Ordering::Relaxed), 0b10);
|
||||||
assert_eq!(tagged_ptr.ptr(Ordering::Relaxed).as_ptr(), ptr);
|
assert_eq!(tagged_ptr.ptr(Ordering::Relaxed), ptr);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
_ = Box::from_raw(ptr);
|
_ = Box::from_raw(ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn tagged_ptr_exchange_ptr() {
|
||||||
|
let ptr = Box::into_raw(Box::new(42u32));
|
||||||
|
let tagged_ptr = TaggedAtomicPtr::<u32, 2>::new(ptr, 0b11);
|
||||||
|
assert_eq!(tagged_ptr.tag(Ordering::Relaxed), 0b11);
|
||||||
|
assert_eq!(tagged_ptr.ptr(Ordering::Relaxed), ptr);
|
||||||
|
|
||||||
|
let new_ptr = Box::into_raw(Box::new(43u32));
|
||||||
|
assert_eq!(
|
||||||
|
tagged_ptr
|
||||||
|
.compare_exchange_ptr(ptr, new_ptr, Ordering::Relaxed, Ordering::Relaxed)
|
||||||
|
.unwrap(),
|
||||||
|
ptr
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(tagged_ptr.tag(Ordering::Relaxed), 0b11);
|
||||||
|
assert_eq!(tagged_ptr.ptr(Ordering::Relaxed), new_ptr);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
_ = Box::from_raw(ptr);
|
||||||
|
_ = Box::from_raw(new_ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue