From 45543767e6f33525b3af43b80a5bf8da4a66492e Mon Sep 17 00:00:00 2001 From: Dominic Elm Date: Fri, 4 Dec 2020 18:01:46 +0100 Subject: [PATCH] Remove instant dummy and update to latest wasm32 simd intrinsics --- core/src/parking_lot.rs | 51 +++------------------------ core/src/thread_parker/wasm_atomic.rs | 36 ++++++++++++++++--- 2 files changed, 37 insertions(+), 50 deletions(-) diff --git a/core/src/parking_lot.rs b/core/src/parking_lot.rs index 1bd19eb6..519ce9e3 100644 --- a/core/src/parking_lot.rs +++ b/core/src/parking_lot.rs @@ -7,7 +7,6 @@ use crate::thread_parker::{ThreadParker, ThreadParkerT, UnparkHandleT}; use crate::util::UncheckedOptionExt; use crate::word_lock::WordLock; -use cfg_if::cfg_if; use core::{ cell::{Cell, UnsafeCell}, ptr, @@ -17,46 +16,6 @@ use instant::Instant; use smallvec::SmallVec; use std::time::Duration; -cfg_if! { - if #[cfg(all( - target_arch = "wasm32", - target_os = "unknown", - target_vendor = "unknown" - ))] { - use core::ops::Add; - - #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] - struct DummyInstant(Duration); - - impl DummyInstant { - pub fn now() -> DummyInstant { - DummyInstant::zero() - } - - const fn zero() -> DummyInstant { - DummyInstant(Duration::from_secs(0)) - } - } - - impl Add for DummyInstant { - type Output = DummyInstant; - - fn add(self, _rhs: Duration) -> DummyInstant { - DummyInstant::zero() - } - } - - // Use dummy implementation for `Instant` on `wasm32`. The reason for this is - // that `Instant::now()` will always panic because time is currently not implemented - // on wasm32-unknown-unknown. - // See https://github.com/rust-lang/rust/blob/master/src/libstd/sys/wasm/time.rs - type InstantType = DummyInstant; - } else { - // Otherwise use `instant::Instant` - type InstantType = Instant; - } -} - static NUM_THREADS: AtomicUsize = AtomicUsize::new(0); /// Holds the pointer to the currently active `HashTable`. @@ -88,7 +47,7 @@ impl HashTable { let new_size = (num_threads * LOAD_FACTOR).next_power_of_two(); let hash_bits = 0usize.leading_zeros() - new_size.leading_zeros() - 1; - let now = InstantType::now(); + let now = Instant::now(); let mut entries = Vec::with_capacity(new_size); for i in 0..new_size { // We must ensure the seed is not zero @@ -118,7 +77,7 @@ struct Bucket { impl Bucket { #[inline] - pub fn new(timeout: InstantType, seed: u32) -> Self { + pub fn new(timeout: Instant, seed: u32) -> Self { Self { mutex: WordLock::new(), queue_head: Cell::new(ptr::null()), @@ -130,7 +89,7 @@ impl Bucket { struct FairTimeout { // Next time at which point be_fair should be set - timeout: InstantType, + timeout: Instant, // the PRNG state for calculating the next timeout seed: u32, @@ -138,14 +97,14 @@ struct FairTimeout { impl FairTimeout { #[inline] - fn new(timeout: InstantType, seed: u32) -> FairTimeout { + fn new(timeout: Instant, seed: u32) -> FairTimeout { FairTimeout { timeout, seed } } // Determine whether we should force a fair unlock, and update the timeout #[inline] fn should_timeout(&mut self) -> bool { - let now = InstantType::now(); + let now = Instant::now(); if now > self.timeout { // Time between 0 and 1ms. let nanos = self.gen_u32() % 1_000_000; diff --git a/core/src/thread_parker/wasm_atomic.rs b/core/src/thread_parker/wasm_atomic.rs index e482c6b0..2128e93c 100644 --- a/core/src/thread_parker/wasm_atomic.rs +++ b/core/src/thread_parker/wasm_atomic.rs @@ -5,13 +5,41 @@ // 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::{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 { + 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 { + 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, @@ -45,7 +73,7 @@ impl super::ThreadParkerT for ThreadParker { #[inline] unsafe fn park(&self) { while self.parked.load(Ordering::Acquire) == PARKED { - let r = unsafe { wasm32::i32_atomic_wait(self.ptr(), PARKED, -1) }; + let r = wasm32::memory_atomic_wait32(self.ptr(), PARKED, -1); // we should have either woken up (0) or got a not-equal due to a // race (1). We should never time out (2) debug_assert!(r == 0 || r == 1); @@ -55,9 +83,9 @@ 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) = timeout.checked_duration_since(Instant::now()) { + if let Some(left) = checked_duration_since_now(timeout) { let nanos_left = i64::try_from(left.as_nanos()).unwrap_or(i64::max_value()); - let r = unsafe { wasm32::i32_atomic_wait(self.ptr(), PARKED, nanos_left) }; + let r = wasm32::memory_atomic_wait32(self.ptr(), PARKED, nanos_left); debug_assert!(r == 0 || r == 1 || r == 2); } else { return false; @@ -86,7 +114,7 @@ pub struct UnparkHandle(*mut i32); impl super::UnparkHandleT for UnparkHandle { #[inline] unsafe fn unpark(self) { - let num_notified = unsafe { wasm32::atomic_notify(self.0 as *mut i32, 1) }; + let num_notified = wasm32::memory_atomic_notify(self.0 as *mut i32, 1); debug_assert!(num_notified == 0 || num_notified == 1); } }