Skip to content

Commit

Permalink
Disable use of std::thread::sleep except on Unix and Windows
Browse files Browse the repository at this point in the history
  • Loading branch information
white-axe committed Jul 27, 2024
1 parent e428500 commit 01b5395
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 28 deletions.
3 changes: 1 addition & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- `spin-plain` feature that switches the locking implementation to a plain spinlock without `std::thread::sleep`

### Removed

### Changed

- `WeakSender` is now `Clone`
- `spin` feature no longer uses `std::thread::sleep` for locking except on Unix-like operating systems and Windows

### Fixed

Expand Down
2 changes: 0 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ exclude = [
[features]
# Use a spinlock internally (may be faster on some platforms)
spin = []
# Use a spinlock internally without `std::thread::sleep` (for platforms that don't support blocking)
spin-plain = []
select = []
async = ["futures-sink", "futures-core"]
eventual-fairness = ["select", "nanorand"]
Expand Down
50 changes: 26 additions & 24 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ use std::{
fmt,
};

#[cfg(any(feature = "spin", feature = "spin-plain"))]
#[cfg(feature = "spin")]
use spin1::{Mutex as Spinlock, MutexGuard as SpinlockGuard};
use crate::signal::{Signal, SyncSignal};

Expand Down Expand Up @@ -257,13 +257,13 @@ enum TryRecvTimeoutError {
}

// TODO: Investigate some sort of invalidation flag for timeouts
#[cfg(any(feature = "spin", feature = "spin-plain"))]
#[cfg(feature = "spin")]
struct Hook<T, S: ?Sized>(Option<Spinlock<Option<T>>>, S);

#[cfg(not(any(feature = "spin", feature = "spin-plain")))]
#[cfg(not(feature = "spin"))]
struct Hook<T, S: ?Sized>(Option<Mutex<Option<T>>>, S);

#[cfg(any(feature = "spin", feature = "spin-plain"))]
#[cfg(feature = "spin")]
impl<T, S: ?Sized + Signal> Hook<T, S> {
pub fn slot(msg: Option<T>, signal: S) -> Arc<Self>
where
Expand All @@ -277,7 +277,7 @@ impl<T, S: ?Sized + Signal> Hook<T, S> {
}
}

#[cfg(not(any(feature = "spin", feature = "spin-plain")))]
#[cfg(not(feature = "spin"))]
impl<T, S: ?Sized + Signal> Hook<T, S> {
pub fn slot(msg: Option<T>, signal: S) -> Arc<Self>
where
Expand Down Expand Up @@ -392,41 +392,43 @@ impl<T> Hook<T, SyncSignal> {
}
}

#[cfg(all(feature = "spin", not(feature = "spin-plain")))]
#[cfg(feature = "spin")]
#[inline]
fn wait_lock<T>(lock: &Spinlock<T>) -> SpinlockGuard<T> {
let mut i = 4;
loop {
for _ in 0..10 {
if let Some(guard) = lock.try_lock() {
return guard;
// Some targets don't support `thread::sleep` (e.g. the `wasm32-unknown-unknown` target when
// running in the main thread of a web browser) so we only use it on targets where we know it
// will work
#[cfg(any(target_family = "unix", target_family = "windows"))]
{
let mut i = 4;
loop {
for _ in 0..10 {
if let Some(guard) = lock.try_lock() {
return guard;
}
thread::yield_now();
}
thread::yield_now();
// Sleep for at most ~1 ms
thread::sleep(Duration::from_nanos(1 << i.min(20)));
i += 1;
}
// Sleep for at most ~1 ms
thread::sleep(Duration::from_nanos(1 << i.min(20)));
i += 1;
}
}

#[cfg(feature = "spin-plain")]
#[inline]
fn wait_lock<T>(lock: &Spinlock<T>) -> SpinlockGuard<T> {
#[cfg(not(any(target_family = "unix", target_family = "windows")))]
lock.lock()
}

#[cfg(not(any(feature = "spin", feature = "spin-plain")))]
#[cfg(not(feature = "spin"))]
#[inline]
fn wait_lock<'a, T>(lock: &'a Mutex<T>) -> MutexGuard<'a, T> {
lock.lock().unwrap()
}

#[cfg(not(any(feature = "spin", feature = "spin-plain")))]
#[cfg(not(feature = "spin"))]
use std::sync::{Mutex, MutexGuard};

#[cfg(any(feature = "spin", feature = "spin-plain"))]
#[cfg(feature = "spin")]
type ChanLock<T> = Spinlock<T>;
#[cfg(not(any(feature = "spin", feature = "spin-plain")))]
#[cfg(not(feature = "spin"))]
type ChanLock<T> = Mutex<T>;


Expand Down

0 comments on commit 01b5395

Please sign in to comment.