Skip to content

Commit dd5285c

Browse files
authored
Support multi-threaded Wasm (#3236)
Replace `atomic_refcell` with `parking_lot` on wasm32. `parking_lot` has had problems running on wasm32 before (#1401) but it works these days. If we have problems again we can always switch to `std::sync::Mutex`. Closes #3102
1 parent 08fb447 commit dd5285c

File tree

3 files changed

+19
-98
lines changed

3 files changed

+19
-98
lines changed

Cargo.lock

Lines changed: 0 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/epaint/Cargo.toml

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ ahash = { version = "0.8.1", default-features = false, features = [
7979
"std",
8080
] }
8181
nohash-hasher = "0.2"
82+
parking_lot = "0.12" # Using parking_lot over std::sync::Mutex gives 50% speedups in some real-world scenarios.
8283

8384
#! ### Optional dependencies
8485
bytemuck = { version = "1.7.2", optional = true, features = ["derive"] }
@@ -94,11 +95,6 @@ serde = { version = "1", optional = true, features = ["derive", "rc"] }
9495
# native:
9596
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
9697
backtrace = { version = "0.3", optional = true }
97-
parking_lot = "0.12" # Using parking_lot over std::sync::Mutex gives 50% speedups in some real-world scenarios.
98-
99-
# web:
100-
[target.'cfg(target_arch = "wasm32")'.dependencies]
101-
atomic_refcell = "0.1" # Used instead of parking_lot on on wasm. See https://github.com/emilk/egui/issues/1401
10298

10399

104100
[dev-dependencies]

crates/epaint/src/mutex.rs

Lines changed: 18 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1-
//! Helper module that wraps some Mutex types with different implementations.
1+
//! Helper module that adds extra checks when the `deadlock_detection` feature is turned on.
22
33
// ----------------------------------------------------------------------------
44

5-
#[cfg(not(target_arch = "wasm32"))]
6-
#[cfg(not(debug_assertions))]
5+
#[cfg(not(feature = "deadlock_detection"))]
76
mod mutex_impl {
87
/// Provides interior mutability.
98
///
10-
/// Uses `parking_lot` crate on native targets, and `atomic_refcell` on `wasm32` targets.
9+
/// This is a thin wrapper around [`parking_lot::Mutex`], except if
10+
/// the feature `deadlock_detection` is turned enabled, in which case
11+
/// extra checks are added to detect deadlocks.
1112
#[derive(Default)]
1213
pub struct Mutex<T>(parking_lot::Mutex<T>);
1314

@@ -27,12 +28,13 @@ mod mutex_impl {
2728
}
2829
}
2930

30-
#[cfg(not(target_arch = "wasm32"))]
31-
#[cfg(debug_assertions)]
31+
#[cfg(feature = "deadlock_detection")]
3232
mod mutex_impl {
3333
/// Provides interior mutability.
3434
///
35-
/// Uses `parking_lot` crate on native targets, and `atomic_refcell` on `wasm32` targets.
35+
/// This is a thin wrapper around [`parking_lot::Mutex`], except if
36+
/// the feature `deadlock_detection` is turned enabled, in which case
37+
/// extra checks are added to detect deadlocks.
3638
#[derive(Default)]
3739
pub struct Mutex<T>(parking_lot::Mutex<T>);
3840

@@ -115,7 +117,8 @@ mod mutex_impl {
115117
}
116118
}
117119

118-
#[cfg(not(target_arch = "wasm32"))]
120+
// ----------------------------------------------------------------------------
121+
119122
#[cfg(not(feature = "deadlock_detection"))]
120123
mod rw_lock_impl {
121124
/// The lock you get from [`RwLock::read`].
@@ -126,7 +129,9 @@ mod rw_lock_impl {
126129

127130
/// Provides interior mutability.
128131
///
129-
/// Uses `parking_lot` crate on native targets, and `atomic_refcell` on `wasm32` targets.
132+
/// This is a thin wrapper around [`parking_lot::RwLock`], except if
133+
/// the feature `deadlock_detection` is turned enabled, in which case
134+
/// extra checks are added to detect deadlocks.
130135
#[derive(Default)]
131136
pub struct RwLock<T>(parking_lot::RwLock<T>);
132137

@@ -148,7 +153,6 @@ mod rw_lock_impl {
148153
}
149154
}
150155

151-
#[cfg(not(target_arch = "wasm32"))]
152156
#[cfg(feature = "deadlock_detection")]
153157
mod rw_lock_impl {
154158
use std::{
@@ -246,7 +250,9 @@ mod rw_lock_impl {
246250

247251
/// Provides interior mutability.
248252
///
249-
/// Uses `parking_lot` crate on native targets, and `atomic_refcell` on `wasm32` targets.
253+
/// This is a thin wrapper around [`parking_lot::RwLock`], except if
254+
/// the feature `deadlock_detection` is turned enabled, in which case
255+
/// extra checks are added to detect deadlocks.
250256
#[derive(Default)]
251257
pub struct RwLock<T> {
252258
lock: parking_lot::RwLock<T>,
@@ -352,80 +358,6 @@ mod rw_lock_impl {
352358

353359
// ----------------------------------------------------------------------------
354360

355-
#[cfg(target_arch = "wasm32")]
356-
mod mutex_impl {
357-
// `atomic_refcell` will panic if multiple threads try to access the same value
358-
359-
/// Provides interior mutability.
360-
///
361-
/// Uses `parking_lot` crate on native targets, and `atomic_refcell` on `wasm32` targets.
362-
#[derive(Default)]
363-
pub struct Mutex<T>(atomic_refcell::AtomicRefCell<T>);
364-
365-
/// The lock you get from [`Mutex`].
366-
pub use atomic_refcell::AtomicRefMut as MutexGuard;
367-
368-
impl<T> Mutex<T> {
369-
#[inline(always)]
370-
pub fn new(val: T) -> Self {
371-
Self(atomic_refcell::AtomicRefCell::new(val))
372-
}
373-
374-
/// Panics if already locked.
375-
#[inline(always)]
376-
pub fn lock(&self) -> MutexGuard<'_, T> {
377-
self.0.borrow_mut()
378-
}
379-
380-
#[inline(always)]
381-
pub fn into_inner(self) -> T {
382-
self.0.into_inner()
383-
}
384-
}
385-
}
386-
387-
#[cfg(target_arch = "wasm32")]
388-
mod rw_lock_impl {
389-
// `atomic_refcell` will panic if multiple threads try to access the same value
390-
391-
/// The lock you get from [`RwLock::read`].
392-
pub use atomic_refcell::AtomicRef as RwLockReadGuard;
393-
394-
/// The lock you get from [`RwLock::write`].
395-
pub use atomic_refcell::AtomicRefMut as RwLockWriteGuard;
396-
397-
/// Provides interior mutability.
398-
///
399-
/// Uses `parking_lot` crate on native targets, and `atomic_refcell` on `wasm32` targets.
400-
#[derive(Default)]
401-
pub struct RwLock<T>(atomic_refcell::AtomicRefCell<T>);
402-
403-
impl<T> RwLock<T> {
404-
#[inline(always)]
405-
pub fn new(val: T) -> Self {
406-
Self(atomic_refcell::AtomicRefCell::new(val))
407-
}
408-
409-
#[inline(always)]
410-
pub fn read(&self) -> RwLockReadGuard<'_, T> {
411-
self.0.borrow()
412-
}
413-
414-
/// Panics if already locked.
415-
#[inline(always)]
416-
pub fn write(&self) -> RwLockWriteGuard<'_, T> {
417-
self.0.borrow_mut()
418-
}
419-
420-
#[inline(always)]
421-
pub fn into_inner(self) -> T {
422-
self.0.into_inner()
423-
}
424-
}
425-
}
426-
427-
// ----------------------------------------------------------------------------
428-
429361
pub use mutex_impl::{Mutex, MutexGuard};
430362
pub use rw_lock_impl::{RwLock, RwLockReadGuard, RwLockWriteGuard};
431363

@@ -469,7 +401,7 @@ mod tests {
469401
let other_thread = {
470402
let one = Arc::clone(&one);
471403
std::thread::spawn(move || {
472-
let _ = one.lock();
404+
let _lock = one.lock();
473405
})
474406
};
475407
std::thread::sleep(Duration::from_millis(200));

0 commit comments

Comments
 (0)