Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

no_std #56

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 37 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,16 @@ weak = []
internal-test-strategies = []
# Possibly some strategies we are experimenting with. Currently empty. No stability guarantees are included about them.
experimental-strategies = []
# no_std doesn't have RwLock and thread_local!
no_std = ["parking_lot", "static_init"]
no_std_spin_loop = ["static_init/spin_loop"]

[dependencies]
# Optional dependency for supporting no_std
# RwLock
parking_lot = { version = "0.11.1", optional = true }
# thread_local!
static_init = { version = "1.0.1", optional = true, features = ["thread_local"] }

[dev-dependencies]
adaptive-barrier = "~0.1"
Expand Down
9 changes: 5 additions & 4 deletions src/access.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,11 @@
//! work_with_usize(Constant(42)).join().unwrap();
//! ```

use std::marker::PhantomData;
use std::ops::Deref;
use std::rc::Rc;
use std::sync::Arc;
use core::marker::PhantomData;
use core::ops::Deref;
use alloc::rc::Rc;
use alloc::sync::Arc;
use alloc::boxed::Box;

use super::ref_cnt::RefCnt;
use super::strategy::Strategy;
Expand Down
6 changes: 3 additions & 3 deletions src/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
//!
//! [Arc]: std::sync::Arc

use std::ops::Deref;
use std::sync::atomic::Ordering;
use core::ops::Deref;
use core::sync::atomic::Ordering;

use super::ref_cnt::RefCnt;
use super::strategy::Strategy;
Expand Down Expand Up @@ -244,7 +244,7 @@ where

