Skip to content

Commit

Permalink
Add a default "std" feature for no_std usage
Browse files Browse the repository at this point in the history
This is a breaking change for no-default-features users.

Signed-off-by: John Nunley <[email protected]>
  • Loading branch information
notgull committed Sep 17, 2023
1 parent 8f8b4fe commit 3a82590
Show file tree
Hide file tree
Showing 10 changed files with 136 additions and 105 deletions.
11 changes: 8 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,18 @@ jobs:
- name: Install Rust
run: rustup update ${{ matrix.rust }} && rustup default ${{ matrix.rust }}
- run: rustup target add wasm32-unknown-unknown
- name: Install WASM Test Tools
uses: taiki-e/install-action@wasm-pack
- name: Install WASM Test Tools and Cargo Hack
uses: taiki-e/install-action@v2
with:
tool: cargo-hack,wasm-pack
- name: Run cargo check
run: cargo check --all --all-features --all-targets
- run: cargo check --all --no-default-features
- name: Run cargo check (without dev-dependencies to catch missing feature flags)
if: startsWith(matrix.rust, 'nightly')
run: cargo check -Z features=dev_dep
- run: rustup target add thumbv7m-none-eabi
- run: cargo hack build --all --target thumbv7m-none-eabi --no-default-features --no-dev-deps
- name: Run cargo check for WASM
run: cargo check --all --all-features --all-targets --target wasm32-unknown-unknown
- name: Test WASM
Expand All @@ -57,7 +62,7 @@ jobs:
matrix:
# When updating this, the reminder to update the minimum supported
# Rust version in Cargo.toml.
rust: ['1.48']
rust: ['1.59']
steps:
- uses: actions/checkout@v3
- name: Install Rust
Expand Down
14 changes: 7 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ name = "async-lock"
version = "2.7.0"
authors = ["Stjepan Glavina <[email protected]>"]
edition = "2018"
rust-version = "1.48"
rust-version = "1.59"
description = "Async synchronization primitives"
license = "Apache-2.0 OR MIT"
repository = "https://github.com/smol-rs/async-lock"
Expand All @@ -15,10 +15,14 @@ categories = ["asynchronous", "concurrency"]
exclude = ["/.*"]

[dependencies]
event-listener = "2"
event-listener-strategy = { git = "https://github.com/smol-rs/event-listener.git" }
event-listener = { version = "3.0.0", default-features = false }
event-listener-strategy = { version = "0.2.0", default-features = false }
pin-project-lite = "0.2.11"

[features]
default = ["std"]
std = ["event-listener/std", "event-listener-strategy/std"]

[dev-dependencies]
async-channel = "1.5.0"
fastrand = "2.0.0"
Expand All @@ -27,7 +31,3 @@ waker-fn = "1.1.0"

[target.'cfg(any(target_arch = "wasm32", target_arch = "wasm64"))'.dev-dependencies]
wasm-bindgen-test = "0.3"

[patch.crates-io]
async-channel = { git = "https://github.com/smol-rs/async-channel.git", branch = "notgull/evl-3.0" }
event-listener = { git = "https://github.com/smol-rs/event-listener.git" }
10 changes: 5 additions & 5 deletions src/barrier.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use event_listener::{Event, EventListener};

use std::fmt;
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
use core::fmt;
use core::future::Future;
use core::pin::Pin;
use core::task::{Context, Poll};

use crate::futures::Lock;
use crate::Mutex;
Expand Down Expand Up @@ -148,7 +148,7 @@ impl Future for BarrierWait<'_> {
// We are the last one.
state.count = 0;
state.generation_id = state.generation_id.wrapping_add(1);
this.barrier.event.notify(std::usize::MAX);
this.barrier.event.notify(core::usize::MAX);
return Poll::Ready(BarrierWaitResult { is_leader: true });
}
}
Expand Down
27 changes: 26 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//! * [`RwLock`] - a reader-writer lock, allowing any number of readers or a single writer.
//! * [`Semaphore`] - limits the number of concurrent operations.

#![cfg_attr(not(feature = "std"), no_std)]
#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)]
#![doc(
html_favicon_url = "https://raw.githubusercontent.com/smol-rs/smol/master/assets/images/logo_fullsize_transparent.png"
Expand All @@ -15,6 +16,8 @@
html_logo_url = "https://raw.githubusercontent.com/smol-rs/smol/master/assets/images/logo_fullsize_transparent.png"
)]

extern crate alloc;

/// Simple macro to extract the value of `Poll` or return `Pending`.
///
/// TODO: Drop in favor of `core::task::ready`, once MSRV is bumped to 1.64.
Expand All @@ -38,7 +41,7 @@ macro_rules! pin {
let mut $x = $x;
#[allow(unused_mut)]
let mut $x = unsafe {
std::pin::Pin::new_unchecked(&mut $x)
core::pin::Pin::new_unchecked(&mut $x)
};
)*
}
Expand Down Expand Up @@ -69,3 +72,25 @@ pub mod futures {
};
pub use crate::semaphore::{Acquire, AcquireArc};
}

