forked from spacejam/sled
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rust's `std::sync` namespace does not provide `AtomicU64` and `AtomicI64` for MIPS and PowerPC architectures. This make the project not capable of being embedded into routers as mentioned on spacejam#1070 This commit changes the references of `AtomicU64` and `AtomicI64` to use a portable version, wich fallbacks to `crossbeam` Mutex when Atomics are not available. To compile against MIPS, the `block` initialization had to change, as the Mutex is not `Copy`, and Rust's initialization of arrays only supports `Copy` types. The `array-init` crate supports non-Copy types, and that is why it was introduced. It also introduces a `--features mutex` crate, which allows to compile to x64 or any other architecture using the Mutex implementation, useful for testing without cross-compiling. Tests passes with: ``` cargo test --features testing cargo test --features testing --features mutex cross build --target mips-unknown-linux-musl ``` Cross-compiling tests fails due to sub-process spawning not getting hooked on qemu binfmt setup and spawning with the wrong architecture (x64 container trying to run MIPS executable). Creating a MIPS Debian VM using QEMU compiles (although very slowly) and runs almost all of the tests correctly (except the quiescent cpu time, which is very slow to run on my VM).
- Loading branch information
Showing
6 changed files
with
307 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,296 @@ | ||
///! Inline of https://github.com/bltavares/atomic-shim | ||
|
||
#[cfg(not(any( | ||
target_arch = "mips", | ||
target_arch = "powerpc", | ||
feature = "mutex" | ||
)))] | ||
pub use std::sync::atomic::{AtomicI64, AtomicU64}; | ||
#[cfg(any(target_arch = "mips", target_arch = "powerpc", feature = "mutex"))] | ||
mod shim { | ||
use crossbeam_utils::sync::ShardedLock; | ||
use std::sync::atomic::Ordering; | ||
|
||
#[derive(Debug, Default)] | ||
pub struct AtomicU64 { | ||
value: ShardedLock<u64>, | ||
} | ||
|
||
impl AtomicU64 { | ||
pub fn new(v: u64) -> Self { | ||
Self { value: ShardedLock::new(v) } | ||
} | ||
|
||
#[allow(dead_code)] | ||
pub fn get_mut(&mut self) -> &mut u64 { | ||
self.value.get_mut().unwrap() | ||
} | ||
|
||
#[allow(dead_code)] | ||
pub fn into_inner(self) -> u64 { | ||
self.value.into_inner().unwrap() | ||
} | ||
|
||
#[allow(dead_code)] | ||
pub fn load(&self, _: Ordering) -> u64 { | ||
*self.value.read().unwrap() | ||
} | ||
|
||
#[allow(dead_code)] | ||
pub fn store(&self, value: u64, _: Ordering) { | ||
let mut lock = self.value.write().unwrap(); | ||
*lock = value; | ||
} | ||
|
||
#[allow(dead_code)] | ||
pub fn swap(&self, value: u64, _: Ordering) -> u64 { | ||
let mut lock = self.value.write().unwrap(); | ||
let prev = *lock; | ||
*lock = value; | ||
prev | ||
} | ||
|
||
#[allow(dead_code)] | ||
pub fn compare_and_swap( | ||
&self, | ||
current: u64, | ||
new: u64, | ||
_: Ordering, | ||
) -> u64 { | ||
let mut lock = self.value.write().unwrap(); | ||
let prev = *lock; | ||
if prev == current { | ||
*lock = new; | ||
}; | ||
prev | ||
} | ||
|
||
#[allow(dead_code)] | ||
pub fn compare_exchange( | ||
&self, | ||
current: u64, | ||
new: u64, | ||
_: Ordering, | ||
_: Ordering, | ||
) -> Result<u64, u64> { | ||
let mut lock = self.value.write().unwrap(); | ||
let prev = *lock; | ||
if prev == current { | ||
*lock = new; | ||
Ok(current) | ||
} else { | ||
Err(prev) | ||
} | ||
} | ||
|
||
#[allow(dead_code)] | ||
pub fn compare_exchange_weak( | ||
&self, | ||
current: u64, | ||
new: u64, | ||
success: Ordering, | ||
failure: Ordering, | ||
) -> Result<u64, u64> { | ||
self.compare_exchange(current, new, success, failure) | ||
} | ||
|
||
#[allow(dead_code)] | ||
pub fn fetch_add(&self, val: u64, _: Ordering) -> u64 { | ||
let mut lock = self.value.write().unwrap(); | ||
let prev = *lock; | ||
*lock = prev.wrapping_add(val); | ||
prev | ||
} | ||
|
||
#[allow(dead_code)] | ||
pub fn fetch_sub(&self, val: u64, _: Ordering) -> u64 { | ||
let mut lock = self.value.write().unwrap(); | ||
let prev = *lock; | ||
*lock = prev.wrapping_sub(val); | ||
prev | ||
} | ||
|
||
#[allow(dead_code)] | ||
pub fn fetch_and(&self, val: u64, _: Ordering) -> u64 { | ||
let mut lock = self.value.write().unwrap(); | ||
let prev = *lock; | ||
*lock = prev & val; | ||
prev | ||
} | ||
|
||
#[allow(dead_code)] | ||
pub fn fetch_nand(&self, val: u64, _: Ordering) -> u64 { | ||
let mut lock = self.value.write().unwrap(); | ||
let prev = *lock; | ||
*lock = !(prev & val); | ||
prev | ||
} | ||
|
||
#[allow(dead_code)] | ||
pub fn fetch_or(&self, val: u64, _: Ordering) -> u64 { | ||
let mut lock = self.value.write().unwrap(); | ||
let prev = *lock; | ||
*lock = prev | val; | ||
prev | ||
} | ||
|
||
#[allow(dead_code)] | ||
pub fn fetch_xor(&self, val: u64, _: Ordering) -> u64 { | ||
let mut lock = self.value.write().unwrap(); | ||
let prev = *lock; | ||
*lock = prev ^ val; | ||
prev | ||
} | ||
} | ||
|
||
impl From<u64> for AtomicU64 { | ||
fn from(value: u64) -> Self { | ||
AtomicU64::new(value) | ||
} | ||
} | ||
|
||
#[derive(Debug, Default)] | ||
pub struct AtomicI64 { | ||
value: ShardedLock<i64>, | ||
} | ||
|
||
impl AtomicI64 { | ||
pub fn new(v: i64) -> Self { | ||
Self { value: ShardedLock::new(v) } | ||
} | ||
|
||
#[allow(dead_code)] | ||
pub fn get_mut(&mut self) -> &mut i64 { | ||
self.value.get_mut().unwrap() | ||
} | ||
|
||
#[allow(dead_code)] | ||
pub fn into_inner(self) -> i64 { | ||
self.value.into_inner().unwrap() | ||
} | ||
|
||
#[allow(dead_code)] | ||
pub fn load(&self, _: Ordering) -> i64 { | ||
*self.value.read().unwrap() | ||
} | ||
|
||
#[allow(dead_code)] | ||
pub fn store(&self, value: i64, _: Ordering) { | ||
let mut lock = self.value.write().unwrap(); | ||
*lock = value; | ||
} | ||
|
||
#[allow(dead_code)] | ||
pub fn swap(&self, value: i64, _: Ordering) -> i64 { | ||
let mut lock = self.value.write().unwrap(); | ||
let prev = *lock; | ||
*lock = value; | ||
prev | ||
} | ||
|
||
#[allow(dead_code)] | ||
pub fn compare_and_swap( | ||
&self, | ||
current: i64, | ||
new: i64, | ||
_: Ordering, | ||
) -> i64 { | ||
let mut lock = self.value.write().unwrap(); | ||
let prev = *lock; | ||
if prev == current { | ||
*lock = new; | ||
}; | ||
prev | ||
} | ||
|
||
#[allow(dead_code)] | ||
pub fn compare_exchange( | ||
&self, | ||
current: i64, | ||
new: i64, | ||
_: Ordering, | ||
_: Ordering, | ||
) -> Result<i64, i64> { | ||
let mut lock = self.value.write().unwrap(); | ||
let prev = *lock; | ||
if prev == current { | ||
*lock = new; | ||
Ok(current) | ||
} else { | ||
Err(prev) | ||
} | ||
} | ||
|
||
#[allow(dead_code)] | ||
pub fn compare_exchange_weak( | ||
&self, | ||
current: i64, | ||
new: i64, | ||
success: Ordering, | ||
failure: Ordering, | ||
) -> Result<i64, i64> { | ||
self.compare_exchange(current, new, success, failure) | ||
} | ||
|
||
#[allow(dead_code)] | ||
pub fn fetch_add(&self, val: i64, _: Ordering) -> i64 { | ||
let mut lock = self.value.write().unwrap(); | ||
let prev = *lock; | ||
*lock = prev.wrapping_add(val); | ||
prev | ||
} | ||
|
||
#[allow(dead_code)] | ||
pub fn fetch_sub(&self, val: i64, _: Ordering) -> i64 { | ||
let mut lock = self.value.write().unwrap(); | ||
let prev = *lock; | ||
*lock = prev.wrapping_sub(val); | ||
prev | ||
} | ||
|
||
#[allow(dead_code)] | ||
pub fn fetch_and(&self, val: i64, _: Ordering) -> i64 { | ||
let mut lock = self.value.write().unwrap(); | ||
let prev = *lock; | ||
*lock = prev & val; | ||
prev | ||
} | ||
|
||
#[allow(dead_code)] | ||
pub fn fetch_nand(&self, val: i64, _: Ordering) -> i64 { | ||
let mut lock = self.value.write().unwrap(); | ||
let prev = *lock; | ||
*lock = !(prev & val); | ||
prev | ||
} | ||
|
||
#[allow(dead_code)] | ||
pub fn fetch_or(&self, val: i64, _: Ordering) -> i64 { | ||
let mut lock = self.value.write().unwrap(); | ||
let prev = *lock; | ||
*lock = prev | val; | ||
prev | ||
} | ||
|
||
#[allow(dead_code)] | ||
pub fn fetch_xor(&self, val: i64, _: Ordering) -> i64 { | ||
let mut lock = self.value.write().unwrap(); | ||
let prev = *lock; | ||
*lock = prev ^ val; | ||
prev | ||
} | ||
} | ||
|
||
impl From<i64> for AtomicI64 { | ||
fn from(value: i64) -> Self { | ||
AtomicI64::new(value) | ||
} | ||
} | ||
} | ||
|
||
#[cfg(any( | ||
target_arch = "mips", | ||
target_arch = "powerpc", | ||
feature = "mutex" | ||
))] | ||
pub use shim::{AtomicI64, AtomicU64}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters