Skip to content
Closed
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
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ edition = "2018"
[dependencies]
parking_lot_core = { path = "core", version = "0.6.2" }
lock_api = { path = "lock_api", version = "0.3.1" }
cfg-if = "0.1.10"

[dev-dependencies]
rand = "0.7"
Expand Down
2 changes: 1 addition & 1 deletion core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ categories = ["concurrency"]
edition = "2018"

[dependencies]
cfg-if = "0.1.5"
cfg-if = "0.1.10"
smallvec = "0.6"
petgraph = { version = "0.4.5", optional = true }
thread-id = { version = "3.2.0", optional = true }
Expand Down
19 changes: 16 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,25 @@
#![warn(rust_2018_idioms)]
#![cfg_attr(feature = "nightly", feature(asm))]

cfg_if::cfg_if! {
if #[cfg(target_arch = "wasm32")] {
Copy link
Contributor

Choose a reason for hiding this comment

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

This wont work correctly when using the multi threading wasm extension.

Copy link
Author

Choose a reason for hiding this comment

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

This is true, but neither would the original code without being explicitly designed for the new atomic primitives that aren’t even available on nightly, right? If it needs new code to work I’m not fussed about the exact way it happens to be incorrect now.

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe add

#[cfg(all(target_arch = "wasm32", target_feature = "atomics"))]
compile_error!("parking_lot doesnt yet support multi threaded wasm");

Also atomic.notify and atomic.wait are exposed on nightly: https://doc.rust-lang.org/stable/core/arch/wasm32/index.html Normal atomics are accessable using the Atomic* types.

Copy link
Author

Choose a reason for hiding this comment

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

I was referring mainly to having to compile libstd from source. Regardless, this is probably a good idea.

mod wasm;
mod raw_mutex {
pub use crate::wasm::raw_mutex::*;
}
mod raw_rwlock {
pub use crate::wasm::raw_rwlock::*;
}
} else {
mod raw_mutex;
mod raw_rwlock;
mod elision;
}
}

mod condvar;
mod elision;
mod mutex;
mod once;
mod raw_mutex;
mod raw_rwlock;
mod remutex;
mod rwlock;
mod util;
Expand Down
2 changes: 2 additions & 0 deletions src/wasm/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod raw_mutex;
pub mod raw_rwlock;
128 changes: 128 additions & 0 deletions src/wasm/raw_mutex.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// Eventually, when access to WASM i32_atomic_wait is stable, this should look more like
// https://github.com/rust-lang/rust/blob/f51752774bbbe48d2aabe53c86e9e91ed3a73a5d/src/libstd/sys/wasm/mutex_atomics.rs#L81-L160
//
// For now, we essentially do what
// https://github.com/rust-lang/rust/blob/253fc0ed742c235fa34c5d78814fa7b8a5e5e055/src/libstd/sys/wasm/mutex.rs does.

use std::cell::UnsafeCell;

const LOCKED_BIT: u8 = 1;
const PARKED_BIT: u8 = 2;

// UnparkToken used to indicate that that the target thread should attempt to
// lock the mutex again as soon as it is unparked.
pub(crate) const TOKEN_NORMAL: UnparkToken = UnparkToken(0);

// UnparkToken used to indicate that the mutex is being handed off to the target
// thread directly without unlocking it.
pub(crate) const TOKEN_HANDOFF: UnparkToken = UnparkToken(1);

/// Raw mutex type backed by the parking lot.
pub struct RawMutex {
state: UnsafeCell<u8>,
}

unsafe impl Send for RawMutex {}
unsafe impl Sync for RawMutex {} // no threads on wasm

use crate::deadlock;
use core::time::Duration;
use lock_api::{GuardSend, RawMutex as RawMutexTrait, RawMutexFair, RawMutexTimed};
use parking_lot_core::{self, UnparkToken};
use std::time::Instant;

unsafe impl RawMutexTrait for RawMutex {
const INIT: RawMutex = RawMutex {
state: UnsafeCell::new(0u8),
};

type GuardMarker = GuardSend;

#[inline]
fn lock(&self) {
unsafe {
let state = self.state.get();
assert!(
(*state & LOCKED_BIT) == 0,
"cannot recursively acquire Mutex"
);
*state = *state | LOCKED_BIT;
deadlock::acquire_resource(self as *const _ as usize);
};
}

#[inline]
fn try_lock(&self) -> bool {
let state = self.state.get();
unsafe {
if *state & LOCKED_BIT > 0 {
false
} else {
*state |= *state;
deadlock::acquire_resource(self as *const _ as usize);
true
}
}
}

#[inline]
fn unlock(&self) {
unsafe {
deadlock::release_resource(self as *const _ as usize);
let state = self.state.get();
*state &= !LOCKED_BIT;
};
}
}

unsafe impl RawMutexTimed for RawMutex {
type Duration = Duration;
type Instant = Instant;

#[inline]
fn try_lock_until(&self, _timeout: Instant) -> bool {
self.try_lock()
}

#[inline]
fn try_lock_for(&self, _timeout: Duration) -> bool {
self.try_lock()
}
}

unsafe impl RawMutexFair for RawMutex {
#[inline]
fn unlock_fair(&self) {
self.unlock()
}

#[inline]
fn bump(&self) {}
}

impl RawMutex {
// Used by Condvar when requeuing threads to us, must be called while
// holding the queue lock.
// false if unlocked
#[inline]
pub(crate) fn mark_parked_if_locked(&self) -> bool {
unsafe {
let state = self.state.get();
if *state & LOCKED_BIT > 0 {
false
} else {
*state &= PARKED_BIT;
true
}
}
}

// Used by Condvar when requeuing threads to us, must be called while
// holding the queue lock.
#[inline]
pub(crate) fn mark_parked(&self) {
unsafe {
*self.state.get() &= !PARKED_BIT;
}
}
}
Loading