#[cold]
fn abort() -> ! {
// For no_std targets, panicking while panicking is defined as an abort
#[cfg(not(feature = "std"))]
{
struct Bomb;

impl Drop for Bomb {
fn drop(&mut self) {
panic!("Panicking while panicking to abort")
}
}

let _bomb = Bomb;
panic!("Panicking while panicking to abort")
}

// For libstd targets, abort using std::process::abort
#[cfg(feature = "std")]
std::process::abort()
}
40 changes: 20 additions & 20 deletions src/mutex.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
use std::borrow::Borrow;
use std::cell::UnsafeCell;
use std::fmt;
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::pin::Pin;
use std::process;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::task::Poll;

// Note: we cannot use `target_family = "wasm"` here because it requires Rust 1.54.
#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))]
use core::borrow::Borrow;
use core::cell::UnsafeCell;
use core::fmt;
use core::marker::PhantomData;
use core::ops::{Deref, DerefMut};
use core::pin::Pin;
use core::sync::atomic::{AtomicUsize, Ordering};
use core::task::Poll;
use core::usize;

use alloc::sync::Arc;

#[cfg(all(feature = "std", not(target_family = "wasm")))]
use std::time::{Duration, Instant};

use std::usize;

use event_listener::{Event, EventListener};
use event_listener_strategy::{easy_wrapper, EventListenerFuture};

