mirror of
https://github.com/zed-industries/zed.git
synced 2026-08-01 19:24:38 +00:00
### 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`) |
||
|---|---|---|
| .. | ||
| src | ||
| build.rs | ||
| Cargo.toml | ||
| LICENSE-GPL | ||