From 19944100c6ceb43fa45d4298ad3ac47ece351d0d Mon Sep 17 00:00:00 2001 From: Christian Eltzschig Date: Sat, 20 Apr 2024 00:16:10 +0200 Subject: [PATCH 1/7] [#200] Add IceAtomic to support AtomicU64 on 32-bit --- iceoryx2-pal/concurrency-sync/src/atomic.rs | 144 ++++++++++++++++++++ iceoryx2-pal/concurrency-sync/src/lib.rs | 1 + iceoryx2-pal/concurrency-sync/src/rwlock.rs | 10 +- 3 files changed, 150 insertions(+), 5 deletions(-) create mode 100644 iceoryx2-pal/concurrency-sync/src/atomic.rs diff --git a/iceoryx2-pal/concurrency-sync/src/atomic.rs b/iceoryx2-pal/concurrency-sync/src/atomic.rs new file mode 100644 index 000000000..3fe9fe0fc --- /dev/null +++ b/iceoryx2-pal/concurrency-sync/src/atomic.rs @@ -0,0 +1,144 @@ +// Copyright (c) 2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache Software License 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license +// which is available at https://opensource.org/licenses/MIT. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT + +use core::{ + cell::UnsafeCell, + ops::{AddAssign, SubAssign}, + sync::atomic::Ordering, +}; + +use crate::{rwlock::RwLockWriterPreference, WaitAction}; + +pub type IceAtomicBool = core::sync::atomic::AtomicBool; +pub type IceAtomicUsize = core::sync::atomic::AtomicUsize; + +pub type IceAtomicU8 = core::sync::atomic::AtomicU8; +pub type IceAtomicU16 = core::sync::atomic::AtomicU16; +pub type IceAtomicU32 = core::sync::atomic::AtomicU32; +pub type IceAtomicI8 = core::sync::atomic::AtomicI8; +pub type IceAtomicI16 = core::sync::atomic::AtomicI16; +pub type IceAtomicI32 = core::sync::atomic::AtomicI32; + +#[cfg(target_pointer_width = "64")] +pub type IceAtomicI64 = core::sync::atomic::AtomicI64; + +#[cfg(target_pointer_width = "64")] +pub type IceAtomicU64 = core::sync::atomic::AtomicU64; + +#[cfg(target_pointer_width = "32")] +pub type IceAtomicI64 = IceAtomic; + +#[cfg(target_pointer_width = "32")] +pub type IceAtomicU64 = IceAtomic; + +type LockType = RwLockWriterPreference; + +#[repr(C)] +pub struct IceAtomic { + data: UnsafeCell, + lock: LockType, +} + +impl IceAtomic { + pub fn new(v: T) -> Self { + Self { + data: UnsafeCell::new(v), + lock: LockType::new(), + } + } + + fn read_lock(&self) { + self.lock.read_lock(|_, _| WaitAction::Continue); + } + + fn write_lock(&self) { + self.lock + .write_lock(|_, _| WaitAction::Continue, |_| {}, |_| {}); + } + + fn unlock(&self) { + self.lock.unlock(|_| {}, |_| {}); + } + + pub fn compare_exchange( + &self, + current: T, + new: T, + success: Ordering, + failure: Ordering, + ) -> Result { + self.write_lock(); + let data = unsafe { *self.data.get() }; + if data != current { + core::sync::atomic::fence(failure); + self.unlock(); + return Err(data); + } + + unsafe { *self.data.get() = new }; + core::sync::atomic::fence(success); + self.unlock(); + Ok(data) + } + + pub fn compare_exchange_weak( + &self, + current: T, + new: T, + success: Ordering, + failure: Ordering, + ) -> Result { + self.compare_exchange(current, new, success, failure) + } + + pub fn fetch_add(&self, value: T, order: Ordering) -> T { + self.write_lock(); + let data = unsafe { *self.data.get() }; + unsafe { *self.data.get() += value }; + core::sync::atomic::fence(order); + self.unlock(); + data + } + + pub fn fetch_sub(&self, value: T, order: Ordering) -> T { + self.write_lock(); + let data = unsafe { *self.data.get() }; + unsafe { *self.data.get() -= value }; + core::sync::atomic::fence(order); + self.unlock(); + data + } + + pub fn load(&self, order: Ordering) -> T { + self.read_lock(); + let data = unsafe { *self.data.get() }; + core::sync::atomic::fence(order); + self.unlock(); + data + } + + pub fn store(&self, value: T, order: Ordering) { + self.write_lock(); + unsafe { *self.data.get() = value }; + core::sync::atomic::fence(order); + self.unlock(); + } + + pub fn swap(&self, value: T, order: Ordering) -> T { + self.write_lock(); + let data = unsafe { *self.data.get() }; + unsafe { *self.data.get() = value }; + core::sync::atomic::fence(order); + self.unlock(); + data + } +} diff --git a/iceoryx2-pal/concurrency-sync/src/lib.rs b/iceoryx2-pal/concurrency-sync/src/lib.rs index d444448e2..74b6a5bac 100644 --- a/iceoryx2-pal/concurrency-sync/src/lib.rs +++ b/iceoryx2-pal/concurrency-sync/src/lib.rs @@ -14,6 +14,7 @@ const SPIN_REPETITIONS: u64 = 10000; +pub mod atomic; pub mod barrier; pub mod condition_variable; pub mod mutex; diff --git a/iceoryx2-pal/concurrency-sync/src/rwlock.rs b/iceoryx2-pal/concurrency-sync/src/rwlock.rs index 28c1a2bb9..96fe4d22d 100644 --- a/iceoryx2-pal/concurrency-sync/src/rwlock.rs +++ b/iceoryx2-pal/concurrency-sync/src/rwlock.rs @@ -26,15 +26,15 @@ pub struct RwLockReaderPreference { impl Default for RwLockReaderPreference { fn default() -> Self { - Self { - reader_count: AtomicU32::new(UNLOCKED), - } + Self::new() } } impl RwLockReaderPreference { - pub fn new() -> Self { - Self::default() + pub const fn new() -> Self { + Self { + reader_count: AtomicU32::new(UNLOCKED), + } } pub fn try_read_lock(&self) -> WaitResult { From a56db0eabc808fd10972c5a4d6740183d21cec79 Mon Sep 17 00:00:00 2001 From: Christian Eltzschig Date: Mon, 22 Apr 2024 11:24:53 +0200 Subject: [PATCH 2/7] [#200] Add missing atomic functionality --- iceoryx2-pal/concurrency-sync/src/atomic.rs | 79 ++++++++++++++++++--- 1 file changed, 69 insertions(+), 10 deletions(-) diff --git a/iceoryx2-pal/concurrency-sync/src/atomic.rs b/iceoryx2-pal/concurrency-sync/src/atomic.rs index 3fe9fe0fc..11b1eeef5 100644 --- a/iceoryx2-pal/concurrency-sync/src/atomic.rs +++ b/iceoryx2-pal/concurrency-sync/src/atomic.rs @@ -12,7 +12,7 @@ use core::{ cell::UnsafeCell, - ops::{AddAssign, SubAssign}, + ops::{AddAssign, BitAndAssign, BitOrAssign, BitXorAssign, Not, SubAssign}, sync::atomic::Ordering, }; @@ -48,7 +48,19 @@ pub struct IceAtomic { lock: LockType, } -impl IceAtomic { +impl< + T: Copy + + Send + + Eq + + AddAssign + + SubAssign + + BitAndAssign + + BitOrAssign + + BitXorAssign + + Ord + + Not, + > IceAtomic +{ pub fn new(v: T) -> Self { Self { data: UnsafeCell::new(v), @@ -69,6 +81,10 @@ impl IceAtomic { self.lock.unlock(|_| {}, |_| {}); } + pub const fn as_ptr(&self) -> *mut T { + self.data.get() + } + pub fn compare_exchange( &self, current: T, @@ -100,22 +116,65 @@ impl IceAtomic { self.compare_exchange(current, new, success, failure) } - pub fn fetch_add(&self, value: T, order: Ordering) -> T { + fn fetch_op(&self, op: F, order: Ordering) -> T { self.write_lock(); let data = unsafe { *self.data.get() }; - unsafe { *self.data.get() += value }; + op(); core::sync::atomic::fence(order); self.unlock(); data } + pub fn fetch_add(&self, value: T, order: Ordering) -> T { + self.fetch_op(|| unsafe { *self.data.get() += value }, order) + } + + pub fn fetch_and(&self, value: T, order: Ordering) -> T { + self.fetch_op(|| unsafe { *self.data.get() &= value }, order) + } + + pub fn fetch_max(&self, value: T, order: Ordering) -> T { + self.fetch_op( + || { + let data = unsafe { *self.data.get() }; + unsafe { *self.data.get() = data.max(value) } + }, + order, + ) + } + + pub fn fetch_min(&self, value: T, order: Ordering) -> T { + self.fetch_op( + || { + let data = unsafe { *self.data.get() }; + unsafe { *self.data.get() = data.min(value) } + }, + order, + ) + } + + pub fn fetch_nand(&self, value: T, order: Ordering) -> T { + self.fetch_op(|| unsafe { *self.data.get() &= !value }, order) + } + + pub fn fetch_or(&self, value: T, order: Ordering) -> T { + self.fetch_op(|| unsafe { *self.data.get() |= value }, order) + } + pub fn fetch_sub(&self, value: T, order: Ordering) -> T { - self.write_lock(); - let data = unsafe { *self.data.get() }; - unsafe { *self.data.get() -= value }; - core::sync::atomic::fence(order); - self.unlock(); - data + self.fetch_op(|| unsafe { *self.data.get() -= value }, order) + } + + pub fn fetch_update(&self, value: T, order: Ordering) -> T { + self.fetch_op(|| unsafe { *self.data.get() = value }, order) + } + + pub fn fetch_xor(&self, value: T, order: Ordering) -> T { + self.fetch_op(|| unsafe { *self.data.get() ^= value }, order) + } + + pub fn into_innter(self) -> T { + unsafe { *self.data.get() } } pub fn load(&self, order: Ordering) -> T { From aebf41dad8f449c784193fb6d55fee225a112efa Mon Sep 17 00:00:00 2001 From: Christian Eltzschig Date: Mon, 22 Apr 2024 13:02:42 +0200 Subject: [PATCH 3/7] [#200] Test ice atomic --- iceoryx2-pal/concurrency-sync/Cargo.toml | 1 + iceoryx2-pal/concurrency-sync/src/atomic.rs | 203 ------------ .../concurrency-sync/src/ice_atomic.rs | 301 ++++++++++++++++++ iceoryx2-pal/concurrency-sync/src/lib.rs | 2 +- .../tests/ice_atomic_tests.rs | 294 +++++++++++++++++ 5 files changed, 597 insertions(+), 204 deletions(-) delete mode 100644 iceoryx2-pal/concurrency-sync/src/atomic.rs create mode 100644 iceoryx2-pal/concurrency-sync/src/ice_atomic.rs create mode 100644 iceoryx2-pal/concurrency-sync/tests/ice_atomic_tests.rs diff --git a/iceoryx2-pal/concurrency-sync/Cargo.toml b/iceoryx2-pal/concurrency-sync/Cargo.toml index d0adb5c7a..0b68516a7 100644 --- a/iceoryx2-pal/concurrency-sync/Cargo.toml +++ b/iceoryx2-pal/concurrency-sync/Cargo.toml @@ -14,3 +14,4 @@ version = { workspace = true } [dev-dependencies] iceoryx2-bb-testing = { workspace = true } +generic-tests = { workspace = true } diff --git a/iceoryx2-pal/concurrency-sync/src/atomic.rs b/iceoryx2-pal/concurrency-sync/src/atomic.rs deleted file mode 100644 index 11b1eeef5..000000000 --- a/iceoryx2-pal/concurrency-sync/src/atomic.rs +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright (c) 2024 Contributors to the Eclipse Foundation -// -// See the NOTICE file(s) distributed with this work for additional -// information regarding copyright ownership. -// -// This program and the accompanying materials are made available under the -// terms of the Apache Software License 2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license -// which is available at https://opensource.org/licenses/MIT. -// -// SPDX-License-Identifier: Apache-2.0 OR MIT - -use core::{ - cell::UnsafeCell, - ops::{AddAssign, BitAndAssign, BitOrAssign, BitXorAssign, Not, SubAssign}, - sync::atomic::Ordering, -}; - -use crate::{rwlock::RwLockWriterPreference, WaitAction}; - -pub type IceAtomicBool = core::sync::atomic::AtomicBool; -pub type IceAtomicUsize = core::sync::atomic::AtomicUsize; - -pub type IceAtomicU8 = core::sync::atomic::AtomicU8; -pub type IceAtomicU16 = core::sync::atomic::AtomicU16; -pub type IceAtomicU32 = core::sync::atomic::AtomicU32; -pub type IceAtomicI8 = core::sync::atomic::AtomicI8; -pub type IceAtomicI16 = core::sync::atomic::AtomicI16; -pub type IceAtomicI32 = core::sync::atomic::AtomicI32; - -#[cfg(target_pointer_width = "64")] -pub type IceAtomicI64 = core::sync::atomic::AtomicI64; - -#[cfg(target_pointer_width = "64")] -pub type IceAtomicU64 = core::sync::atomic::AtomicU64; - -#[cfg(target_pointer_width = "32")] -pub type IceAtomicI64 = IceAtomic; - -#[cfg(target_pointer_width = "32")] -pub type IceAtomicU64 = IceAtomic; - -type LockType = RwLockWriterPreference; - -#[repr(C)] -pub struct IceAtomic { - data: UnsafeCell, - lock: LockType, -} - -impl< - T: Copy - + Send - + Eq - + AddAssign - + SubAssign - + BitAndAssign - + BitOrAssign - + BitXorAssign - + Ord - + Not, - > IceAtomic -{ - pub fn new(v: T) -> Self { - Self { - data: UnsafeCell::new(v), - lock: LockType::new(), - } - } - - fn read_lock(&self) { - self.lock.read_lock(|_, _| WaitAction::Continue); - } - - fn write_lock(&self) { - self.lock - .write_lock(|_, _| WaitAction::Continue, |_| {}, |_| {}); - } - - fn unlock(&self) { - self.lock.unlock(|_| {}, |_| {}); - } - - pub const fn as_ptr(&self) -> *mut T { - self.data.get() - } - - pub fn compare_exchange( - &self, - current: T, - new: T, - success: Ordering, - failure: Ordering, - ) -> Result { - self.write_lock(); - let data = unsafe { *self.data.get() }; - if data != current { - core::sync::atomic::fence(failure); - self.unlock(); - return Err(data); - } - - unsafe { *self.data.get() = new }; - core::sync::atomic::fence(success); - self.unlock(); - Ok(data) - } - - pub fn compare_exchange_weak( - &self, - current: T, - new: T, - success: Ordering, - failure: Ordering, - ) -> Result { - self.compare_exchange(current, new, success, failure) - } - - fn fetch_op(&self, op: F, order: Ordering) -> T { - self.write_lock(); - let data = unsafe { *self.data.get() }; - op(); - core::sync::atomic::fence(order); - self.unlock(); - data - } - - pub fn fetch_add(&self, value: T, order: Ordering) -> T { - self.fetch_op(|| unsafe { *self.data.get() += value }, order) - } - - pub fn fetch_and(&self, value: T, order: Ordering) -> T { - self.fetch_op(|| unsafe { *self.data.get() &= value }, order) - } - - pub fn fetch_max(&self, value: T, order: Ordering) -> T { - self.fetch_op( - || { - let data = unsafe { *self.data.get() }; - unsafe { *self.data.get() = data.max(value) } - }, - order, - ) - } - - pub fn fetch_min(&self, value: T, order: Ordering) -> T { - self.fetch_op( - || { - let data = unsafe { *self.data.get() }; - unsafe { *self.data.get() = data.min(value) } - }, - order, - ) - } - - pub fn fetch_nand(&self, value: T, order: Ordering) -> T { - self.fetch_op(|| unsafe { *self.data.get() &= !value }, order) - } - - pub fn fetch_or(&self, value: T, order: Ordering) -> T { - self.fetch_op(|| unsafe { *self.data.get() |= value }, order) - } - - pub fn fetch_sub(&self, value: T, order: Ordering) -> T { - self.fetch_op(|| unsafe { *self.data.get() -= value }, order) - } - - pub fn fetch_update(&self, value: T, order: Ordering) -> T { - self.fetch_op(|| unsafe { *self.data.get() = value }, order) - } - - pub fn fetch_xor(&self, value: T, order: Ordering) -> T { - self.fetch_op(|| unsafe { *self.data.get() ^= value }, order) - } - - pub fn into_innter(self) -> T { - unsafe { *self.data.get() } - } - - pub fn load(&self, order: Ordering) -> T { - self.read_lock(); - let data = unsafe { *self.data.get() }; - core::sync::atomic::fence(order); - self.unlock(); - data - } - - pub fn store(&self, value: T, order: Ordering) { - self.write_lock(); - unsafe { *self.data.get() = value }; - core::sync::atomic::fence(order); - self.unlock(); - } - - pub fn swap(&self, value: T, order: Ordering) -> T { - self.write_lock(); - let data = unsafe { *self.data.get() }; - unsafe { *self.data.get() = value }; - core::sync::atomic::fence(order); - self.unlock(); - data - } -} diff --git a/iceoryx2-pal/concurrency-sync/src/ice_atomic.rs b/iceoryx2-pal/concurrency-sync/src/ice_atomic.rs new file mode 100644 index 000000000..e88db2510 --- /dev/null +++ b/iceoryx2-pal/concurrency-sync/src/ice_atomic.rs @@ -0,0 +1,301 @@ +// Copyright (c) 2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache Software License 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license +// which is available at https://opensource.org/licenses/MIT. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT + +use core::{ + cell::UnsafeCell, + ops::{AddAssign, BitAndAssign, BitOrAssign, BitXorAssign, Not, SubAssign}, + sync::atomic::Ordering, +}; + +use crate::{rwlock::RwLockWriterPreference, WaitAction}; + +pub type IceAtomicBool = core::sync::atomic::AtomicBool; +pub type IceAtomicUsize = core::sync::atomic::AtomicUsize; + +pub type IceAtomicU8 = core::sync::atomic::AtomicU8; +pub type IceAtomicU16 = core::sync::atomic::AtomicU16; +pub type IceAtomicU32 = core::sync::atomic::AtomicU32; +pub type IceAtomicI8 = core::sync::atomic::AtomicI8; +pub type IceAtomicI16 = core::sync::atomic::AtomicI16; +pub type IceAtomicI32 = core::sync::atomic::AtomicI32; + +#[cfg(target_pointer_width = "64")] +pub type IceAtomicI64 = core::sync::atomic::AtomicI64; + +#[cfg(target_pointer_width = "64")] +pub type IceAtomicU64 = core::sync::atomic::AtomicU64; + +#[cfg(target_pointer_width = "32")] +pub type IceAtomicI64 = IceAtomic; + +#[cfg(target_pointer_width = "32")] +pub type IceAtomicU64 = IceAtomic; + +type LockType = RwLockWriterPreference; + +pub mod internal { + use super::*; + + pub trait AtomicInteger: + Copy + + Send + + Eq + + AddAssign + + SubAssign + + BitAndAssign + + BitOrAssign + + BitXorAssign + + Ord + + Not + { + fn overflowing_add(self, rhs: Self) -> (Self, bool); + fn overflowing_sub(self, rhs: Self) -> (Self, bool); + } + + impl AtomicInteger for u64 { + fn overflowing_add(self, rhs: Self) -> (Self, bool) { + self.overflowing_add(rhs) + } + + fn overflowing_sub(self, rhs: Self) -> (Self, bool) { + self.overflowing_sub(rhs) + } + } + + impl AtomicInteger for u128 { + fn overflowing_add(self, rhs: Self) -> (Self, bool) { + self.overflowing_add(rhs) + } + + fn overflowing_sub(self, rhs: Self) -> (Self, bool) { + self.overflowing_sub(rhs) + } + } + + impl AtomicInteger for i64 { + fn overflowing_add(self, rhs: Self) -> (Self, bool) { + self.overflowing_add(rhs) + } + + fn overflowing_sub(self, rhs: Self) -> (Self, bool) { + self.overflowing_sub(rhs) + } + } + + impl AtomicInteger for i128 { + fn overflowing_add(self, rhs: Self) -> (Self, bool) { + self.overflowing_add(rhs) + } + + fn overflowing_sub(self, rhs: Self) -> (Self, bool) { + self.overflowing_sub(rhs) + } + } +} + +#[repr(C)] +pub struct IceAtomic { + data: UnsafeCell, + lock: LockType, +} + +impl IceAtomic { + pub fn new(v: T) -> Self { + Self { + data: UnsafeCell::new(v), + lock: LockType::new(), + } + } + + fn read_lock(&self) { + self.lock.read_lock(|_, _| WaitAction::Continue); + } + + fn write_lock(&self) { + self.lock + .write_lock(|_, _| WaitAction::Continue, |_| {}, |_| {}); + } + + fn unlock(&self) { + self.lock.unlock(|_| {}, |_| {}); + } + + pub const fn as_ptr(&self) -> *mut T { + self.data.get() + } + + pub fn compare_exchange( + &self, + current: T, + new: T, + _success: Ordering, + _failure: Ordering, + ) -> Result { + self.write_lock(); + let data = unsafe { *self.data.get() }; + if data != current { + core::sync::atomic::fence(Ordering::SeqCst); + self.unlock(); + return Err(data); + } + + unsafe { *self.data.get() = new }; + core::sync::atomic::fence(Ordering::SeqCst); + self.unlock(); + Ok(data) + } + + pub fn compare_exchange_weak( + &self, + current: T, + new: T, + success: Ordering, + failure: Ordering, + ) -> Result { + self.compare_exchange(current, new, success, failure) + } + + fn fetch_op T>(&self, op: F, _order: Ordering) -> T { + self.write_lock(); + let data = op(); + core::sync::atomic::fence(Ordering::SeqCst); + self.unlock(); + data + } + + pub fn fetch_add(&self, value: T, order: Ordering) -> T { + self.fetch_op( + || { + let old = unsafe { *self.data.get() }; + unsafe { *self.data.get() = old.overflowing_add(value).0 }; + old + }, + order, + ) + } + + pub fn fetch_and(&self, value: T, order: Ordering) -> T { + self.fetch_op( + || { + let old = unsafe { *self.data.get() }; + unsafe { *self.data.get() &= value }; + old + }, + order, + ) + } + + pub fn fetch_max(&self, value: T, order: Ordering) -> T { + self.fetch_op( + || { + let old = unsafe { *self.data.get() }; + unsafe { *self.data.get() = old.max(value) }; + old + }, + order, + ) + } + + pub fn fetch_min(&self, value: T, order: Ordering) -> T { + self.fetch_op( + || { + let old = unsafe { *self.data.get() }; + unsafe { *self.data.get() = old.min(value) }; + old + }, + order, + ) + } + + pub fn fetch_nand(&self, value: T, order: Ordering) -> T { + self.fetch_op( + || { + let old = unsafe { *self.data.get() }; + unsafe { *self.data.get() &= !value }; + old + }, + order, + ) + } + + pub fn fetch_or(&self, value: T, order: Ordering) -> T { + self.fetch_op( + || { + let old = unsafe { *self.data.get() }; + unsafe { *self.data.get() |= value }; + old + }, + order, + ) + } + + pub fn fetch_sub(&self, value: T, order: Ordering) -> T { + self.fetch_op( + || { + let old = unsafe { *self.data.get() }; + unsafe { *self.data.get() = old.overflowing_sub(value).0 }; + old + }, + order, + ) + } + + pub fn fetch_update(&self, value: T, order: Ordering) -> T { + self.fetch_op( + || { + let old = unsafe { *self.data.get() }; + unsafe { *self.data.get() = value }; + old + }, + order, + ) + } + + pub fn fetch_xor(&self, value: T, order: Ordering) -> T { + self.fetch_op( + || { + let old = unsafe { *self.data.get() }; + unsafe { *self.data.get() ^= value }; + old + }, + order, + ) + } + + pub fn into_inner(self) -> T { + unsafe { *self.data.get() } + } + + pub fn load(&self, _order: Ordering) -> T { + self.read_lock(); + let data = unsafe { *self.data.get() }; + core::sync::atomic::fence(Ordering::SeqCst); + self.unlock(); + data + } + + pub fn store(&self, value: T, _order: Ordering) { + self.write_lock(); + unsafe { *self.data.get() = value }; + core::sync::atomic::fence(Ordering::SeqCst); + self.unlock(); + } + + pub fn swap(&self, value: T, _order: Ordering) -> T { + self.write_lock(); + let data = unsafe { *self.data.get() }; + unsafe { *self.data.get() = value }; + core::sync::atomic::fence(Ordering::SeqCst); + self.unlock(); + data + } +} diff --git a/iceoryx2-pal/concurrency-sync/src/lib.rs b/iceoryx2-pal/concurrency-sync/src/lib.rs index 74b6a5bac..678744655 100644 --- a/iceoryx2-pal/concurrency-sync/src/lib.rs +++ b/iceoryx2-pal/concurrency-sync/src/lib.rs @@ -14,9 +14,9 @@ const SPIN_REPETITIONS: u64 = 10000; -pub mod atomic; pub mod barrier; pub mod condition_variable; +pub mod ice_atomic; pub mod mutex; pub mod rwlock; pub mod semaphore; diff --git a/iceoryx2-pal/concurrency-sync/tests/ice_atomic_tests.rs b/iceoryx2-pal/concurrency-sync/tests/ice_atomic_tests.rs new file mode 100644 index 000000000..ecbea44d7 --- /dev/null +++ b/iceoryx2-pal/concurrency-sync/tests/ice_atomic_tests.rs @@ -0,0 +1,294 @@ +// Copyright (c) 2023 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache Software License 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license +// which is available at https://opensource.org/licenses/MIT. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT + +use std::sync::atomic::AtomicU32; + +static COUNTER: AtomicU32 = AtomicU32::new(0); + +#[generic_tests::define] +mod ice_atomic { + use super::*; + + use iceoryx2_bb_testing::assert_that; + use iceoryx2_pal_concurrency_sync::ice_atomic::{internal::AtomicInteger, IceAtomic}; + use std::{ + fmt::Debug, + ops::{BitAnd, BitOr}, + sync::atomic::Ordering, + }; + + trait Req: AtomicInteger + Debug + BitOr + BitAnd { + fn generate_value() -> Self; + } + + impl Req for u64 { + fn generate_value() -> Self { + 0x0000f0f0f0f0 + COUNTER.fetch_add(1, Ordering::Relaxed) as u64 + } + } + + impl Req for u128 { + fn generate_value() -> Self { + 0x00000f0f0f0f0f0f0f0f0f0f + COUNTER.fetch_add(1, Ordering::Relaxed) as u128 + } + } + + impl Req for i64 { + fn generate_value() -> Self { + (0x0000abcdabcdabcd + COUNTER.fetch_add(1, Ordering::Relaxed) as i64) + * (-1 as i64).pow(COUNTER.load(Ordering::Relaxed)) + } + } + + impl Req for i128 { + fn generate_value() -> Self { + (0x0000abcdabcdabcddeadbeef + COUNTER.fetch_add(1, Ordering::Relaxed) as i128) + * (-1 as i128).pow(COUNTER.load(Ordering::Relaxed)) + } + } + + #[test] + fn new_works() { + let n = T::generate_value(); + let sut = IceAtomic::::new(n); + + assert_that!(sut.load(Ordering::Relaxed), eq n); + } + + #[test] + fn as_ptr_works() { + let n1 = T::generate_value(); + let n2 = T::generate_value(); + + let sut = IceAtomic::::new(n1); + let old_value = unsafe { *sut.as_ptr() }; + unsafe { *sut.as_ptr() = n2 }; + + assert_that!(old_value, eq n1); + assert_that!(unsafe{*sut.as_ptr()}, eq n2); + assert_that!(sut.load(Ordering::Relaxed), eq n2); + } + + #[test] + fn compare_exchange_success_works() { + let n_old = T::generate_value(); + let n_new = T::generate_value(); + let sut = IceAtomic::::new(n_old); + + let result = sut.compare_exchange(n_old, n_new, Ordering::Relaxed, Ordering::Relaxed); + + assert_that!(result, is_ok); + assert_that!(result.unwrap(), eq n_old); + } + + #[test] + fn compare_exchange_weak_success_works() { + let n_old = T::generate_value(); + let n_new = T::generate_value(); + let sut = IceAtomic::::new(n_old); + + let result = sut.compare_exchange_weak(n_old, n_new, Ordering::Relaxed, Ordering::Relaxed); + + assert_that!(result, is_ok); + assert_that!(result.unwrap(), eq n_old); + } + + #[test] + fn compare_exchange_failure_works() { + let n_old = T::generate_value(); + let n_new = T::generate_value(); + let sut = IceAtomic::::new(n_old); + + let result = sut.compare_exchange(n_new, n_old, Ordering::Relaxed, Ordering::Relaxed); + + assert_that!(result, is_err); + assert_that!(result.err().unwrap(), eq n_old); + } + + #[test] + fn compare_exchange_weak_failure_works() { + let n_old = T::generate_value(); + let n_new = T::generate_value(); + let sut = IceAtomic::::new(n_old); + + let result = sut.compare_exchange(n_new, n_old, Ordering::Relaxed, Ordering::Relaxed); + + assert_that!(result, is_err); + assert_that!(result.err().unwrap(), eq n_old); + } + + #[test] + fn fetch_add_works() { + let n = T::generate_value(); + let sut = IceAtomic::::new(n); + + let result = sut.fetch_add(n, Ordering::Relaxed); + + assert_that!(result, eq n); + assert_that!(sut.load(Ordering::Relaxed), eq n.overflowing_add(n).0); + } + + #[test] + fn fetch_and_works() { + let n1 = T::generate_value(); + let n2 = T::generate_value(); + + let sut = IceAtomic::::new(n1); + + let result = sut.fetch_and(n2, Ordering::Relaxed); + + assert_that!(result, eq n1); + let mut bit_and = n1; + bit_and &= n2; + assert_that!(sut.load(Ordering::Relaxed), eq bit_and); + } + + #[test] + fn fetch_max_works() { + let n1 = T::generate_value(); + let n2 = T::generate_value(); + + let sut = IceAtomic::::new(n1); + + let result = sut.fetch_max(n2, Ordering::Relaxed); + + assert_that!(result, eq n1); + assert_that!(sut.load(Ordering::Relaxed), eq n1.max(n2)); + } + + #[test] + fn fetch_min_works() { + let n1 = T::generate_value(); + let n2 = T::generate_value(); + + let sut = IceAtomic::::new(n1); + + let result = sut.fetch_min(n2, Ordering::Relaxed); + + assert_that!(result, eq n1); + assert_that!(sut.load(Ordering::Relaxed), eq n1.min(n2)); + } + + #[test] + fn fetch_nand_works() { + let n1 = T::generate_value(); + let n2 = T::generate_value(); + + let sut = IceAtomic::::new(n1); + + let result = sut.fetch_nand(n2, Ordering::Relaxed); + + assert_that!(result, eq n1); + let mut bit_nand = n1; + bit_nand &= !n2; + assert_that!(sut.load(Ordering::Relaxed), eq bit_nand); + } + + #[test] + fn fetch_or_works() { + let n1 = T::generate_value(); + let n2 = T::generate_value(); + + let sut = IceAtomic::::new(n1); + + let result = sut.fetch_or(n2, Ordering::Relaxed); + + assert_that!(result, eq n1); + let mut bit_or = n1; + bit_or |= n2; + assert_that!(sut.load(Ordering::Relaxed), eq bit_or); + } + + #[test] + fn fetch_sub_works() { + let n1 = T::generate_value(); + let n2 = T::generate_value(); + + let sut = IceAtomic::::new(n1); + + let result = sut.fetch_sub(n2, Ordering::Relaxed); + + assert_that!(result, eq n1); + assert_that!(sut.load(Ordering::Relaxed), eq n1.overflowing_sub(n2).0); + } + + #[test] + fn fetch_update_works() { + let n1 = T::generate_value(); + let n2 = T::generate_value(); + + let sut = IceAtomic::::new(n1); + + let result = sut.fetch_update(n2, Ordering::Relaxed); + + assert_that!(result, eq n1); + assert_that!(sut.load(Ordering::Relaxed), eq n2); + } + + #[test] + fn fetch_xor_works() { + let n1 = T::generate_value(); + let n2 = T::generate_value(); + + let sut = IceAtomic::::new(n1); + + let result = sut.fetch_xor(n2, Ordering::Relaxed); + + assert_that!(result, eq n1); + let mut bit_xor = n1; + bit_xor ^= n2; + assert_that!(sut.load(Ordering::Relaxed), eq bit_xor); + } + + #[test] + fn into_inner_works() { + let n = T::generate_value(); + let sut = IceAtomic::::new(n); + + assert_that!(IceAtomic::::into_inner(sut), eq n); + } + + #[test] + fn load_store_works() { + let n1 = T::generate_value(); + let n2 = T::generate_value(); + let sut = IceAtomic::::new(n1); + + sut.store(n2, Ordering::Relaxed); + + assert_that!(sut.load(Ordering::Relaxed), eq n2); + } + + #[test] + fn swap_works() { + let n1 = T::generate_value(); + let n2 = T::generate_value(); + let sut = IceAtomic::::new(n1); + + let result = sut.swap(n2, Ordering::Relaxed); + + assert_that!(result, eq n1); + assert_that!(sut.load(Ordering::Relaxed), eq n2); + } + + #[instantiate_tests()] + mod u64 {} + + #[instantiate_tests()] + mod u128 {} + + #[instantiate_tests()] + mod i64 {} + + #[instantiate_tests()] + mod i128 {} +} From 085535a8665461dc8804564d0ee960d8849f7577 Mon Sep 17 00:00:00 2001 From: Christian Eltzschig Date: Mon, 22 Apr 2024 14:04:39 +0200 Subject: [PATCH 4/7] [#200] Add compatibility checks --- .../concurrency-sync/src/ice_atomic.rs | 75 +++- .../tests/ice_atomic_tests.rs | 341 +++++++++++++++++- 2 files changed, 398 insertions(+), 18 deletions(-) diff --git a/iceoryx2-pal/concurrency-sync/src/ice_atomic.rs b/iceoryx2-pal/concurrency-sync/src/ice_atomic.rs index e88db2510..575de8480 100644 --- a/iceoryx2-pal/concurrency-sync/src/ice_atomic.rs +++ b/iceoryx2-pal/concurrency-sync/src/ice_atomic.rs @@ -18,31 +18,52 @@ use core::{ use crate::{rwlock::RwLockWriterPreference, WaitAction}; +/// Behaves like [`core::sync::atomic::AtomicBool`] pub type IceAtomicBool = core::sync::atomic::AtomicBool; + +/// Behaves like [`core::sync::atomic::AtomicUsize`] pub type IceAtomicUsize = core::sync::atomic::AtomicUsize; +/// Behaves like [`core::sync::atomic::AtomicU8`] pub type IceAtomicU8 = core::sync::atomic::AtomicU8; + +/// Behaves like [`core::sync::atomic::AtomicU16`] pub type IceAtomicU16 = core::sync::atomic::AtomicU16; + +/// Behaves like [`core::sync::atomic::AtomicU32`] pub type IceAtomicU32 = core::sync::atomic::AtomicU32; + +/// Behaves like [`core::sync::atomic::AtomicI8`] pub type IceAtomicI8 = core::sync::atomic::AtomicI8; + +/// Behaves like [`core::sync::atomic::AtomicI16`] pub type IceAtomicI16 = core::sync::atomic::AtomicI16; + +/// Behaves like [`core::sync::atomic::AtomicI32`] pub type IceAtomicI32 = core::sync::atomic::AtomicI32; #[cfg(target_pointer_width = "64")] +/// Behaves like [`core::sync::atomic::AtomicI64`] pub type IceAtomicI64 = core::sync::atomic::AtomicI64; #[cfg(target_pointer_width = "64")] +/// Behaves like [`core::sync::atomic::AtomicU64`] pub type IceAtomicU64 = core::sync::atomic::AtomicU64; #[cfg(target_pointer_width = "32")] +/// Non lock-free implementation that behaves like [`core::sync::atomic::AtomicI64`] pub type IceAtomicI64 = IceAtomic; #[cfg(target_pointer_width = "32")] +/// Non lock-free implementation that behaves like [`core::sync::atomic::AtomicU64`] pub type IceAtomicU64 = IceAtomic; type LockType = RwLockWriterPreference; +#[doc(hidden)] pub mod internal { + use core::ops::BitAnd; + use super::*; pub trait AtomicInteger: @@ -54,6 +75,7 @@ pub mod internal { + BitAndAssign + BitOrAssign + BitXorAssign + + BitAnd + Ord + Not { @@ -102,6 +124,9 @@ pub mod internal { } } +/// iceoryx2 implementation of an atomic that has an internal [`RwLockWriterPreference`]. +/// It enables atomic operations on platforms that do not support them with the restriction that +/// those operations are no longer lock-free. #[repr(C)] pub struct IceAtomic { data: UnsafeCell, @@ -109,6 +134,7 @@ pub struct IceAtomic { } impl IceAtomic { + /// See [`core::sync::atomic::AtomicU64::new()`] pub fn new(v: T) -> Self { Self { data: UnsafeCell::new(v), @@ -129,10 +155,12 @@ impl IceAtomic { self.lock.unlock(|_| {}, |_| {}); } + /// See [`core::sync::atomic::AtomicU64::as_ptr()`] pub const fn as_ptr(&self) -> *mut T { self.data.get() } + /// See [`core::sync::atomic::AtomicU64::compare_exchange()`] pub fn compare_exchange( &self, current: T, @@ -154,6 +182,7 @@ impl IceAtomic { Ok(data) } + /// See [`core::sync::atomic::AtomicU64::compare_exchange_weak()`] pub fn compare_exchange_weak( &self, current: T, @@ -172,6 +201,7 @@ impl IceAtomic { data } + /// See [`core::sync::atomic::AtomicU64::fetch_add()`] pub fn fetch_add(&self, value: T, order: Ordering) -> T { self.fetch_op( || { @@ -183,6 +213,7 @@ impl IceAtomic { ) } + /// See [`core::sync::atomic::AtomicU64::fetch_and()`] pub fn fetch_and(&self, value: T, order: Ordering) -> T { self.fetch_op( || { @@ -194,6 +225,7 @@ impl IceAtomic { ) } + /// See [`core::sync::atomic::AtomicU64::fetch_max()`] pub fn fetch_max(&self, value: T, order: Ordering) -> T { self.fetch_op( || { @@ -205,6 +237,7 @@ impl IceAtomic { ) } + /// See [`core::sync::atomic::AtomicU64::fetch_min()`] pub fn fetch_min(&self, value: T, order: Ordering) -> T { self.fetch_op( || { @@ -216,17 +249,19 @@ impl IceAtomic { ) } + /// See [`core::sync::atomic::AtomicU64::fetch_nand()`] pub fn fetch_nand(&self, value: T, order: Ordering) -> T { self.fetch_op( || { let old = unsafe { *self.data.get() }; - unsafe { *self.data.get() &= !value }; + unsafe { *self.data.get() = !(old & value) }; old }, order, ) } + /// See [`core::sync::atomic::AtomicU64::fetch_or()`] pub fn fetch_or(&self, value: T, order: Ordering) -> T { self.fetch_op( || { @@ -238,6 +273,7 @@ impl IceAtomic { ) } + /// See [`core::sync::atomic::AtomicU64::fetch_sub()`] pub fn fetch_sub(&self, value: T, order: Ordering) -> T { self.fetch_op( || { @@ -249,17 +285,32 @@ impl IceAtomic { ) } - pub fn fetch_update(&self, value: T, order: Ordering) -> T { - self.fetch_op( - || { - let old = unsafe { *self.data.get() }; - unsafe { *self.data.get() = value }; - old - }, - order, - ) + /// See [`core::sync::atomic::AtomicU64::fetch_update()`] + pub fn fetch_update Option>( + &self, + _set_order: Ordering, + _fetch_order: Ordering, + mut f: F, + ) -> Result { + self.write_lock(); + let data = unsafe { *self.data.get() }; + + match f(data) { + Some(v) => { + unsafe { *self.data.get() = v }; + core::sync::atomic::fence(Ordering::SeqCst); + self.unlock(); + Ok(data) + } + None => { + core::sync::atomic::fence(Ordering::SeqCst); + self.unlock(); + Err(data) + } + } } + /// See [`core::sync::atomic::AtomicU64::fetch_xor()`] pub fn fetch_xor(&self, value: T, order: Ordering) -> T { self.fetch_op( || { @@ -271,10 +322,12 @@ impl IceAtomic { ) } + /// See [`core::sync::atomic::AtomicU64::into_inner()`] pub fn into_inner(self) -> T { unsafe { *self.data.get() } } + /// See [`core::sync::atomic::AtomicU64::load()`] pub fn load(&self, _order: Ordering) -> T { self.read_lock(); let data = unsafe { *self.data.get() }; @@ -283,6 +336,7 @@ impl IceAtomic { data } + /// See [`core::sync::atomic::AtomicU64::store()`] pub fn store(&self, value: T, _order: Ordering) { self.write_lock(); unsafe { *self.data.get() = value }; @@ -290,6 +344,7 @@ impl IceAtomic { self.unlock(); } + /// See [`core::sync::atomic::AtomicU64::swap()`] pub fn swap(&self, value: T, _order: Ordering) -> T { self.write_lock(); let data = unsafe { *self.data.get() }; diff --git a/iceoryx2-pal/concurrency-sync/tests/ice_atomic_tests.rs b/iceoryx2-pal/concurrency-sync/tests/ice_atomic_tests.rs index ecbea44d7..0faa3f0b7 100644 --- a/iceoryx2-pal/concurrency-sync/tests/ice_atomic_tests.rs +++ b/iceoryx2-pal/concurrency-sync/tests/ice_atomic_tests.rs @@ -22,38 +22,72 @@ mod ice_atomic { use iceoryx2_pal_concurrency_sync::ice_atomic::{internal::AtomicInteger, IceAtomic}; use std::{ fmt::Debug, - ops::{BitAnd, BitOr}, + ops::{AddAssign, BitAnd, BitOr}, sync::atomic::Ordering, }; trait Req: AtomicInteger + Debug + BitOr + BitAnd { fn generate_value() -> Self; + fn generate_compatibility_value() -> Self; + fn to_u32(&self) -> u32; } impl Req for u64 { + fn to_u32(&self) -> u32 { + *self as u32 + } + fn generate_value() -> Self { 0x0000f0f0f0f0 + COUNTER.fetch_add(1, Ordering::Relaxed) as u64 } + + fn generate_compatibility_value() -> Self { + 0x00000000f0f0 + COUNTER.fetch_add(1, Ordering::Relaxed) as u64 + } } impl Req for u128 { + fn to_u32(&self) -> u32 { + *self as u32 + } + fn generate_value() -> Self { 0x00000f0f0f0f0f0f0f0f0f0f + COUNTER.fetch_add(1, Ordering::Relaxed) as u128 } + + fn generate_compatibility_value() -> Self { + 0x000000000000000000000f0f + COUNTER.fetch_add(1, Ordering::Relaxed) as u128 + } } impl Req for i64 { + fn to_u32(&self) -> u32 { + *self as u32 + } + fn generate_value() -> Self { (0x0000abcdabcdabcd + COUNTER.fetch_add(1, Ordering::Relaxed) as i64) * (-1 as i64).pow(COUNTER.load(Ordering::Relaxed)) } + + fn generate_compatibility_value() -> Self { + 0x000000000000abcd + COUNTER.fetch_add(1, Ordering::Relaxed) as i64 + } } impl Req for i128 { + fn to_u32(&self) -> u32 { + *self as u32 + } + fn generate_value() -> Self { (0x0000abcdabcdabcddeadbeef + COUNTER.fetch_add(1, Ordering::Relaxed) as i128) * (-1 as i128).pow(COUNTER.load(Ordering::Relaxed)) } + + fn generate_compatibility_value() -> Self { + 0x00000000000000000000beef + COUNTER.fetch_add(1, Ordering::Relaxed) as i128 + } } #[test] @@ -188,8 +222,7 @@ mod ice_atomic { let result = sut.fetch_nand(n2, Ordering::Relaxed); assert_that!(result, eq n1); - let mut bit_nand = n1; - bit_nand &= !n2; + let bit_nand = !(n1 & n2); assert_that!(sut.load(Ordering::Relaxed), eq bit_nand); } @@ -221,17 +254,42 @@ mod ice_atomic { assert_that!(sut.load(Ordering::Relaxed), eq n1.overflowing_sub(n2).0); } + fn ok_fetch_update(value: T) -> Option { + let mut temp = value; + temp += value; + Some(temp) + } + + fn err_fetch_update(_value: T) -> Option { + None + } + #[test] - fn fetch_update_works() { + fn fetch_update_success_works() { let n1 = T::generate_value(); - let n2 = T::generate_value(); let sut = IceAtomic::::new(n1); - let result = sut.fetch_update(n2, Ordering::Relaxed); + let result = sut.fetch_update(Ordering::Relaxed, Ordering::Relaxed, ok_fetch_update::); - assert_that!(result, eq n1); - assert_that!(sut.load(Ordering::Relaxed), eq n2); + assert_that!(result, is_ok); + assert_that!(result.unwrap(), eq n1); + let mut n = n1; + n += n1; + assert_that!(sut.load(Ordering::Relaxed), eq n); + } + + #[test] + fn fetch_update_failure_works() { + let n1 = T::generate_value(); + + let sut = IceAtomic::::new(n1); + + let result = sut.fetch_update(Ordering::Relaxed, Ordering::Relaxed, err_fetch_update::); + + assert_that!(result, is_err); + assert_that!(result.err().unwrap(), eq n1); + assert_that!(sut.load(Ordering::Relaxed), eq n1); } #[test] @@ -280,6 +338,273 @@ mod ice_atomic { assert_that!(sut.load(Ordering::Relaxed), eq n2); } + #[test] + fn compatibility_new_works() { + let n = T::generate_compatibility_value(); + let sut = IceAtomic::::new(n); + let compat = AtomicU32::new(n.to_u32()); + + assert_that!(compat.load(Ordering::Relaxed), eq sut.load(Ordering::Relaxed).to_u32()); + } + + #[test] + fn compatibility_as_ptr_works() { + let n1 = T::generate_compatibility_value(); + let n2 = T::generate_compatibility_value(); + + let sut = IceAtomic::::new(n1); + let compat = AtomicU32::new(n1.to_u32()); + + assert_that!(unsafe {*compat.as_ptr()}, eq unsafe{*sut.as_ptr()}.to_u32() ); + + unsafe { *sut.as_ptr() = n2 }; + unsafe { *compat.as_ptr() = n2.to_u32() }; + + assert_that!(unsafe {*compat.as_ptr()}, eq unsafe{*sut.as_ptr()}.to_u32() ); + assert_that!(unsafe {*compat.as_ptr()}, eq n2.to_u32() ); + } + + #[test] + fn compatibility_compare_exchange_success_works() { + let n1 = T::generate_compatibility_value(); + let n2 = T::generate_compatibility_value(); + + let sut = IceAtomic::::new(n1); + let compat = AtomicU32::new(n1.to_u32()); + + let result_sut = sut.compare_exchange(n1, n2, Ordering::Relaxed, Ordering::Relaxed); + let result_compat = compat.compare_exchange( + n1.to_u32(), + n2.to_u32(), + Ordering::Relaxed, + Ordering::Relaxed, + ); + + assert_that!(result_sut, is_ok); + assert_that!(result_compat, is_ok); + + assert_that!(result_sut.unwrap(), eq n1); + assert_that!(result_compat.unwrap(), eq n1.to_u32()); + } + + #[test] + fn compatibility_compare_exchange_weak_success_works() { + let n1 = T::generate_compatibility_value(); + let n2 = T::generate_compatibility_value(); + + let sut = IceAtomic::::new(n1); + let compat = AtomicU32::new(n1.to_u32()); + + let result_sut = sut.compare_exchange_weak(n1, n2, Ordering::Relaxed, Ordering::Relaxed); + let result_compat = compat.compare_exchange_weak( + n1.to_u32(), + n2.to_u32(), + Ordering::Relaxed, + Ordering::Relaxed, + ); + + assert_that!(result_sut, is_ok); + assert_that!(result_compat, is_ok); + + assert_that!(result_sut.unwrap(), eq n1); + assert_that!(result_compat.unwrap(), eq n1.to_u32()); + } + + #[test] + fn compatibility_compare_exchange_failure_works() { + let n1 = T::generate_compatibility_value(); + let n2 = T::generate_compatibility_value(); + + let sut = IceAtomic::::new(n1); + let compat = AtomicU32::new(n1.to_u32()); + + let result_sut = sut.compare_exchange(n2, n1, Ordering::Relaxed, Ordering::Relaxed); + let result_compat = compat.compare_exchange( + n2.to_u32(), + n1.to_u32(), + Ordering::Relaxed, + Ordering::Relaxed, + ); + + assert_that!(result_sut, is_err); + assert_that!(result_compat, is_err); + + assert_that!(result_sut.err().unwrap(), eq n1); + assert_that!(result_compat.err().unwrap(), eq n1.to_u32()); + } + + #[test] + fn compatibility_compare_exchange_weak_failure_works() { + let n1 = T::generate_compatibility_value(); + let n2 = T::generate_compatibility_value(); + + let sut = IceAtomic::::new(n1); + let compat = AtomicU32::new(n1.to_u32()); + + let result_sut = sut.compare_exchange_weak(n2, n1, Ordering::Relaxed, Ordering::Relaxed); + let result_compat = compat.compare_exchange_weak( + n2.to_u32(), + n1.to_u32(), + Ordering::Relaxed, + Ordering::Relaxed, + ); + + assert_that!(result_sut, is_err); + assert_that!(result_compat, is_err); + + assert_that!(result_sut.err().unwrap(), eq n1); + assert_that!(result_compat.err().unwrap(), eq n1.to_u32()); + } + + #[test] + fn compatibility_fetch_add_works() { + let n1 = T::generate_compatibility_value(); + let n2 = T::generate_compatibility_value(); + + let sut = IceAtomic::::new(n1); + let compat = AtomicU32::new(n1.to_u32()); + + assert_that!(sut.fetch_add(n2, Ordering::Relaxed).to_u32(), eq compat.fetch_add(n2.to_u32(), Ordering::Relaxed)); + assert_that!(sut.load(Ordering::Relaxed).to_u32(), eq compat.load(Ordering::Relaxed)); + } + + #[test] + fn compatibility_fetch_and_works() { + let n1 = T::generate_compatibility_value(); + let n2 = T::generate_compatibility_value(); + + let sut = IceAtomic::::new(n1); + let compat = AtomicU32::new(n1.to_u32()); + + assert_that!(sut.fetch_and(n2, Ordering::Relaxed).to_u32(), eq compat.fetch_and(n2.to_u32(), Ordering::Relaxed)); + assert_that!(sut.load(Ordering::Relaxed).to_u32(), eq compat.load(Ordering::Relaxed)); + } + + #[test] + fn compatibility_fetch_max_works() { + let n1 = T::generate_compatibility_value(); + let n2 = T::generate_compatibility_value(); + + let sut = IceAtomic::::new(n1); + let compat = AtomicU32::new(n1.to_u32()); + + assert_that!(sut.fetch_max(n2, Ordering::Relaxed).to_u32(), eq compat.fetch_max(n2.to_u32(), Ordering::Relaxed)); + assert_that!(sut.load(Ordering::Relaxed).to_u32(), eq compat.load(Ordering::Relaxed)); + } + + #[test] + fn compatibility_fetch_min_works() { + let n1 = T::generate_compatibility_value(); + let n2 = T::generate_compatibility_value(); + + let sut = IceAtomic::::new(n1); + let compat = AtomicU32::new(n1.to_u32()); + + assert_that!(sut.fetch_min(n2, Ordering::Relaxed).to_u32(), eq compat.fetch_min(n2.to_u32(), Ordering::Relaxed)); + assert_that!(sut.load(Ordering::Relaxed).to_u32(), eq compat.load(Ordering::Relaxed)); + } + + #[test] + fn compatibility_fetch_nand_works() { + let n1 = T::generate_compatibility_value(); + let n2 = T::generate_compatibility_value(); + + let sut = IceAtomic::::new(n1); + let compat = AtomicU32::new(n1.to_u32()); + + assert_that!(sut.fetch_nand(n2, Ordering::Relaxed).to_u32(), eq compat.fetch_nand(n2.to_u32(), Ordering::Relaxed)); + assert_that!(sut.load(Ordering::Relaxed).to_u32(), eq compat.load(Ordering::Relaxed)); + } + + #[test] + fn compatibility_fetch_or_works() { + let n1 = T::generate_compatibility_value(); + let n2 = T::generate_compatibility_value(); + + let sut = IceAtomic::::new(n1); + let compat = AtomicU32::new(n1.to_u32()); + + assert_that!(sut.fetch_or(n2, Ordering::Relaxed).to_u32(), eq compat.fetch_or(n2.to_u32(), Ordering::Relaxed)); + assert_that!(sut.load(Ordering::Relaxed).to_u32(), eq compat.load(Ordering::Relaxed)); + } + + #[test] + fn compatibility_fetch_sub_works() { + let n1 = T::generate_compatibility_value(); + let n2 = T::generate_compatibility_value(); + + let sut = IceAtomic::::new(n1); + let compat = AtomicU32::new(n1.to_u32()); + + assert_that!(sut.fetch_sub(n2, Ordering::Relaxed).to_u32(), eq compat.fetch_sub(n2.to_u32(), Ordering::Relaxed)); + assert_that!(sut.load(Ordering::Relaxed).to_u32(), eq compat.load(Ordering::Relaxed)); + } + + #[test] + fn compatibility_fetch_update_success_works() { + let n1 = T::generate_compatibility_value(); + + let sut = IceAtomic::::new(n1); + let compat = AtomicU32::new(n1.to_u32()); + + let result_sut = + sut.fetch_update(Ordering::Relaxed, Ordering::Relaxed, ok_fetch_update::); + let result_compat = + compat.fetch_update(Ordering::Relaxed, Ordering::Relaxed, ok_fetch_update::); + + assert_that!(result_sut, is_ok); + assert_that!(result_compat, is_ok); + + assert_that!(result_sut.unwrap().to_u32(), eq result_compat.unwrap()); + assert_that!(sut.load(Ordering::Relaxed).to_u32(), eq compat.load(Ordering::Relaxed)); + } + + #[test] + fn compatibility_fetch_update_failure_works() { + let n1 = T::generate_compatibility_value(); + + let sut = IceAtomic::::new(n1); + let compat = AtomicU32::new(n1.to_u32()); + + let result_sut = + sut.fetch_update(Ordering::Relaxed, Ordering::Relaxed, err_fetch_update::); + let result_compat = compat.fetch_update( + Ordering::Relaxed, + Ordering::Relaxed, + err_fetch_update::, + ); + + assert_that!(result_sut, is_err); + assert_that!(result_compat, is_err); + + assert_that!(result_sut.err().unwrap().to_u32(), eq result_compat.err().unwrap()); + assert_that!(sut.load(Ordering::Relaxed).to_u32(), eq compat.load(Ordering::Relaxed)); + } + + #[test] + fn compatibility_fetch_xor_works() { + let n1 = T::generate_compatibility_value(); + let n2 = T::generate_compatibility_value(); + + let sut = IceAtomic::::new(n1); + let compat = AtomicU32::new(n1.to_u32()); + + assert_that!(sut.fetch_xor(n2, Ordering::Relaxed).to_u32(), eq compat.fetch_xor(n2.to_u32(), Ordering::Relaxed)); + assert_that!(sut.load(Ordering::Relaxed).to_u32(), eq compat.load(Ordering::Relaxed)); + } + + #[test] + fn compatibility_swap_works() { + let n1 = T::generate_compatibility_value(); + let n2 = T::generate_compatibility_value(); + + let sut = IceAtomic::::new(n1); + let compat = AtomicU32::new(n1.to_u32()); + + assert_that!(sut.swap(n2, Ordering::Relaxed).to_u32(), eq compat.swap(n2.to_u32(), Ordering::Relaxed)); + assert_that!(sut.load(Ordering::Relaxed).to_u32(), eq compat.load(Ordering::Relaxed)); + } + #[instantiate_tests()] mod u64 {} From e1e4908ff1ed15a7b75b23927ae01ce70ca69b1a Mon Sep 17 00:00:00 2001 From: Christian Eltzschig Date: Mon, 22 Apr 2024 14:07:04 +0200 Subject: [PATCH 5/7] [#200] Add release notes --- doc/release-notes/iceoryx2-unreleased.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/release-notes/iceoryx2-unreleased.md b/doc/release-notes/iceoryx2-unreleased.md index 1f29c8db3..21cdbbeeb 100644 --- a/doc/release-notes/iceoryx2-unreleased.md +++ b/doc/release-notes/iceoryx2-unreleased.md @@ -40,6 +40,7 @@ sample.send()?; } ``` + * Introduce `IoxAtomic` that supports up to 128bit atomics on 32-bit architecture with a ReadWriteLock [#200](https://github.com/eclipse-iceoryx/iceoryx2/issues/200) * Example that demonstrates publish-subscribe communication with dynamic data [#205](https://github.com/eclipse-iceoryx/iceoryx2/issues/205) ### Bugfixes From 88c9ea7d390777021794a168d32024507457b11d Mon Sep 17 00:00:00 2001 From: Christian Eltzschig Date: Sun, 28 Apr 2024 15:00:24 +0200 Subject: [PATCH 6/7] [#200] Rename IceAtomic into IoxAtomic --- .../src/{ice_atomic.rs => iox_atomic.rs} | 28 +++---- iceoryx2-pal/concurrency-sync/src/lib.rs | 2 +- ...ce_atomic_tests.rs => iox_atomic_tests.rs} | 76 +++++++++---------- 3 files changed, 53 insertions(+), 53 deletions(-) rename iceoryx2-pal/concurrency-sync/src/{ice_atomic.rs => iox_atomic.rs} (92%) rename iceoryx2-pal/concurrency-sync/tests/{ice_atomic_tests.rs => iox_atomic_tests.rs} (91%) diff --git a/iceoryx2-pal/concurrency-sync/src/ice_atomic.rs b/iceoryx2-pal/concurrency-sync/src/iox_atomic.rs similarity index 92% rename from iceoryx2-pal/concurrency-sync/src/ice_atomic.rs rename to iceoryx2-pal/concurrency-sync/src/iox_atomic.rs index 575de8480..119e0e6cd 100644 --- a/iceoryx2-pal/concurrency-sync/src/ice_atomic.rs +++ b/iceoryx2-pal/concurrency-sync/src/iox_atomic.rs @@ -19,44 +19,44 @@ use core::{ use crate::{rwlock::RwLockWriterPreference, WaitAction}; /// Behaves like [`core::sync::atomic::AtomicBool`] -pub type IceAtomicBool = core::sync::atomic::AtomicBool; +pub type IoxAtomicBool = core::sync::atomic::AtomicBool; /// Behaves like [`core::sync::atomic::AtomicUsize`] -pub type IceAtomicUsize = core::sync::atomic::AtomicUsize; +pub type IoxAtomicUsize = core::sync::atomic::AtomicUsize; /// Behaves like [`core::sync::atomic::AtomicU8`] -pub type IceAtomicU8 = core::sync::atomic::AtomicU8; +pub type IoxAtomicU8 = core::sync::atomic::AtomicU8; /// Behaves like [`core::sync::atomic::AtomicU16`] -pub type IceAtomicU16 = core::sync::atomic::AtomicU16; +pub type IoxAtomicU16 = core::sync::atomic::AtomicU16; /// Behaves like [`core::sync::atomic::AtomicU32`] -pub type IceAtomicU32 = core::sync::atomic::AtomicU32; +pub type IoxAtomicU32 = core::sync::atomic::AtomicU32; /// Behaves like [`core::sync::atomic::AtomicI8`] -pub type IceAtomicI8 = core::sync::atomic::AtomicI8; +pub type IoxAtomicI8 = core::sync::atomic::AtomicI8; /// Behaves like [`core::sync::atomic::AtomicI16`] -pub type IceAtomicI16 = core::sync::atomic::AtomicI16; +pub type IoxAtomicI16 = core::sync::atomic::AtomicI16; /// Behaves like [`core::sync::atomic::AtomicI32`] -pub type IceAtomicI32 = core::sync::atomic::AtomicI32; +pub type IoxAtomicI32 = core::sync::atomic::AtomicI32; #[cfg(target_pointer_width = "64")] /// Behaves like [`core::sync::atomic::AtomicI64`] -pub type IceAtomicI64 = core::sync::atomic::AtomicI64; +pub type IoxAtomicI64 = core::sync::atomic::AtomicI64; #[cfg(target_pointer_width = "64")] /// Behaves like [`core::sync::atomic::AtomicU64`] -pub type IceAtomicU64 = core::sync::atomic::AtomicU64; +pub type IoxAtomicU64 = core::sync::atomic::AtomicU64; #[cfg(target_pointer_width = "32")] /// Non lock-free implementation that behaves like [`core::sync::atomic::AtomicI64`] -pub type IceAtomicI64 = IceAtomic; +pub type IoxAtomicI64 = IoxAtomic; #[cfg(target_pointer_width = "32")] /// Non lock-free implementation that behaves like [`core::sync::atomic::AtomicU64`] -pub type IceAtomicU64 = IceAtomic; +pub type IoxAtomicU64 = IoxAtomic; type LockType = RwLockWriterPreference; @@ -128,12 +128,12 @@ pub mod internal { /// It enables atomic operations on platforms that do not support them with the restriction that /// those operations are no longer lock-free. #[repr(C)] -pub struct IceAtomic { +pub struct IoxAtomic { data: UnsafeCell, lock: LockType, } -impl IceAtomic { +impl IoxAtomic { /// See [`core::sync::atomic::AtomicU64::new()`] pub fn new(v: T) -> Self { Self { diff --git a/iceoryx2-pal/concurrency-sync/src/lib.rs b/iceoryx2-pal/concurrency-sync/src/lib.rs index 678744655..a0c8e9968 100644 --- a/iceoryx2-pal/concurrency-sync/src/lib.rs +++ b/iceoryx2-pal/concurrency-sync/src/lib.rs @@ -16,7 +16,7 @@ const SPIN_REPETITIONS: u64 = 10000; pub mod barrier; pub mod condition_variable; -pub mod ice_atomic; +pub mod iox_atomic; pub mod mutex; pub mod rwlock; pub mod semaphore; diff --git a/iceoryx2-pal/concurrency-sync/tests/ice_atomic_tests.rs b/iceoryx2-pal/concurrency-sync/tests/iox_atomic_tests.rs similarity index 91% rename from iceoryx2-pal/concurrency-sync/tests/ice_atomic_tests.rs rename to iceoryx2-pal/concurrency-sync/tests/iox_atomic_tests.rs index 0faa3f0b7..5487c97fc 100644 --- a/iceoryx2-pal/concurrency-sync/tests/ice_atomic_tests.rs +++ b/iceoryx2-pal/concurrency-sync/tests/iox_atomic_tests.rs @@ -19,7 +19,7 @@ mod ice_atomic { use super::*; use iceoryx2_bb_testing::assert_that; - use iceoryx2_pal_concurrency_sync::ice_atomic::{internal::AtomicInteger, IceAtomic}; + use iceoryx2_pal_concurrency_sync::iox_atomic::{internal::AtomicInteger, IoxAtomic}; use std::{ fmt::Debug, ops::{AddAssign, BitAnd, BitOr}, @@ -93,7 +93,7 @@ mod ice_atomic { #[test] fn new_works() { let n = T::generate_value(); - let sut = IceAtomic::::new(n); + let sut = IoxAtomic::::new(n); assert_that!(sut.load(Ordering::Relaxed), eq n); } @@ -103,7 +103,7 @@ mod ice_atomic { let n1 = T::generate_value(); let n2 = T::generate_value(); - let sut = IceAtomic::::new(n1); + let sut = IoxAtomic::::new(n1); let old_value = unsafe { *sut.as_ptr() }; unsafe { *sut.as_ptr() = n2 }; @@ -116,7 +116,7 @@ mod ice_atomic { fn compare_exchange_success_works() { let n_old = T::generate_value(); let n_new = T::generate_value(); - let sut = IceAtomic::::new(n_old); + let sut = IoxAtomic::::new(n_old); let result = sut.compare_exchange(n_old, n_new, Ordering::Relaxed, Ordering::Relaxed); @@ -128,7 +128,7 @@ mod ice_atomic { fn compare_exchange_weak_success_works() { let n_old = T::generate_value(); let n_new = T::generate_value(); - let sut = IceAtomic::::new(n_old); + let sut = IoxAtomic::::new(n_old); let result = sut.compare_exchange_weak(n_old, n_new, Ordering::Relaxed, Ordering::Relaxed); @@ -140,7 +140,7 @@ mod ice_atomic { fn compare_exchange_failure_works() { let n_old = T::generate_value(); let n_new = T::generate_value(); - let sut = IceAtomic::::new(n_old); + let sut = IoxAtomic::::new(n_old); let result = sut.compare_exchange(n_new, n_old, Ordering::Relaxed, Ordering::Relaxed); @@ -152,7 +152,7 @@ mod ice_atomic { fn compare_exchange_weak_failure_works() { let n_old = T::generate_value(); let n_new = T::generate_value(); - let sut = IceAtomic::::new(n_old); + let sut = IoxAtomic::::new(n_old); let result = sut.compare_exchange(n_new, n_old, Ordering::Relaxed, Ordering::Relaxed); @@ -163,7 +163,7 @@ mod ice_atomic { #[test] fn fetch_add_works() { let n = T::generate_value(); - let sut = IceAtomic::::new(n); + let sut = IoxAtomic::::new(n); let result = sut.fetch_add(n, Ordering::Relaxed); @@ -176,7 +176,7 @@ mod ice_atomic { let n1 = T::generate_value(); let n2 = T::generate_value(); - let sut = IceAtomic::::new(n1); + let sut = IoxAtomic::::new(n1); let result = sut.fetch_and(n2, Ordering::Relaxed); @@ -191,7 +191,7 @@ mod ice_atomic { let n1 = T::generate_value(); let n2 = T::generate_value(); - let sut = IceAtomic::::new(n1); + let sut = IoxAtomic::::new(n1); let result = sut.fetch_max(n2, Ordering::Relaxed); @@ -204,7 +204,7 @@ mod ice_atomic { let n1 = T::generate_value(); let n2 = T::generate_value(); - let sut = IceAtomic::::new(n1); + let sut = IoxAtomic::::new(n1); let result = sut.fetch_min(n2, Ordering::Relaxed); @@ -217,7 +217,7 @@ mod ice_atomic { let n1 = T::generate_value(); let n2 = T::generate_value(); - let sut = IceAtomic::::new(n1); + let sut = IoxAtomic::::new(n1); let result = sut.fetch_nand(n2, Ordering::Relaxed); @@ -231,7 +231,7 @@ mod ice_atomic { let n1 = T::generate_value(); let n2 = T::generate_value(); - let sut = IceAtomic::::new(n1); + let sut = IoxAtomic::::new(n1); let result = sut.fetch_or(n2, Ordering::Relaxed); @@ -246,7 +246,7 @@ mod ice_atomic { let n1 = T::generate_value(); let n2 = T::generate_value(); - let sut = IceAtomic::::new(n1); + let sut = IoxAtomic::::new(n1); let result = sut.fetch_sub(n2, Ordering::Relaxed); @@ -268,7 +268,7 @@ mod ice_atomic { fn fetch_update_success_works() { let n1 = T::generate_value(); - let sut = IceAtomic::::new(n1); + let sut = IoxAtomic::::new(n1); let result = sut.fetch_update(Ordering::Relaxed, Ordering::Relaxed, ok_fetch_update::); @@ -283,7 +283,7 @@ mod ice_atomic { fn fetch_update_failure_works() { let n1 = T::generate_value(); - let sut = IceAtomic::::new(n1); + let sut = IoxAtomic::::new(n1); let result = sut.fetch_update(Ordering::Relaxed, Ordering::Relaxed, err_fetch_update::); @@ -297,7 +297,7 @@ mod ice_atomic { let n1 = T::generate_value(); let n2 = T::generate_value(); - let sut = IceAtomic::::new(n1); + let sut = IoxAtomic::::new(n1); let result = sut.fetch_xor(n2, Ordering::Relaxed); @@ -310,16 +310,16 @@ mod ice_atomic { #[test] fn into_inner_works() { let n = T::generate_value(); - let sut = IceAtomic::::new(n); + let sut = IoxAtomic::::new(n); - assert_that!(IceAtomic::::into_inner(sut), eq n); + assert_that!(IoxAtomic::::into_inner(sut), eq n); } #[test] fn load_store_works() { let n1 = T::generate_value(); let n2 = T::generate_value(); - let sut = IceAtomic::::new(n1); + let sut = IoxAtomic::::new(n1); sut.store(n2, Ordering::Relaxed); @@ -330,7 +330,7 @@ mod ice_atomic { fn swap_works() { let n1 = T::generate_value(); let n2 = T::generate_value(); - let sut = IceAtomic::::new(n1); + let sut = IoxAtomic::::new(n1); let result = sut.swap(n2, Ordering::Relaxed); @@ -341,7 +341,7 @@ mod ice_atomic { #[test] fn compatibility_new_works() { let n = T::generate_compatibility_value(); - let sut = IceAtomic::::new(n); + let sut = IoxAtomic::::new(n); let compat = AtomicU32::new(n.to_u32()); assert_that!(compat.load(Ordering::Relaxed), eq sut.load(Ordering::Relaxed).to_u32()); @@ -352,7 +352,7 @@ mod ice_atomic { let n1 = T::generate_compatibility_value(); let n2 = T::generate_compatibility_value(); - let sut = IceAtomic::::new(n1); + let sut = IoxAtomic::::new(n1); let compat = AtomicU32::new(n1.to_u32()); assert_that!(unsafe {*compat.as_ptr()}, eq unsafe{*sut.as_ptr()}.to_u32() ); @@ -369,7 +369,7 @@ mod ice_atomic { let n1 = T::generate_compatibility_value(); let n2 = T::generate_compatibility_value(); - let sut = IceAtomic::::new(n1); + let sut = IoxAtomic::::new(n1); let compat = AtomicU32::new(n1.to_u32()); let result_sut = sut.compare_exchange(n1, n2, Ordering::Relaxed, Ordering::Relaxed); @@ -392,7 +392,7 @@ mod ice_atomic { let n1 = T::generate_compatibility_value(); let n2 = T::generate_compatibility_value(); - let sut = IceAtomic::::new(n1); + let sut = IoxAtomic::::new(n1); let compat = AtomicU32::new(n1.to_u32()); let result_sut = sut.compare_exchange_weak(n1, n2, Ordering::Relaxed, Ordering::Relaxed); @@ -415,7 +415,7 @@ mod ice_atomic { let n1 = T::generate_compatibility_value(); let n2 = T::generate_compatibility_value(); - let sut = IceAtomic::::new(n1); + let sut = IoxAtomic::::new(n1); let compat = AtomicU32::new(n1.to_u32()); let result_sut = sut.compare_exchange(n2, n1, Ordering::Relaxed, Ordering::Relaxed); @@ -438,7 +438,7 @@ mod ice_atomic { let n1 = T::generate_compatibility_value(); let n2 = T::generate_compatibility_value(); - let sut = IceAtomic::::new(n1); + let sut = IoxAtomic::::new(n1); let compat = AtomicU32::new(n1.to_u32()); let result_sut = sut.compare_exchange_weak(n2, n1, Ordering::Relaxed, Ordering::Relaxed); @@ -461,7 +461,7 @@ mod ice_atomic { let n1 = T::generate_compatibility_value(); let n2 = T::generate_compatibility_value(); - let sut = IceAtomic::::new(n1); + let sut = IoxAtomic::::new(n1); let compat = AtomicU32::new(n1.to_u32()); assert_that!(sut.fetch_add(n2, Ordering::Relaxed).to_u32(), eq compat.fetch_add(n2.to_u32(), Ordering::Relaxed)); @@ -473,7 +473,7 @@ mod ice_atomic { let n1 = T::generate_compatibility_value(); let n2 = T::generate_compatibility_value(); - let sut = IceAtomic::::new(n1); + let sut = IoxAtomic::::new(n1); let compat = AtomicU32::new(n1.to_u32()); assert_that!(sut.fetch_and(n2, Ordering::Relaxed).to_u32(), eq compat.fetch_and(n2.to_u32(), Ordering::Relaxed)); @@ -485,7 +485,7 @@ mod ice_atomic { let n1 = T::generate_compatibility_value(); let n2 = T::generate_compatibility_value(); - let sut = IceAtomic::::new(n1); + let sut = IoxAtomic::::new(n1); let compat = AtomicU32::new(n1.to_u32()); assert_that!(sut.fetch_max(n2, Ordering::Relaxed).to_u32(), eq compat.fetch_max(n2.to_u32(), Ordering::Relaxed)); @@ -497,7 +497,7 @@ mod ice_atomic { let n1 = T::generate_compatibility_value(); let n2 = T::generate_compatibility_value(); - let sut = IceAtomic::::new(n1); + let sut = IoxAtomic::::new(n1); let compat = AtomicU32::new(n1.to_u32()); assert_that!(sut.fetch_min(n2, Ordering::Relaxed).to_u32(), eq compat.fetch_min(n2.to_u32(), Ordering::Relaxed)); @@ -509,7 +509,7 @@ mod ice_atomic { let n1 = T::generate_compatibility_value(); let n2 = T::generate_compatibility_value(); - let sut = IceAtomic::::new(n1); + let sut = IoxAtomic::::new(n1); let compat = AtomicU32::new(n1.to_u32()); assert_that!(sut.fetch_nand(n2, Ordering::Relaxed).to_u32(), eq compat.fetch_nand(n2.to_u32(), Ordering::Relaxed)); @@ -521,7 +521,7 @@ mod ice_atomic { let n1 = T::generate_compatibility_value(); let n2 = T::generate_compatibility_value(); - let sut = IceAtomic::::new(n1); + let sut = IoxAtomic::::new(n1); let compat = AtomicU32::new(n1.to_u32()); assert_that!(sut.fetch_or(n2, Ordering::Relaxed).to_u32(), eq compat.fetch_or(n2.to_u32(), Ordering::Relaxed)); @@ -533,7 +533,7 @@ mod ice_atomic { let n1 = T::generate_compatibility_value(); let n2 = T::generate_compatibility_value(); - let sut = IceAtomic::::new(n1); + let sut = IoxAtomic::::new(n1); let compat = AtomicU32::new(n1.to_u32()); assert_that!(sut.fetch_sub(n2, Ordering::Relaxed).to_u32(), eq compat.fetch_sub(n2.to_u32(), Ordering::Relaxed)); @@ -544,7 +544,7 @@ mod ice_atomic { fn compatibility_fetch_update_success_works() { let n1 = T::generate_compatibility_value(); - let sut = IceAtomic::::new(n1); + let sut = IoxAtomic::::new(n1); let compat = AtomicU32::new(n1.to_u32()); let result_sut = @@ -563,7 +563,7 @@ mod ice_atomic { fn compatibility_fetch_update_failure_works() { let n1 = T::generate_compatibility_value(); - let sut = IceAtomic::::new(n1); + let sut = IoxAtomic::::new(n1); let compat = AtomicU32::new(n1.to_u32()); let result_sut = @@ -586,7 +586,7 @@ mod ice_atomic { let n1 = T::generate_compatibility_value(); let n2 = T::generate_compatibility_value(); - let sut = IceAtomic::::new(n1); + let sut = IoxAtomic::::new(n1); let compat = AtomicU32::new(n1.to_u32()); assert_that!(sut.fetch_xor(n2, Ordering::Relaxed).to_u32(), eq compat.fetch_xor(n2.to_u32(), Ordering::Relaxed)); @@ -598,7 +598,7 @@ mod ice_atomic { let n1 = T::generate_compatibility_value(); let n2 = T::generate_compatibility_value(); - let sut = IceAtomic::::new(n1); + let sut = IoxAtomic::::new(n1); let compat = AtomicU32::new(n1.to_u32()); assert_that!(sut.swap(n2, Ordering::Relaxed).to_u32(), eq compat.swap(n2.to_u32(), Ordering::Relaxed)); From 9ad018dd81c1cd0eee5e4824676a44b849ad6173 Mon Sep 17 00:00:00 2001 From: Christian Eltzschig Date: Tue, 30 Apr 2024 00:43:14 +0200 Subject: [PATCH 7/7] [#200] Refactor test to be more robust --- .../tests/iox_atomic_tests.rs | 31 +++++++++++++------ 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/iceoryx2-pal/concurrency-sync/tests/iox_atomic_tests.rs b/iceoryx2-pal/concurrency-sync/tests/iox_atomic_tests.rs index 5487c97fc..88a6d418b 100644 --- a/iceoryx2-pal/concurrency-sync/tests/iox_atomic_tests.rs +++ b/iceoryx2-pal/concurrency-sync/tests/iox_atomic_tests.rs @@ -138,11 +138,12 @@ mod ice_atomic { #[test] fn compare_exchange_failure_works() { + let n_outdated = T::generate_value(); let n_old = T::generate_value(); let n_new = T::generate_value(); let sut = IoxAtomic::::new(n_old); - let result = sut.compare_exchange(n_new, n_old, Ordering::Relaxed, Ordering::Relaxed); + let result = sut.compare_exchange(n_outdated, n_new, Ordering::Relaxed, Ordering::Relaxed); assert_that!(result, is_err); assert_that!(result.err().unwrap(), eq n_old); @@ -150,11 +151,13 @@ mod ice_atomic { #[test] fn compare_exchange_weak_failure_works() { + let n_outdated = T::generate_value(); let n_old = T::generate_value(); let n_new = T::generate_value(); let sut = IoxAtomic::::new(n_old); - let result = sut.compare_exchange(n_new, n_old, Ordering::Relaxed, Ordering::Relaxed); + let result = + sut.compare_exchange_weak(n_outdated, n_new, Ordering::Relaxed, Ordering::Relaxed); assert_that!(result, is_err); assert_that!(result.err().unwrap(), eq n_old); @@ -191,12 +194,16 @@ mod ice_atomic { let n1 = T::generate_value(); let n2 = T::generate_value(); - let sut = IoxAtomic::::new(n1); + let sut_1 = IoxAtomic::::new(n1); + let sut_2 = IoxAtomic::::new(n2); - let result = sut.fetch_max(n2, Ordering::Relaxed); + let result_1 = sut_1.fetch_max(n2, Ordering::Relaxed); + let result_2 = sut_2.fetch_max(n1, Ordering::Relaxed); - assert_that!(result, eq n1); - assert_that!(sut.load(Ordering::Relaxed), eq n1.max(n2)); + assert_that!(result_1, eq n1); + assert_that!(result_2, eq n2); + assert_that!(sut_1.load(Ordering::Relaxed), eq n1.max(n2)); + assert_that!(sut_2.load(Ordering::Relaxed), eq n1.max(n2)); } #[test] @@ -204,12 +211,16 @@ mod ice_atomic { let n1 = T::generate_value(); let n2 = T::generate_value(); - let sut = IoxAtomic::::new(n1); + let sut_1 = IoxAtomic::::new(n1); + let sut_2 = IoxAtomic::::new(n2); - let result = sut.fetch_min(n2, Ordering::Relaxed); + let result_1 = sut_1.fetch_min(n2, Ordering::Relaxed); + let result_2 = sut_2.fetch_min(n1, Ordering::Relaxed); - assert_that!(result, eq n1); - assert_that!(sut.load(Ordering::Relaxed), eq n1.min(n2)); + assert_that!(result_1, eq n1); + assert_that!(result_2, eq n2); + assert_that!(sut_1.load(Ordering::Relaxed), eq n1.min(n2)); + assert_that!(sut_2.load(Ordering::Relaxed), eq n1.min(n2)); } #[test]