Skip to content

Commit

Permalink
feat(#1, loom): add more configs
Browse files Browse the repository at this point in the history
  • Loading branch information
wvwwvwwv committed Jul 17, 2024
1 parent 71f6080 commit 4b3c5c3
Show file tree
Hide file tree
Showing 10 changed files with 243 additions and 120 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/sdd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ jobs:
- name: Doc
run: cargo doc --document-private-items;
- name: Loom
run: RUSTFLAGS="--cfg loom" cargo test --release --lib
run: RUSTFLAGS="--cfg loom_test" cargo test --features sdd_loom --release --lib
- name: Miri
run: cargo +nightly miri test --lib --bins --tests
benchmark:
Expand Down
10 changes: 6 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,18 @@ keywords = ["concurrent", "epoch", "garbage", "lock-free", "memory"]
[workspace]
members = [".", "examples"]

[dependencies]
loom = { version = "0.7", optional = true }

[features]
sdd_loom = ["loom"]

[dev-dependencies]
criterion = "0.5"
futures = "0.3"
loom = "0.7"
static_assertions = "1.1"
tokio = { version = "1.38", features = ["full"] }

[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(loom)'] }

[[bench]]
name = "ebr"
harness = false
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ A scalable lock-free delayed memory reclaimer that emulates garbage collection b

Its delayed deallocation algorithm is based on a variant of epoch-based reclamation where _retired_ memory chunks are stored in thread-local storage until certain criteria are met. The [crossbeam_epoch](https://docs.rs/crossbeam-epoch/) crate offers similar functionality, however users will find `sdd` easier to use as the lifetime of a memory chunk is safely _managed_. For instance, `sdd::AtomicOwned` and `sdd::Owned` retire the contained instance when they are dropped, and `sdd::AtomicShared` and `sdd::Shared` retire the instance when the last strong reference is dropped.

## Features

* Lock-free epoch-based reclamation.
* [`Loom`](https://crates.io/crates/loom) support: `features = ["loom"]`.

## Memory Overhead

Retired instances are stored in intrusive queues in thread-local storage, and therefore additional space for `Option<NonNull<dyn Collectible>>` is allocated per instance.
Expand Down
26 changes: 25 additions & 1 deletion src/atomic_owned.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use super::optional_public::AtomicPtr;
use super::ref_counted::RefCounted;
use super::{Guard, Owned, Ptr, Tag};
use std::mem::forget;
use std::panic::UnwindSafe;
use std::ptr::{null_mut, NonNull};
use std::sync::atomic::AtomicPtr;
use std::sync::atomic::Ordering::{self, Relaxed};

/// [`AtomicOwned`] owns the underlying instance, and allows users to perform atomic operations
Expand Down Expand Up @@ -52,6 +52,7 @@ impl<T> AtomicOwned<T> {
/// let owned: Owned<usize> = Owned::new(10);
/// let atomic_owned: AtomicOwned<usize> = AtomicOwned::from(owned);
/// ```
#[cfg(not(feature = "sdd_loom"))]
#[inline]
#[must_use]
pub const fn from(owned: Owned<T>) -> Self {
Expand All @@ -62,6 +63,18 @@ impl<T> AtomicOwned<T> {
}
}

/// Creates a new [`AtomicOwned`] from an [`Owned`] of `T`.
#[cfg(feature = "sdd_loom")]
#[inline]
#[must_use]
pub fn from(owned: Owned<T>) -> Self {
let ptr = owned.get_underlying_ptr();
forget(owned);
Self {
instance_ptr: AtomicPtr::new(ptr),
}
}

/// Creates a null [`AtomicOwned`].
///
/// # Examples
Expand All @@ -71,6 +84,7 @@ impl<T> AtomicOwned<T> {
///
/// let atomic_owned: AtomicOwned<usize> = AtomicOwned::null();
/// ```
#[cfg(not(feature = "sdd_loom"))]
#[inline]
#[must_use]
pub const fn null() -> Self {
Expand All @@ -79,6 +93,16 @@ impl<T> AtomicOwned<T> {
}
}

/// Creates a null [`AtomicOwned`].
#[cfg(feature = "sdd_loom")]
#[inline]
#[must_use]
pub fn null() -> Self {
Self {
instance_ptr: AtomicPtr::new(null_mut()),
}
}

/// Returns `true` if the [`AtomicOwned`] is null.
///
/// # Examples
Expand Down
26 changes: 25 additions & 1 deletion src/atomic_shared.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use super::optional_public::AtomicPtr;
use super::ref_counted::RefCounted;
use super::{Guard, Ptr, Shared, Tag};
use std::mem::forget;
use std::panic::UnwindSafe;
use std::ptr::{null_mut, NonNull};
use std::sync::atomic::AtomicPtr;
use std::sync::atomic::Ordering::{self, Acquire, Relaxed};

/// [`AtomicShared`] owns the underlying instance, and allows users to perform atomic operations
Expand Down Expand Up @@ -52,6 +52,7 @@ impl<T> AtomicShared<T> {
/// let shared: Shared<usize> = Shared::new(10);
/// let atomic_shared: AtomicShared<usize> = AtomicShared::from(shared);
/// ```
#[cfg(not(feature = "sdd_loom"))]
#[inline]
#[must_use]
pub const fn from(shared: Shared<T>) -> Self {
Expand All @@ -62,6 +63,18 @@ impl<T> AtomicShared<T> {
}
}

/// Creates a new [`AtomicShared`] from a [`Shared`] of `T`.
#[cfg(feature = "sdd_loom")]
#[inline]
#[must_use]
pub fn from(shared: Shared<T>) -> Self {
let ptr = shared.get_underlying_ptr();
forget(shared);
Self {
instance_ptr: AtomicPtr::new(ptr),
}
}

/// Creates a null [`AtomicShared`].
///
/// # Examples
Expand All @@ -71,6 +84,7 @@ impl<T> AtomicShared<T> {
///
/// let atomic_shared: AtomicShared<usize> = AtomicShared::null();
/// ```
#[cfg(not(feature = "sdd_loom"))]
#[inline]
#[must_use]
pub const fn null() -> Self {
Expand All @@ -79,6 +93,16 @@ impl<T> AtomicShared<T> {
}
}

/// Creates a null [`AtomicShared`].
#[cfg(feature = "sdd_loom")]
#[inline]
#[must_use]
pub fn null() -> Self {
Self {
instance_ptr: AtomicPtr::new(null_mut()),
}
}

/// Returns `true` if the [`AtomicShared`] is null.
///
/// # Examples
Expand Down
Loading

0 comments on commit 4b3c5c3

Please sign in to comment.