zed/crates/remote_server/Cargo.toml
Anthony Eid c16d19c94d
gpui: Fix deadlock in performance profiler and reenable it (#61584)
### Summary

PR #58942 disabled the performance profiler within Zed because there was
a race condition that caused Zed to hang forever due to a deadlock
involving the foreground thread. This PR fixes the deadlock and
re-enables the performance profiler.

The deadlock happened because `ThreadTimings::drop()` locks
`GLOBAL_THREAD_TIMINGS`, and that drop could run in places where
`GLOBAL_THREAD_TIMINGS` was already locked: the collection paths
(`get_all_timings`, `take_all_stats`, `set_trace_enabled(false)`) held
the global lock while upgrading and then dropping per-thread
`Arc<GuardedTaskTimings>` handles. If a worker thread exited in that
window (e.g. GCD reclaiming an idle thread), the collector inherited the
last strong reference, and dropping it ran `ThreadTimings::drop` ->
`GLOBAL_THREAD_TIMINGS.lock()` reentrantly on the same thread. The
spinlock is not reentrant, so the thread spun forever while holding the
lock, hanging every other thread that touched the profiler.

The fix: hold `GLOBAL_THREAD_TIMINGS` only long enough to upgrade the
`Weak` handles (`upgraded_thread_timings()`), and release it before any
per-thread buffer is locked, copied, or dropped. A last-reference drop
now always runs with the global lock free. As a side benefit, the
up-to-16MiB per-thread buffer copies no longer happen under the global
lock.

### Diagram

```mermaid
sequenceDiagram
    participant C as Collector thread (get_all_timings)
    participant G as GLOBAL_THREAD_TIMINGS (spin::Mutex)
    participant T as Worker thread (exiting)

    Note over T: holds the only strong Arc<br/>in its THREAD_TIMINGS TLS
    C->>G: lock() — guard held for entire collection
    C->>C: Weak::upgrade() (strong: 1 → 2)
    T->>T: thread exits, TLS destructor drops its Arc (strong: 2 → 1)
    C->>C: temp Arc dropped at end of iteration (strong: 1 → 0)
    C->>C: ThreadTimings::drop() runs on collector thread
    C->>G: lock() again — already held by this thread
    Note over C,G: spin lock is not reentrant → spins forever,<br/>every other profiler user spins behind it

    Note over C,T: Fix: upgrade all Weaks under the lock, release it,<br/>then lock/copy/drop per-thread handles — the reentrant<br/>drop can now only ever run with the global lock free
```

Release Notes:

- Fixed a deadlock in the performance profiler and re-enabled it (`zed:
open performance profiler`)
2026-07-24 15:34:17 +00:00

119 lines
3.4 KiB
TOML

[package]
name = "remote_server"
description = "Daemon used for remote editing"
edition.workspace = true
version = "0.1.0"
publish.workspace = true
license = "GPL-3.0-or-later"
[lints]
workspace = true
[lib]
path = "src/server.rs"
doctest = false
[[bin]]
name = "remote_server"
[features]
default = []
debug-embed = ["dep:rust-embed"]
test-support = ["fs/test-support"]
[dependencies]
acp_thread.workspace = true
anyhow.workspace = true
async-channel.workspace = true
askpass.workspace = true
clap.workspace = true
client.workspace = true
collections.workspace = true
crashes.workspace = true
dap_adapters.workspace = true
debug_adapter_extension.workspace = true
env_logger.workspace = true
extension.workspace = true
extension_host.workspace = true
fs.workspace = true
futures.workspace = true
git.workspace = true
git_hosting_providers.workspace = true
gpui = { workspace = true, features = ["profiler"] }
gpui_platform.workspace = true
gpui_tokio.workspace = true
http_client.workspace = true
image.workspace = true
json_schema_store.workspace = true
language.workspace = true
language_extension.workspace = true
languages.workspace = true
log.workspace = true
lsp.workspace = true
net.workspace = true
node_runtime.workspace = true
paths.workspace = true
project.workspace = true
proto.workspace = true
release_channel.workspace = true
remote.workspace = true
reqwest_client.workspace = true
rpc.workspace = true
rust-embed = { workspace = true, optional = true, features = ["debug-embed"] }
semver.workspace = true
serde.workspace = true
serde_json.workspace = true
settings.workspace = true
shellexpand.workspace = true
smol.workspace = true
sysinfo.workspace = true
task.workspace = true
telemetry.workspace = true
util.workspace = true
watch.workspace = true
worktree.workspace = true
thiserror.workspace = true
rayon.workspace = true
uuid = { workspace = true, features = ["v4"] }
[target.'cfg(not(windows))'.dependencies]
crash-handler.workspace = true
fork.workspace = true
libc.workspace = true
minidumper.workspace = true
[target.'cfg(windows)'.dependencies]
windows.workspace = true
gpui = { workspace = true, features = ["windows-manifest"] }
[dev-dependencies]
action_log.workspace = true
agent = { workspace = true, features = ["test-support"] }
agent-client-protocol.workspace = true
client = { workspace = true, features = ["test-support"] }
clock = { workspace = true, features = ["test-support"] }
editor = { workspace = true, features = ["test-support"] }
fs = { workspace = true, features = ["test-support"] }
gpui = { workspace = true, features = ["test-support"] }
http_client = { workspace = true, features = ["test-support"] }
language = { workspace = true, features = ["test-support"] }
language_model = { workspace = true, features = ["test-support"] }
lsp = { workspace = true, features = ["test-support"] }
node_runtime = { workspace = true, features = ["test-support"] }
pretty_assertions.workspace = true
project = { workspace = true, features = ["test-support"] }
remote = { workspace = true, features = ["test-support"] }
serde_json.workspace = true
tempfile.workspace = true
theme = { workspace = true, features = ["test-support"] }
theme_settings.workspace = true
unindent.workspace = true
workspace = { workspace = true, features = ["test-support"] }
zlog.workspace = true
[build-dependencies]
cargo_toml.workspace = true
toml.workspace = true
[package.metadata.cargo-machete]
ignored = ["rust-embed", "paths"]