Skip to content

Commit

Permalink
Add no-std support (#3)
Browse files Browse the repository at this point in the history
* Add no-std support

* Update CI and version number

* Add workflows for loom and miri
  • Loading branch information
Johnabell authored Nov 8, 2023
1 parent 9dc7f47 commit f94dd5b
Show file tree
Hide file tree
Showing 8 changed files with 196 additions and 41 deletions.
40 changes: 39 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ jobs:
strategy:
matrix:
rust: [ stable, nightly ]
features: [ --no-default-features, --all-features ]
steps:
- run: sudo apt install libwayland-cursor0 libxkbcommon-dev libwayland-dev
- uses: actions/checkout@v2
Expand All @@ -24,13 +25,15 @@ jobs:
- uses: actions-rs/cargo@v1
with:
command: check
args: ${{ matrix.features }}

test:
name: Test Suite
runs-on: ubuntu-latest
strategy:
matrix:
rust: [ stable, nightly ]
features: [ --no-default-features, --all-features ]
steps:
- run: sudo apt install libwayland-cursor0 libxkbcommon-dev libwayland-dev
- uses: actions/checkout@v2
Expand All @@ -42,6 +45,7 @@ jobs:
- uses: actions-rs/cargo@v1
with:
command: test
args: ${{ matrix.features }}

fmt:
name: Rustfmt
Expand Down Expand Up @@ -69,6 +73,7 @@ jobs:
strategy:
matrix:
rust: [ stable, nightly ]
features: [ --no-default-features, --all-features ]
steps:
- run: sudo apt install libwayland-cursor0 libxkbcommon-dev libwayland-dev
- uses: actions/checkout@v2
Expand All @@ -81,4 +86,37 @@ jobs:
- uses: actions-rs/cargo@v1
with:
command: clippy
# args: -- -D warnings
args: ${{ matrix.features }} -- -D warnings

loom:
name: Loom
runs-on: ubuntu-latest
strategy:
matrix:
rust: [ stable, nightly ]
steps:
- run: sudo apt install libwayland-cursor0 libxkbcommon-dev libwayland-dev
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ matrix.rust }}
override: true
- run: RUSTFLAGS="--cfg loom" cargo test --test concurrency_tests --release

miri:
name: Miri
runs-on: ubuntu-latest
strategy:
matrix:
features: [ --no-default-features, --all-features ]
steps:
- run: sudo apt install libwayland-cursor0 libxkbcommon-dev libwayland-dev
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: nightly
override: true
- run: rustup component add miri
- run: RUST_BACKTRACE=1 MIRIFLAGS="-Zmiri-ignore-leaks -Zmiri-disable-isolation" cargo miri test ${{ matrix.features }}
10 changes: 7 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
[package]
name = "atom_box"
version = "0.1.3"
version = "0.2.0"
edition = "2018"
authors = ["John Bell <[email protected]>"]

license = "MIT OR Apache-2.0"

readme = "README.md"
description = "A safe idiomatic Rust implementation of Atmoic Box using hazard pointers"
description = "A safe idiomatic Rust implementation of Atomic Box using hazard pointers"
repository = "https://github.com/Johnabell/atom_box.git"

keywords = ["atomic", "harard", "pointers", "AtomicBox"]
keywords = ["atomic", "hazard", "pointers", "AtomicBox"]
categories = ["concurrency", "rust-patterns", "memory-management"]

[features]
default = ["std"]
std = []

[target.'cfg(loom)'.dependencies]
loom = "0.5"
8 changes: 5 additions & 3 deletions src/domain/list.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::macros::conditional_const;
use crate::sync::{AtomicIsize, AtomicPtr, Ordering};
use alloc::boxed::Box;

