Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 18 additions & 10 deletions onnxruntime/core/providers/webgpu/webgpu_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -922,7 +922,7 @@
}
}

std::unordered_map<int32_t, WebGpuContextFactory::WebGpuContextInfo> WebGpuContextFactory::contexts_;
std::unordered_map<int32_t, WebGpuContextFactory::WebGpuContextInfo>* WebGpuContextFactory::contexts_ = nullptr;
std::mutex WebGpuContextFactory::mutex_;
std::once_flag WebGpuContextFactory::init_default_flag_;
wgpu::Instance WebGpuContextFactory::default_instance_;
Expand Down Expand Up @@ -958,6 +958,11 @@

std::lock_guard<std::mutex> lock(mutex_);

// Lazy-allocate the contexts map on first use (heap-allocated to avoid static destruction crash).
if (contexts_ == nullptr) {
contexts_ = new std::unordered_map<int32_t, WebGpuContextInfo>();
}

Check warning on line 965 in onnxruntime/core/providers/webgpu/webgpu_context.cc

View workflow job for this annotation

GitHub Actions / Optional Lint C++

[cpplint] reported by reviewdog 🐶 Add #include <unordered_map> for unordered_map<> [build/include_what_you_use] [4] Raw Output: onnxruntime/core/providers/webgpu/webgpu_context.cc:965: Add #include <unordered_map> for unordered_map<> [build/include_what_you_use] [4]
if (default_instance_ == nullptr) {
// Create wgpu::Instance
wgpu::InstanceFeatureName required_instance_features[] = {wgpu::InstanceFeatureName::TimedWaitAny};
Expand All @@ -981,15 +986,15 @@
"WebGPU EP custom context (contextId>0) must have custom WebGPU instance and device.");
}

auto it = contexts_.find(context_id);
if (it == contexts_.end()) {
auto it = contexts_->find(context_id);
if (it == contexts_->end()) {
GSL_SUPPRESS(r.11)
auto context = std::unique_ptr<WebGpuContext>(new WebGpuContext(instance,
device,
config.validation_mode,
config.preserve_device,
config.max_storage_buffer_binding_size));
it = contexts_.emplace(context_id, WebGpuContextFactory::WebGpuContextInfo{std::move(context), 0}).first;
it = contexts_->emplace(context_id, WebGpuContextFactory::WebGpuContextInfo{std::move(context), 0}).first;
} else if (context_id != 0) {
ORT_ENFORCE(it->second.context->instance_.Get() == instance &&
it->second.context->device_.Get() == device,
Expand All @@ -1006,26 +1011,29 @@
WebGpuContext& WebGpuContextFactory::GetContext(int context_id) {
std::lock_guard<std::mutex> lock(mutex_);

auto it = contexts_.find(context_id);
ORT_ENFORCE(it != contexts_.end(), "WebGPU EP context ID ", context_id, " is not found.");
ORT_ENFORCE(contexts_ != nullptr, "WebGPU contexts have not been initialized or have been cleaned up.");
auto it = contexts_->find(context_id);
ORT_ENFORCE(it != contexts_->end(), "WebGPU EP context ID ", context_id, " is not found.");

return *it->second.context;
}

void WebGpuContextFactory::ReleaseContext(int context_id) {
std::lock_guard<std::mutex> lock(mutex_);

auto it = contexts_.find(context_id);
ORT_ENFORCE(it != contexts_.end(), "WebGPU EP context ID ", context_id, " is not found.");
ORT_ENFORCE(contexts_ != nullptr, "WebGPU contexts have not been initialized or have been cleaned up.");
auto it = contexts_->find(context_id);
ORT_ENFORCE(it != contexts_->end(), "WebGPU EP context ID ", context_id, " is not found.");

if (--it->second.ref_count == 0 && !it->second.context->preserve_device_) {
contexts_.erase(it);
contexts_->erase(it);
}
}

void WebGpuContextFactory::Cleanup() {
std::lock_guard<std::mutex> lock(mutex_);
contexts_.clear();
delete contexts_;
contexts_ = nullptr;
default_instance_ = nullptr;
}

Expand Down
9 changes: 8 additions & 1 deletion onnxruntime/core/providers/webgpu/webgpu_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,14 @@
private:
WebGpuContextFactory() {}

static std::unordered_map<int32_t, WebGpuContextInfo> contexts_;
// Use pointers to heap-allocated objects so that their destructors do NOT run
// during static destruction at process exit. This avoids crashes when dependent
// DLLs (e.g. dxcompiler.dll) have already been unloaded by the OS.
// Cleanup() explicitly deletes them during normal unload. In the shared-library
// build this is reached via ReleaseEpFactory, and in the WebGPU static-lib build
// it is reached from OrtEnv::~OrtEnv via CleanupWebGpuContexts().
// On abnormal/process termination they simply leak, which is safe.
Comment thread
fs-eire marked this conversation as resolved.
static std::unordered_map<int32_t, WebGpuContextInfo>* contexts_;

Check warning on line 157 in onnxruntime/core/providers/webgpu/webgpu_context.h

View workflow job for this annotation

GitHub Actions / Optional Lint C++

[cpplint] reported by reviewdog 🐶 Add #include <unordered_map> for unordered_map<> [build/include_what_you_use] [4] Raw Output: onnxruntime/core/providers/webgpu/webgpu_context.h:157: Add #include <unordered_map> for unordered_map<> [build/include_what_you_use] [4]
static std::mutex mutex_;
static std::once_flag init_default_flag_;
static wgpu::Instance default_instance_;
Expand Down
Loading