#[cfg(test)]
mod tests {
use std::sync::Arc;
use alloc::sync::Arc;

use super::*;
use crate::{ArcSwap, ArcSwapOption};
Expand Down
6 changes: 3 additions & 3 deletions src/debt/fast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
//! before the change and before any cleanup of the old pointer happened (in which case we know the
//! writer will see our debt).

use std::cell::Cell;
use std::slice::Iter;
use std::sync::atomic::Ordering::*;
use core::cell::Cell;
use alloc::slice::Iter;
use core::sync::atomic::Ordering::*;

use super::Debt;

Expand Down
8 changes: 4 additions & 4 deletions src/debt/helping.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,10 @@
//! writer and that change is the destruction ‒ by that time, the destroying thread has exclusive
//! ownership and therefore there can be no new readers.

use std::cell::Cell;
use std::ptr;
use std::sync::atomic::Ordering::*;
use std::sync::atomic::{AtomicPtr, AtomicUsize};
use core::cell::Cell;
use core::ptr;
use core::sync::atomic::Ordering::*;
use core::sync::atomic::{AtomicPtr, AtomicUsize};

use super::Debt;
use crate::RefCnt;
Expand Down
46 changes: 38 additions & 8 deletions src/debt/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,12 @@
//! at least as up to date value of the writers as when the cooldown started. That we if we see 0,
//! we know it must have happened since then.

use std::cell::Cell;
use std::ptr;
use std::slice::Iter;
use std::sync::atomic::Ordering::*;
use std::sync::atomic::{AtomicPtr, AtomicUsize};
use core::cell::Cell;
use core::ptr;
use alloc::slice::Iter;
use core::sync::atomic::Ordering::*;
use core::sync::atomic::{AtomicPtr, AtomicUsize};
use alloc::boxed::Box;

use super::fast::{Local as FastLocal, Slots as FastSlots};
use super::helping::{Local as HelpingLocal, Slots as HelpingSlots};
Expand Down Expand Up @@ -205,8 +206,7 @@ pub(crate) struct LocalNode {
impl LocalNode {
pub(crate) fn with<R, F: FnOnce(&LocalNode) -> R>(f: F) -> R {
let f = Cell::new(Some(f));
THREAD_HEAD
.try_with(|head| {
thread_head_try_with(|head| {
if head.node.get().is_none() {
head.node.set(Some(Node::get()));
}
Expand Down Expand Up @@ -302,6 +302,11 @@ impl Drop for LocalNode {
}
}

#[cfg(not(feature = "no_std"))]
extern crate std;
#[cfg(not(feature = "no_std"))]
use std::thread_local;
#[cfg(not(feature = "no_std"))]
thread_local! {
/// A debt node assigned to this thread.
static THREAD_HEAD: LocalNode = LocalNode {
Expand All @@ -310,6 +315,31 @@ thread_local! {
helping: HelpingLocal::default(),
};
}
#[cfg(not(feature = "no_std"))]
fn thread_head_try_with<F, R>(f: F) -> Result<R, std::thread::AccessError>
where
F: FnOnce(&LocalNode) -> R,
{
THREAD_HEAD.try_with(f)
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be better to have a whole (inline) module under that #[cfg(...)] instead of repeating it again and again?


#[cfg(feature = "no_std")]
use static_init::dynamic;
#[cfg(feature = "no_std")]
#[dynamic(drop)]
#[thread_local]
static THREAD_HEAD: LocalNode = LocalNode {
node: Cell::new(None),
fast: FastLocal::default(),
helping: HelpingLocal::default(),
};
#[cfg(feature = "no_std")]
fn thread_head_try_with<F, R>(f: F) -> Result<R, ()>
where
F: FnOnce(&LocalNode) -> R,
{
Result::Ok(f(&THREAD_HEAD))
}

#[cfg(test)]
mod tests {
Expand All @@ -318,7 +348,7 @@ mod tests {
impl Node {
fn is_empty(&self) -> bool {
self.fast_slots()
.chain(std::iter::once(self.helping_slot()))
.chain(core::iter::once(self.helping_slot()))
.all(|d| d.0.load(Relaxed) == Debt::NONE)
}

Expand Down
8 changes: 4 additions & 4 deletions src/debt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
//! Each node has some fast (but fallible) nodes and a fallback node, with different algorithms to
//! claim them (see the relevant submodules).

use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::*;
use core::sync::atomic::AtomicUsize;
use core::sync::atomic::Ordering::*;

pub(crate) use self::list::{LocalNode, Node};
use super::RefCnt;
Expand Down Expand Up @@ -96,7 +96,7 @@ impl Debt {

let all_slots = node
.fast_slots()
.chain(std::iter::once(node.helping_slot()));
.chain(core::iter::once(node.helping_slot()));
for slot in all_slots {
// Note: Release is enough even here. That makes sure the increment is
// visible to whoever might acquire on this slot and can't leak below this.
Expand All @@ -116,7 +116,7 @@ impl Debt {

#[cfg(test)]
mod tests {
use std::sync::Arc;
use alloc::sync::Arc;

/// Checks the assumption that arcs to ZSTs have different pointer values.
#[test]
Expand Down
36 changes: 22 additions & 14 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,11 @@
//!
//! [RwLock]: https://doc.rust-lang.org/std/sync/struct.RwLock.html

#![feature(thread_local)]

#![no_std]
extern crate alloc;

pub mod access;
mod as_raw;
pub mod cache;
Expand All @@ -135,14 +140,14 @@ pub mod strategy;
#[cfg(feature = "weak")]
mod weak;

use std::borrow::Borrow;
use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
use std::marker::PhantomData;
use std::mem;
use std::ops::Deref;
use std::ptr;
use std::sync::atomic::{AtomicPtr, Ordering};
use std::sync::Arc;
use core::borrow::Borrow;
use core::fmt::{Debug, Display, Formatter, Result as FmtResult};
use core::marker::PhantomData;
use core::mem;
use core::ops::Deref;
use core::ptr;
use core::sync::atomic::{AtomicPtr, Ordering};
use alloc::sync::Arc;

use crate::access::{Access, Map};
pub use crate::as_raw::AsRaw;
Expand Down Expand Up @@ -764,8 +769,10 @@ macro_rules! t {
($name: ident, $strategy: ty) => {
#[cfg(test)]
mod $name {
use std::panic;
use std::sync::atomic::{self, AtomicUsize};
use core::panic;
use core::sync::atomic::{self, AtomicUsize};
use alloc::format;
use alloc::borrow::ToOwned;

use adaptive_barrier::{Barrier, PanicMode};
use crossbeam_utils::thread;
Expand All @@ -786,7 +793,7 @@ macro_rules! t {
fn publish() {
const READERS: usize = 2;
for _ in 0..ITERATIONS {
let config = As::<String>::default();
let config = As::<alloc::string::String>::default();
let ended = AtomicUsize::new(0);
thread::scope(|scope| {
for _ in 0..READERS {
Expand Down Expand Up @@ -1081,8 +1088,9 @@ macro_rules! t {
/// A panic from within the rcu callback should not change anything.
#[test]
fn rcu_panic() {
extern crate std;
let shared = ArcSwap::from(Arc::new(0));
assert!(panic::catch_unwind(|| shared.rcu(|_| -> usize { panic!() })).is_err());
assert!(std::panic::catch_unwind(|| shared.rcu(|_| -> usize { panic!() })).is_err());
assert_eq!(1, Arc::strong_count(&shared.swap(Arc::new(42))));
}

Expand Down Expand Up @@ -1138,7 +1146,7 @@ macro_rules! t {
// Fill up the slots sometimes
let fillup = || {
if i % 2 == 0 {
Some((0..50).map(|_| shared.load()).collect::<Vec<_>>())
Some((0..50).map(|_| shared.load()).collect::<alloc::vec::Vec<_>>())
} else {
None
}
Expand Down Expand Up @@ -1237,7 +1245,7 @@ mod tests {
let a = Arc::new(0);
let shared = ArcSwap::from(Arc::clone(&a));
assert_eq!(2, Arc::strong_count(&a));
let mut guards = (0..1000).map(|_| shared.load()).collect::<Vec<_>>();
let mut guards = (0..1000).map(|_| shared.load()).collect::<alloc::vec::Vec<_>>();
let count = Arc::strong_count(&a);
assert!(count > 2);
let guard = shared.load();
Expand Down
6 changes: 3 additions & 3 deletions src/ref_cnt.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::ptr;
use std::rc::Rc;
use std::sync::Arc;
use core::ptr;
use alloc::rc::Rc;
use alloc::sync::Arc;

/// A trait describing smart reference counted pointers.
///
Expand Down
12 changes: 6 additions & 6 deletions src/strategy/hybrid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@
//! See the [crate::debt] module for the actual slot manipulation. Here we just wrap them into the
//! strategy.

use std::borrow::Borrow;
use std::mem::{self, ManuallyDrop};
use std::ops::Deref;
use std::ptr;
use std::sync::atomic::AtomicPtr;
use std::sync::atomic::Ordering::*;
use core::borrow::Borrow;
use core::mem::{self, ManuallyDrop};
use core::ops::Deref;
use core::ptr;
use core::sync::atomic::AtomicPtr;
use core::sync::atomic::Ordering::*;

use super::sealed::{CaS, InnerStrategy, Protected};
use crate::debt::{Debt, LocalNode};
Expand Down
4 changes: 2 additions & 2 deletions src/strategy/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@
//! [`ArcSwap`]: crate::ArcSwap
//! [`load`]: crate::ArcSwapAny::load

use std::borrow::Borrow;
use std::sync::atomic::AtomicPtr;
use core::borrow::Borrow;
use core::sync::atomic::AtomicPtr;

use crate::ref_cnt::RefCnt;

Expand Down
Loading