Skip to content

Commit

Permalink
Disable eventual fairness on wasm32-unknown-unknown
Browse files Browse the repository at this point in the history
std::time::Instant panics on this target and the external instant crate
adds undesirable external dependencies to the wasm module.
  • Loading branch information
Amanieu committed Oct 31, 2021
1 parent aecb031 commit f9e45fb
Show file tree
Hide file tree
Showing 21 changed files with 125 additions and 124 deletions.
3 changes: 0 additions & 3 deletions Cargo.toml
Expand Up @@ -13,7 +13,6 @@ edition = "2018"
[dependencies]
parking_lot_core = { path = "core", version = "0.8.4" }
lock_api = { path = "lock_api", version = "0.4.5" }
instant = "0.1.9"

[dev-dependencies]
rand = "0.8.3"
Expand All @@ -28,8 +27,6 @@ owning_ref = ["lock_api/owning_ref"]
nightly = ["parking_lot_core/nightly", "lock_api/nightly"]
deadlock_detection = ["parking_lot_core/deadlock_detection"]
serde = ["lock_api/serde"]
stdweb = ["instant/stdweb"]
wasm-bindgen = ["instant/wasm-bindgen"]
send_guard = []

[workspace]
Expand Down
1 change: 0 additions & 1 deletion core/Cargo.toml
Expand Up @@ -15,7 +15,6 @@ smallvec = "1.6.1"
petgraph = { version = "0.5.1", optional = true }
thread-id = { version = "4.0.0", optional = true }
backtrace = { version = "0.3.60", optional = true }
instant = "0.1.9"

[target.'cfg(unix)'.dependencies]
libc = "0.2.95"
Expand Down
42 changes: 33 additions & 9 deletions core/src/parking_lot.rs
Expand Up @@ -12,10 +12,27 @@ use core::{
ptr,
sync::atomic::{AtomicPtr, AtomicUsize, Ordering},
};
use instant::Instant;
use smallvec::SmallVec;
use std::time::Duration;

// Don't use Instant on wasm32-unknown-unknown, it just panics.
cfg_if::cfg_if! {
if #[cfg(all(
target_arch = "wasm32",
target_os = "unknown",
target_vendor = "unknown"
))] {
struct Instant;
impl Instant {
fn now() -> Instant {
Instant
}
}
} else {
use std::time::Instant;
}
}

static NUM_THREADS: AtomicUsize = AtomicUsize::new(0);

