onnxruntime
ef73996a - [WebGPU] Fix OrtReleaseEnv self-deadlock after failed adapter request on Linux (#29591)

Commit
5 days ago
[WebGPU] Fix OrtReleaseEnv self-deadlock after failed adapter request on Linux (#29591) On Linux with the WebGPU EP, if `SessionOptionsAppendExecutionProvider` is called when no Vulkan adapter is available, a subsequent `OrtReleaseEnv` on the same thread hangs forever in a futex wait. ### Root causes **1. C++ exceptions thrown inside Dawn `WaitAny` callbacks (primary)** `ORT_ENFORCE` was called directly inside the `RequestAdapter`/`RequestDevice` callback lambdas. Dawn's `WaitAny` does not release its internal `EventManager` mutex on exception, so throwing through it leaves that mutex permanently locked. The deadlock fires later when `Cleanup()` calls `wgpuInstanceRelease` → `EventManager::ShutDown()` → tries to re-acquire the same mutex on the same thread. **2. Zombie `WebGpuContext` left in the factory map (secondary)** When `Initialize()` threw, the `WebGpuContext` entry remained in `contexts_` with `ref_count=1` and no owner — a resource leak that would also re-trigger the deadlock path at `Cleanup()`. ### Changes (`webgpu_context.cc`) - **Adapter callback**: replace the throwing lambda with a non-throwing one that writes into a local `RequestAdapterResult` struct; `ORT_ENFORCE` is moved to *after* `WaitAny` returns: ```cpp // Before — throws inside Dawn's callback dispatch: [](wgpu::RequestAdapterStatus status, wgpu::Adapter adapter, wgpu::StringView message, wgpu::Adapter* ptr) { ORT_ENFORCE(status == wgpu::RequestAdapterStatus::Success, ...); *ptr = std::move(adapter); }, &adapter // After — captures result, throws outside Dawn: [](wgpu::RequestAdapterStatus status, wgpu::Adapter adapter, wgpu::StringView message, RequestAdapterResult* result) { result->status = status; if (status == wgpu::RequestAdapterStatus::Success) result->adapter = std::move(adapter); else result->message = std::string{message}; }, &adapter_result // ORT_ENFORCE(adapter_result.status == ...) called here, after WaitAny ``` - **Device callback**: same pattern applied to `RequestDevice`. - **`CreateContext` cleanup**: wrap `Initialize()` in a `try/catch`; on failure decrement `ref_count` and erase the entry from `contexts_` if it reaches zero. ### Motivation and Context Fixes the hang reported when registering the WebGPU EP with no usable Vulkan adapter and then calling `OrtReleaseEnv`. The process would park on a futex with `__owner` set to its own TID — a non-recursive mutex locked twice on the same thread — and never exit. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Author
Parents
Loading