Skip to content

Commit 85ff31d

Browse files
authored
Merge pull request #141 from storycraft/fix/dashmap-deadlock
fix: replace to sccmap
1 parent 8326b14 commit 85ff31d

File tree

7 files changed

+65
-38
lines changed

7 files changed

+65
-38
lines changed

Cargo.lock

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

crates/client/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ asdf-overlay-event = { workspace = true, features = ["bincode"] }
1919
tokio = { workspace = true, features = ["macros", "time", "net"] }
2020

2121
bincode = "2.0.1"
22-
dashmap = "6.1.0"
22+
scc = "3.3.3"
2323
ntapi = "0.4.1"
2424
anyhow = "1.0.97"
2525
scopeguard = "1.2.0"

crates/client/src/client.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ use asdf_overlay_common::{
1111
};
1212
use asdf_overlay_event::OverlayEvent;
1313
use bincode::Decode;
14-
use dashmap::DashMap;
1514
use tokio::{
1615
io::{AsyncReadExt, AsyncWriteExt, WriteHalf, split},
1716
net::windows::named_pipe::NamedPipeClient,
@@ -24,7 +23,7 @@ pub struct IpcClientConn {
2423
next_id: u32,
2524
tx: WriteHalf<NamedPipeClient>,
2625
buf: Vec<u8>,
27-
map: Weak<DashMap<u32, oneshot::Sender<Vec<u8>>>>,
26+
map: Weak<scc::HashMap<u32, oneshot::Sender<Vec<u8>>>>,
2827
read_task: JoinHandle<anyhow::Result<()>>,
2928
}
3029

@@ -33,7 +32,7 @@ impl IpcClientConn {
3332
pub async fn new(client: NamedPipeClient) -> anyhow::Result<(Self, IpcClientEventStream)> {
3433
let (mut rx, tx) = split(client);
3534

36-
let map = Arc::new(DashMap::<u32, oneshot::Sender<Vec<u8>>>::new());
35+
let map = Arc::new(scc::HashMap::<u32, oneshot::Sender<Vec<u8>>>::new());
3736
let (event_tx, event_rx) = mpsc::unbounded_channel();
3837

3938
let read_task = tokio::spawn({
@@ -51,7 +50,7 @@ impl IpcClientConn {
5150

5251
match packet {
5352
ServerToClientPacket::Response(res) => {
54-
if let Some((_, sender)) = map.remove(&res.id) {
53+
if let Some((_, sender)) = map.remove_async(&res.id).await {
5554
_ = sender.send(res.data);
5655
}
5756
}
@@ -129,7 +128,7 @@ impl IpcClientConn {
129128
.await?;
130129

131130
let (tx, rx) = oneshot::channel();
132-
map.insert(id, tx);
131+
map.upsert_async(id, tx).await;
133132
self.tx.write_all(&self.buf).await?;
134133

135134
self.tx.flush().await?;

packages/core/native/Cargo.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,14 @@ asdf-overlay-client = { workspace = true }
1717
tokio = { workspace = true, features = ["full"] }
1818

1919
neon = "1"
20-
parking_lot = "0.12.3"
2120
anyhow = "1.0.97"
2221
once_cell = "1.21.3"
23-
dashmap = "6.1.0"
2422
rustc-hash = "2.1.1"
2523
mimalloc = "0.1.46"
2624
bytemuck = "1.22.0"
2725
futures = "0.3.31"
2826
num = "0.4.3"
27+
scc = "3.3.3"
2928

3029
[dependencies.windows]
3130
workspace = true

packages/core/native/src/lib.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,11 @@ mod overlay;
33
mod surface;
44
mod util;
55

6-
use dashmap::DashMap;
76
use mimalloc::MiMalloc;
87
use neon::prelude::*;
98
use rustc_hash::FxBuildHasher;
109

11-
type FxDashMap<K, V> = DashMap<K, V, FxBuildHasher>;
10+
type FxSccMap<K, V> = scc::HashMap<K, V, FxBuildHasher>;
1211

1312
#[global_allocator]
1413
static GLOBAL: MiMalloc = MiMalloc;

packages/core/native/src/overlay.rs

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
use core::{
2+
pin::pin,
23
sync::atomic::{AtomicU32, Ordering},
4+
task::Poll,
35
time::Duration,
46
};
57
use std::{path::PathBuf, sync::LazyLock};
68

79
use super::conv::{deserialize_percent_length, emit_event};
810
use super::util::with_rt;
9-
use crate::{conv::deserialize_handle_update, util::runtime};
11+
use crate::{FxSccMap, conv::deserialize_handle_update, util::runtime};
1012
use anyhow::Context as AnyhowContext;
1113
use asdf_overlay_client::{
1214
OverlayDll,
@@ -18,12 +20,9 @@ use asdf_overlay_client::{
1820
event::OverlayEvent,
1921
inject,
2022
};
21-
use dashmap::DashMap;
23+
use futures::future::poll_fn;
2224
use neon::prelude::*;
2325
use num::FromPrimitive;
24-
use rustc_hash::FxBuildHasher;
25-
26-
type FxDashMap<K, V> = DashMap<K, V, FxBuildHasher>;
2726

2827
struct Overlay {
2928
ipc: IpcClientConn,
@@ -32,7 +31,7 @@ struct Overlay {
3231

3332
struct OverlayStore {
3433
next_id: AtomicU32,
35-
overlay_map: FxDashMap<u32, Overlay>,
34+
overlay_map: FxSccMap<u32, Overlay>,
3635
}
3736

3837
impl OverlayStore {
@@ -55,7 +54,9 @@ impl OverlayStore {
5554
.context("cannot inject to the process")?;
5655

5756
let id = self.next_id.fetch_add(1, Ordering::AcqRel);
58-
self.overlay_map.insert(id, Overlay { ipc, event });
57+
self.overlay_map
58+
.upsert_async(id, Overlay { ipc, event })
59+
.await;
5960

6061
Ok(id)
6162
}
@@ -65,20 +66,35 @@ impl OverlayStore {
6566
id: u32,
6667
f: impl AsyncFnOnce(&mut Overlay) -> R,
6768
) -> anyhow::Result<R> {
68-
let mut overlay = self.overlay_map.get_mut(&id).context("invalid id")?;
69+
let mut overlay = self
70+
.overlay_map
71+
.get_async(&id)
72+
.await
73+
.context("invalid id")?;
6974
Ok(f(&mut *overlay).await)
7075
}
7176

77+
async fn next_event(&self, id: u32) -> anyhow::Result<Option<OverlayEvent>> {
78+
poll_fn(|cx| {
79+
let Some(mut overlay) = self.overlay_map.get_sync(&id) else {
80+
return Poll::Ready(Err(anyhow::anyhow!("invalid id")));
81+
};
82+
83+
pin!(overlay.event.recv()).poll(cx).map(Ok)
84+
})
85+
.await
86+
}
87+
7288
fn destroy(&self, id: u32) -> anyhow::Result<()> {
73-
self.overlay_map.remove(&id).context("invalid id")?;
89+
self.overlay_map.remove_sync(&id).context("invalid id")?;
7490

7591
Ok(())
7692
}
7793
}
7894

7995
static STORE: LazyLock<OverlayStore> = LazyLock::new(|| OverlayStore {
8096
next_id: AtomicU32::new(0),
81-
overlay_map: FxDashMap::default(),
97+
overlay_map: FxSccMap::default(),
8298
});
8399

84100
pub async fn try_with_ipc<T>(
@@ -214,15 +230,8 @@ fn overlay_call_next_event(mut cx: FunctionContext) -> JsResult<JsPromise> {
214230

215231
let (deferred, promise) = cx.promise();
216232
rt.spawn(async move {
217-
let res = async move {
218-
let event: Option<OverlayEvent> = STORE
219-
.with_mut(id, async move |overlay| overlay.event.recv().await)
220-
.await?;
221-
Ok::<_, anyhow::Error>(event)
222-
}
223-
.await;
224-
225-
deferred.settle_with(&channel, move |mut cx| match res {
233+
let event = STORE.next_event(id).await;
234+
deferred.settle_with(&channel, move |mut cx| match event {
226235
Ok(Some(event)) => {
227236
let emitter = emitter.into_inner(&mut cx);
228237
let emit = emit.into_inner(&mut cx);

packages/core/native/src/surface.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@ use neon::{
1111
use once_cell::sync::Lazy;
1212

1313
use crate::{
14-
FxDashMap,
14+
FxSccMap,
1515
conv::{deserialize_copy_rect, deserialize_gpu_luid, serialize_handle_update},
1616
util::create_adapter_by_luid,
1717
};
1818

1919
struct SurfaceStore {
2020
next_id: AtomicU32,
21-
overlay_map: FxDashMap<u32, OverlaySurface>,
21+
overlay_map: FxSccMap<u32, OverlaySurface>,
2222
}
2323

2424
impl SurfaceStore {
@@ -27,7 +27,7 @@ impl SurfaceStore {
2727
let surface = OverlaySurface::new(adapter.as_ref())?;
2828

2929
let id = self.next_id.fetch_add(1, Ordering::AcqRel);
30-
self.overlay_map.insert(id, surface);
30+
self.overlay_map.upsert_sync(id, surface);
3131
Ok(id)
3232
}
3333

@@ -38,19 +38,19 @@ impl SurfaceStore {
3838
) -> anyhow::Result<R> {
3939
let mut surface = self
4040
.overlay_map
41-
.get_mut(&id)
41+
.get_sync(&id)
4242
.context("Invalid surface id.")?;
4343
f(&mut surface)
4444
}
4545

4646
fn destroy(&self, id: u32) -> bool {
47-
self.overlay_map.remove(&id).is_some()
47+
self.overlay_map.remove_sync(&id).is_some()
4848
}
4949
}
5050

5151
static STORE: Lazy<SurfaceStore> = Lazy::new(|| SurfaceStore {
5252
next_id: AtomicU32::new(0),
53-
overlay_map: FxDashMap::default(),
53+
overlay_map: FxSccMap::default(),
5454
});
5555

5656
fn surface_create(mut cx: FunctionContext) -> JsResult<JsNumber> {

0 commit comments

Comments
 (0)