/// Holds the pointer to the currently active `HashTable`.
Expand Down Expand Up @@ -104,14 +121,21 @@ impl FairTimeout {
// Determine whether we should force a fair unlock, and update the timeout
#[inline]
fn should_timeout(&mut self) -> bool {
let now = Instant::now();
if now > self.timeout {
// Time between 0 and 1ms.
let nanos = self.gen_u32() % 1_000_000;
self.timeout = now + Duration::new(0, nanos);
true
} else {
false
#[cfg(not(all(
target_arch = "wasm32",
target_os = "unknown",
target_vendor = "unknown"
)))]
{
let now = Instant::now();
if now > self.timeout {
// Time between 0 and 1ms.
let nanos = self.gen_u32() % 1_000_000;
self.timeout = now + Duration::new(0, nanos);
true
} else {
false
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion core/src/thread_parker/generic.rs
Expand Up @@ -9,8 +9,8 @@
//! parking facilities available.

use core::sync::atomic::{spin_loop_hint, AtomicBool, Ordering};
use instant::Instant;
use std::thread;
use std::time::Instant;

// Helper type for putting a thread to sleep until some other thread wakes it up
pub struct ThreadParker {
Expand Down
2 changes: 1 addition & 1 deletion core/src/thread_parker/linux.rs
Expand Up @@ -9,9 +9,9 @@ use core::{
ptr,
sync::atomic::{AtomicI32, Ordering},
};
use instant::Instant;
use libc;
use std::thread;
use std::time::Instant;

// x32 Linux uses a non-standard type for tv_nsec in timespec.
// See https://sourceware.org/bugzilla/show_bug.cgi?id=16437
Expand Down
2 changes: 1 addition & 1 deletion core/src/thread_parker/mod.rs
@@ -1,5 +1,5 @@
use cfg_if::cfg_if;
use instant::Instant;
use std::time::Instant;

/// Trait for the platform thread parker implementation.
///
Expand Down
2 changes: 1 addition & 1 deletion core/src/thread_parker/redox.rs
Expand Up @@ -9,8 +9,8 @@ use core::{
ptr,
sync::atomic::{AtomicI32, Ordering},
};
use instant::Instant;
use std::thread;
use std::time::Instant;
use syscall::{
call::futex,
data::TimeSpec,
Expand Down
2 changes: 1 addition & 1 deletion core/src/thread_parker/sgx.rs
Expand Up @@ -6,7 +6,7 @@
// copied, modified, or distributed except according to those terms.

use core::sync::atomic::{AtomicBool, Ordering};
use instant::Instant;
use std::time::Instant;
use std::{
io,
os::fortanix_sgx::{
Expand Down
2 changes: 1 addition & 1 deletion core/src/thread_parker/unix.rs
Expand Up @@ -11,8 +11,8 @@ use core::{
cell::{Cell, UnsafeCell},
mem::MaybeUninit,
};
use instant::Instant;
use libc;
use std::time::Instant;
use std::{thread, time::Duration};

// x32 Linux uses a non-standard type for tv_nsec in timespec.
Expand Down
2 changes: 1 addition & 1 deletion core/src/thread_parker/wasm.rs
Expand Up @@ -8,8 +8,8 @@
//! The wasm platform can't park when atomic support is not available.
//! So this ThreadParker just panics on any attempt to park.

use instant::Instant;
use std::thread;
use std::time::Instant;

pub struct ThreadParker(());

Expand Down
32 changes: 2 additions & 30 deletions core/src/thread_parker/wasm_atomic.rs
Expand Up @@ -5,41 +5,13 @@
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

use cfg_if::cfg_if;
use core::{
arch::wasm32,
sync::atomic::{AtomicI32, Ordering},
};
use instant::Instant;
use std::time::Duration;
use std::time::{Duration, Instant};
use std::{convert::TryFrom, thread};

cfg_if! {
if #[cfg(all(
target_arch = "wasm32",
target_os = "unknown",
target_vendor = "unknown"
))] {
// This function serves as a polyfill for `Instant::checked_duration_since`, which is
// currently not implemented for wasm32-unknown-unknown.
// TODO: Remove this shim once it
fn checked_duration_since_now(other: Instant) -> Option<Duration> {
let now = Instant::now();

if other < now {
None
} else {
Some(other.duration_since(now))
}
}
} else {
// If we are not targeting wasm32, we can use the native `checked_duration_since`.
fn checked_duration_since_now(timeout: Instant) -> Option<Duration> {
timeout.checked_duration_since(Instant::now())
}
}
}

// Helper type for putting a thread to sleep until some other thread wakes it up
pub struct ThreadParker {
parked: AtomicI32,
Expand Down Expand Up @@ -83,7 +55,7 @@ impl super::ThreadParkerT for ThreadParker {
#[inline]
unsafe fn park_until(&self, timeout: Instant) -> bool {
while self.parked.load(Ordering::Acquire) == PARKED {
if let Some(left) = checked_duration_since_now(timeout) {
if let Some(left) = timeout.checked_duration_since(Instant::now()) {
let nanos_left = i64::try_from(left.as_nanos()).unwrap_or(i64::max_value());
let r = wasm32::memory_atomic_wait32(self.ptr(), PARKED, nanos_left);
debug_assert!(r == 0 || r == 1 || r == 2);
Expand Down
2 changes: 1 addition & 1 deletion core/src/thread_parker/windows/keyed_event.rs
Expand Up @@ -9,8 +9,8 @@ use core::{
mem::{self, MaybeUninit},
ptr,
};
use instant::Instant;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::time::Instant;
use winapi::{
shared::{
minwindef::{TRUE, ULONG},
Expand Down
2 changes: 1 addition & 1 deletion core/src/thread_parker/windows/mod.rs
Expand Up @@ -9,7 +9,7 @@ use core::{
ptr,
sync::atomic::{AtomicPtr, AtomicUsize, Ordering},
};
use instant::Instant;
use std::time::Instant;

mod keyed_event;
mod waitaddress;
Expand Down
2 changes: 1 addition & 1 deletion core/src/thread_parker/windows/waitaddress.rs
Expand Up @@ -9,7 +9,7 @@ use core::{
mem,
sync::atomic::{AtomicUsize, Ordering},
};
use instant::Instant;
use std::time::Instant;
use winapi::{
shared::{
basetsd::SIZE_T,
Expand Down
6 changes: 3 additions & 3 deletions lock_api/src/mutex.rs
Expand Up @@ -663,8 +663,8 @@ impl<'a, R: RawMutex + 'a, T: fmt::Display + ?Sized + 'a> fmt::Display for Mutex
unsafe impl<'a, R: RawMutex + 'a, T: ?Sized + 'a> StableAddress for MutexGuard<'a, R, T> {}

/// An RAII mutex guard returned by the `Arc` locking operations on `Mutex`.
///
/// This is similar to the `MutexGuard` struct, except instead of using a reference to unlock the `Mutex` it
///
/// This is similar to the `MutexGuard` struct, except instead of using a reference to unlock the `Mutex` it
/// uses an `Arc<Mutex>`. This has several advantages, most notably that it has an `'static` lifetime.
#[cfg(feature = "arc_lock")]
#[must_use = "if unused the Mutex will immediately unlock"]
Expand Down Expand Up @@ -713,7 +713,7 @@ impl<R: RawMutexFair, T: ?Sized> ArcMutexGuard<R, T> {

// SAFETY: make sure the Arc gets it reference decremented
let mut s = ManuallyDrop::new(s);
unsafe { ptr::drop_in_place(&mut s.mutex) };
unsafe { ptr::drop_in_place(&mut s.mutex) };
}

/// Temporarily unlocks the mutex to execute the given function.
Expand Down
39 changes: 19 additions & 20 deletions lock_api/src/remutex.rs
Expand Up @@ -401,7 +401,7 @@ impl<R: RawMutex, G: GetThreadId, T: ?Sized> ReentrantMutex<R, G, T> {
}

/// # Safety
///
///
/// The lock must be held before calling this method.
#[cfg(feature = "arc_lock")]
#[inline]
Expand All @@ -413,7 +413,7 @@ impl<R: RawMutex, G: GetThreadId, T: ?Sized> ReentrantMutex<R, G, T> {
}

/// Acquires a reentrant mutex through an `Arc`.
///
///
/// This method is similar to the `lock` method; however, it requires the `ReentrantMutex` to be inside of an
/// `Arc` and the resulting mutex guard has no lifetime requirements.
#[cfg(feature = "arc_lock")]
Expand All @@ -425,7 +425,7 @@ impl<R: RawMutex, G: GetThreadId, T: ?Sized> ReentrantMutex<R, G, T> {
}

/// Attempts to acquire a reentrant mutex through an `Arc`.
///
///
/// This method is similar to the `try_lock` method; however, it requires the `ReentrantMutex` to be inside
/// of an `Arc` and the resulting mutex guard has no lifetime requirements.
#[cfg(feature = "arc_lock")]
Expand Down Expand Up @@ -490,12 +490,15 @@ impl<R: RawMutexTimed, G: GetThreadId, T: ?Sized> ReentrantMutex<R, G, T> {
}

/// Attempts to acquire this lock until a timeout is reached, through an `Arc`.
///
///
/// This method is similar to the `try_lock_for` method; however, it requires the `ReentrantMutex` to be
/// inside of an `Arc` and the resulting mutex guard has no lifetime requirements.
#[cfg(feature = "arc_lock")]
#[inline]
pub fn try_lock_arc_for(self: &Arc<Self>, timeout: R::Duration) -> Option<ArcReentrantMutexGuard<R, G, T>> {
pub fn try_lock_arc_for(
self: &Arc<Self>,
timeout: R::Duration,
) -> Option<ArcReentrantMutexGuard<R, G, T>> {
if self.raw.try_lock_for(timeout) {
// SAFETY: locking guarantee is upheld
Some(unsafe { self.guard_arc() })
Expand All @@ -505,12 +508,15 @@ impl<R: RawMutexTimed, G: GetThreadId, T: ?Sized> ReentrantMutex<R, G, T> {
}

/// Attempts to acquire this lock until a timeout is reached, through an `Arc`.
///
///
/// This method is similar to the `try_lock_until` method; however, it requires the `ReentrantMutex` to be
/// inside of an `Arc` and the resulting mutex guard has no lifetime requirements.
#[cfg(feature = "arc_lock")]
#[inline]
pub fn try_lock_arc_until(self: &Arc<Self>, timeout: R::Instant) -> Option<ArcReentrantMutexGuard<R, G, T>> {
pub fn try_lock_arc_until(
self: &Arc<Self>,
timeout: R::Instant,
) -> Option<ArcReentrantMutexGuard<R, G, T>> {
if self.raw.try_lock_until(timeout) {
// SAFETY: locking guarantee is upheld
Some(unsafe { self.guard_arc() })
Expand Down Expand Up @@ -736,7 +742,6 @@ impl<'a, R: RawMutexFair + 'a, G: GetThreadId + 'a, T: ?Sized + 'a>
s.remutex.raw.bump();
}
}

}

impl<'a, R: RawMutex + 'a, G: GetThreadId + 'a, T: ?Sized + 'a> Deref
Expand Down Expand Up @@ -783,9 +788,9 @@ unsafe impl<'a, R: RawMutex + 'a, G: GetThreadId + 'a, T: ?Sized + 'a> StableAdd
{
}

/// An RAII mutex guard returned by the `Arc` locking operations on `ReentrantMutex`.
///
/// This is similar to the `ReentrantMutexGuard` struct, except instead of using a reference to unlock the
/// An RAII mutex guard returned by the `Arc` locking operations on `ReentrantMutex`.
///
/// This is similar to the `ReentrantMutexGuard` struct, except instead of using a reference to unlock the
/// `Mutex` it uses an `Arc<ReentrantMutex>`. This has several advantages, most notably that it has an `'static`
/// lifetime.
#[cfg(feature = "arc_lock")]
Expand Down Expand Up @@ -821,9 +826,7 @@ impl<R: RawMutex, G: GetThreadId, T: ?Sized> ArcReentrantMutexGuard<R, G, T> {
}

#[cfg(feature = "arc_lock")]
impl<R: RawMutexFair, G: GetThreadId, T: ?Sized>
ArcReentrantMutexGuard<R, G, T>
{
impl<R: RawMutexFair, G: GetThreadId, T: ?Sized> ArcReentrantMutexGuard<R, G, T> {
/// Unlocks the mutex using a fair unlock protocol.
///
/// This is functionally identical to the `unlock_fair` method on [`ReentrantMutexGuard`].
Expand Down Expand Up @@ -868,9 +871,7 @@ impl<R: RawMutexFair, G: GetThreadId, T: ?Sized>
}

#[cfg(feature = "arc_lock")]
impl<R: RawMutex, G: GetThreadId, T: ?Sized> Deref
for ArcReentrantMutexGuard<R, G, T>
{
impl<R: RawMutex, G: GetThreadId, T: ?Sized> Deref for ArcReentrantMutexGuard<R, G, T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
Expand All @@ -879,9 +880,7 @@ impl<R: RawMutex, G: GetThreadId, T: ?Sized> Deref
}

#[cfg(feature = "arc_lock")]
impl<R: RawMutex, G: GetThreadId, T: ?Sized> Drop
for ArcReentrantMutexGuard<R, G, T>
{
impl<R: RawMutex, G: GetThreadId, T: ?Sized> Drop for ArcReentrantMutexGuard<R, G, T> {
#[inline]
fn drop(&mut self) {
// Safety: A ReentrantMutexGuard always holds the lock.
Expand Down

0 comments on commit f9e45fb

Please sign in to comment.