Expand Down Expand Up @@ -263,6 +261,7 @@ impl<T: Default + ?Sized> Default for Mutex<T> {
easy_wrapper! {
/// The future returned by [`Mutex::lock`].
pub struct Lock<'a, T: ?Sized>(LockInner<'a, T> => MutexGuard<'a, T>);
#[cfg(all(feature = "std", not(target_family = "wasm")))]
pub(crate) wait();
}

Expand Down Expand Up @@ -320,6 +319,7 @@ impl<'a, T: ?Sized> EventListenerFuture for LockInner<'a, T> {
easy_wrapper! {
/// The future returned by [`Mutex::lock_arc`].
pub struct LockArc<T: ?Sized>(LockArcInnards<T> => MutexGuardArc<T>);
#[cfg(all(feature = "std", not(target_family = "wasm")))]
pub(crate) wait();
}

Expand Down Expand Up @@ -412,7 +412,7 @@ pin_project_lite::pin_project! {

/// `pin_project_lite` doesn't support `#[cfg]` yet, so we have to do this manually.
struct Start {
#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))]
#[cfg(all(feature = "std", not(target_family = "wasm")))]
start: Option<Instant>,
}

Expand All @@ -430,7 +430,7 @@ impl<T: ?Sized, B: Borrow<Mutex<T>>> AcquireSlow<B, T> {
mutex: Some(mutex),
listener,
start: Start {
#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))]
#[cfg(all(feature = "std", not(target_family = "wasm")))]
start: None,
},
starved: false,
Expand Down Expand Up @@ -464,7 +464,7 @@ impl<T: ?Sized, B: Unpin + Borrow<Mutex<T>>> EventListenerFuture for AcquireSlow
context: &mut S::Context,
) -> Poll<Self::Output> {
let mut this = self.as_mut().project();
#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))]
#[cfg(all(feature = "std", not(target_family = "wasm")))]
let start = *this.start.start.get_or_insert_with(Instant::now);
let mutex = Borrow::<Mutex<T>>::borrow(
this.mutex.as_ref().expect("future polled after completion"),
Expand Down Expand Up @@ -518,7 +518,7 @@ impl<T: ?Sized, B: Unpin + Borrow<Mutex<T>>> EventListenerFuture for AcquireSlow

// If waiting for too long, fall back to a fairer locking strategy that will prevent
// newer lock operations from starving us forever.
#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))]
#[cfg(all(feature = "std", not(target_family = "wasm")))]
if start.elapsed() > Duration::from_micros(500) {
break;
}
Expand All @@ -528,7 +528,7 @@ impl<T: ?Sized, B: Unpin + Borrow<Mutex<T>>> EventListenerFuture for AcquireSlow
// Increment the number of starved lock operations.
if mutex.state.fetch_add(2, Ordering::Release) > usize::MAX / 2 {
// In case of potential overflow, abort.
process::abort();
crate::abort();
}

// Indicate that we are now starving and will use a fairer locking strategy.
Expand Down
33 changes: 20 additions & 13 deletions src/once_cell.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
use std::cell::UnsafeCell;
use std::convert::Infallible;
use std::fmt;
use std::future::Future;
use std::mem::{forget, MaybeUninit};
use std::ptr;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
use core::cell::UnsafeCell;
use core::convert::Infallible;
use core::fmt;
use core::future::Future;
use core::mem::{forget, MaybeUninit};
use core::ptr;
use core::sync::atomic::{AtomicUsize, Ordering};

#[cfg(all(feature = "std", not(target_family = "wasm")))]
use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};

use event_listener::{Event, EventListener};
use event_listener_strategy::{Blocking, NonBlocking, Strategy};
use event_listener_strategy::{NonBlocking, Strategy};

/// The current state of the `OnceCell`.
#[derive(Copy, Clone, PartialEq, Eq)]
Expand Down Expand Up @@ -319,6 +321,7 @@ impl<T> OnceCell<T> {
///
/// assert_eq!(cell.wait_blocking(), &1);
/// ```
#[cfg(all(feature = "std", not(target_family = "wasm")))]
pub fn wait_blocking(&self) -> &T {
// Fast path: see if the value is already initialized.
if let Some(value) = self.get() {
Expand Down Expand Up @@ -423,6 +426,7 @@ impl<T> OnceCell<T> {
///
/// assert_eq!(result.unwrap(), &1);
/// ```
#[cfg(all(feature = "std", not(target_family = "wasm")))]
pub fn get_or_try_init_blocking<E>(
&self,
closure: impl FnOnce() -> Result<T, E>,
Expand All @@ -435,8 +439,8 @@ impl<T> OnceCell<T> {
// Slow path: initialize the value.
// The futures provided should never block, so we can use `now_or_never`.
now_or_never(self.initialize_or_wait(
move || std::future::ready(closure()),
&mut Blocking::default(),
move || core::future::ready(closure()),
&mut event_listener_strategy::Blocking::default(),
))?;
debug_assert!(self.is_initialized());

Expand Down Expand Up @@ -497,6 +501,7 @@ impl<T> OnceCell<T> {
/// assert_eq!(cell.get_or_init_blocking(|| 1), &1);
/// assert_eq!(cell.get_or_init_blocking(|| 2), &1);
/// ```
#[cfg(all(feature = "std", not(target_family = "wasm")))]
pub fn get_or_init_blocking(&self, closure: impl FnOnce() -> T + Unpin) -> &T {
match self.get_or_try_init_blocking(move || {
let result: Result<T, Infallible> = Ok(closure());
Expand Down Expand Up @@ -563,6 +568,7 @@ impl<T> OnceCell<T> {
/// assert_eq!(cell.get(), Some(&1));
/// assert_eq!(cell.set_blocking(2), Err(2));
/// ```
#[cfg(all(feature = "std", not(target_family = "wasm")))]
pub fn set_blocking(&self, value: T) -> Result<&T, T> {
let mut value = Some(value);
self.get_or_init_blocking(|| value.take().unwrap());
Expand Down Expand Up @@ -643,8 +649,8 @@ impl<T> OnceCell<T> {
.store(State::Initialized.into(), Ordering::Release);

// Notify the listeners that the value is initialized.
self.active_initializers.notify_additional(std::usize::MAX);
self.passive_waiters.notify_additional(std::usize::MAX);
self.active_initializers.notify_additional(core::usize::MAX);
self.passive_waiters.notify_additional(core::usize::MAX);

return Ok(());
}
Expand Down Expand Up @@ -758,6 +764,7 @@ impl<T> Drop for OnceCell<T> {
}

/// Either return the result of a future now, or panic.
#[cfg(all(feature = "std", not(target_family = "wasm")))]
fn now_or_never<T>(f: impl Future<Output = T>) -> T {
const NOOP_WAKER: RawWakerVTable = RawWakerVTable::new(clone, wake, wake_by_ref, drop);

Expand Down
13 changes: 7 additions & 6 deletions src/rwlock.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use std::cell::UnsafeCell;
use std::fmt;
use std::mem::{self, ManuallyDrop};
use std::ops::{Deref, DerefMut};
use std::ptr::{self, NonNull};
use std::sync::Arc;
use core::cell::UnsafeCell;
use core::fmt;
use core::mem::{self, ManuallyDrop};
use core::ops::{Deref, DerefMut};
use core::ptr::{self, NonNull};

use alloc::sync::Arc;

pub(crate) mod futures;
mod raw;
Expand Down
13 changes: 7 additions & 6 deletions src/rwlock/futures.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use std::fmt;
use std::future::Future;
use std::mem::ManuallyDrop;
use std::pin::Pin;
use std::sync::Arc;
use std::task::{Context, Poll};
use core::fmt;
use core::future::Future;
use core::mem::ManuallyDrop;
use core::pin::Pin;
use core::task::{Context, Poll};

use alloc::sync::Arc;

use super::raw::{RawRead, RawUpgradableRead, RawUpgrade, RawWrite};
use super::{
Expand Down
Loading

0 comments on commit 3a82590

Please sign in to comment.