#[derive(Debug)]
pub(super) struct LockFreeList<T> {
Expand All @@ -19,7 +20,7 @@ impl<T> LockFreeList<T> {
pub,
fn new() -> Self {
Self {
head: AtomicPtr::new(std::ptr::null_mut()),
head: AtomicPtr::new(core::ptr::null_mut()),
count: AtomicIsize::new(0),
}
}
Expand All @@ -28,7 +29,7 @@ impl<T> LockFreeList<T> {
pub(super) fn push(&self, value: T) -> *mut Node<T> {
let node = Box::into_raw(Box::new(Node {
value,
next: AtomicPtr::new(std::ptr::null_mut()),
next: AtomicPtr::new(core::ptr::null_mut()),
}));

// # Safety
Expand Down Expand Up @@ -87,6 +88,7 @@ impl<T> Drop for LockFreeList<T> {
#[cfg(test)]
mod test {
use super::*;
use alloc::vec::Vec;

#[test]
fn test_push() {
Expand Down Expand Up @@ -146,6 +148,6 @@ mod test {
"The list should contain all the values from pushed to it from list2 and the original values from list 1"
);
// To avoid dropping the nodes which we moved from list2 to list1
std::mem::forget(list2);
core::mem::forget(list2);
}
}
26 changes: 15 additions & 11 deletions src/domain/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,13 @@ mod reclaim_strategy;

use crate::macros::conditional_const;
use crate::sync::Ordering;
use alloc::boxed::Box;
#[cfg(not(feature = "std"))]
use alloc::collections::BTreeSet as Set;
use list::{LockFreeList, Node};
pub use reclaim_strategy::{ReclaimStrategy, TimedCappedSettings};
use std::collections::HashSet;
#[cfg(feature = "std")]
use std::collections::HashSet as Set;

pub(crate) trait Retirable {}

Expand All @@ -51,7 +55,7 @@ impl Retire {
fn new<T>(ptr: *mut T) -> Self {
Self {
ptr: ptr as *mut usize,
retirable: unsafe { std::mem::transmute(ptr as *mut dyn Retirable) },
retirable: unsafe { core::mem::transmute(ptr as *mut dyn Retirable) },
}
}
}
Expand Down Expand Up @@ -146,7 +150,7 @@ On nightly this will panic if the domain id is equal to the shared domain's id (
/// Value must be associated with this domain.
/// Value must be able to live as long as the domain.
pub(crate) unsafe fn retire<T>(&self, value: *mut T) {
std::sync::atomic::fence(Ordering::SeqCst);
core::sync::atomic::fence(Ordering::SeqCst);

self.retired.push(Retire::new(value));
if self.should_reclaim() {
Expand Down Expand Up @@ -185,9 +189,9 @@ On nightly this will panic if the domain id is equal to the shared domain's id (
let retired_list = self
.retired
.head
.swap(std::ptr::null_mut(), Ordering::Acquire);
.swap(core::ptr::null_mut(), Ordering::Acquire);

std::sync::atomic::fence(Ordering::SeqCst);
core::sync::atomic::fence(Ordering::SeqCst);

self.retired.count.store(0, Ordering::Release);
if retired_list.is_null() {
Expand All @@ -199,11 +203,11 @@ On nightly this will panic if the domain id is equal to the shared domain's id (

fn reclaim_unguarded(
&self,
guarded_ptrs: HashSet<*const usize>,
guarded_ptrs: Set<*const usize>,
retired_list: *mut Node<Retire>,
) -> usize {
let mut node_ptr = retired_list;
let mut still_retired = std::ptr::null_mut();
let mut still_retired = core::ptr::null_mut();
let mut tail_ptr = None;
let mut reclaimed = 0;
let mut number_remaining = 0;
Expand Down Expand Up @@ -231,7 +235,7 @@ On nightly this will panic if the domain id is equal to the shared domain's id (
// the pointer has not yet been dropped and has only been placed in the retired
// list once. There are currently no other threads looking at the value since it is
// no longer protected by any of the hazard pointers.
unsafe { std::ptr::drop_in_place(node.value.retirable) };
unsafe { core::ptr::drop_in_place(node.value.retirable) };

// # Safety
//
Expand All @@ -246,7 +250,7 @@ On nightly this will panic if the domain id is equal to the shared domain's id (
}

if let Some(tail) = tail_ptr {
std::sync::atomic::fence(Ordering::SeqCst);
core::sync::atomic::fence(Ordering::SeqCst);

// # Safety
//
Expand All @@ -258,8 +262,8 @@ On nightly this will panic if the domain id is equal to the shared domain's id (
reclaimed
}

fn get_guarded_ptrs(&self) -> HashSet<*const usize> {
let mut guarded_ptrs = HashSet::new();
fn get_guarded_ptrs(&self) -> Set<*const usize> {
let mut guarded_ptrs = Set::new();
let mut node_ptr = self.hazard_ptrs.head.load(Ordering::Acquire);
while !node_ptr.is_null() {
// # Safety
Expand Down
Loading

0 comments on commit f94dd5b

Please sign in to comment.