Skip to content

Commit b37ca36

Browse files
committed
fix potential hang in capi initialization
dpctl_capi singleton intiailization could cause deadlocks with updated order manager
1 parent 75c691c commit b37ca36

1 file changed

Lines changed: 28 additions & 2 deletions

File tree

dpctl/apis/include/dpctl4pybind11.hpp

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,11 @@
2626
#pragma once
2727

2828
#include "dpctl_capi.h"
29+
#include <atomic>
2930
#include <complex>
3031
#include <cstddef> // for std::size_t for C++ linkage
3132
#include <memory>
33+
#include <mutex>
3234
#include <pybind11/pybind11.h>
3335
#include <stddef.h> // for size_t for C linkage
3436
#include <stdexcept>
@@ -142,8 +144,32 @@ class dpctl_capi
142144

143145
static auto &get()
144146
{
145-
static dpctl_capi api{};
146-
return api;
147+
static std::atomic<dpctl_capi *> global_capi{nullptr};
148+
dpctl_capi *capi_ptr = global_capi.load(std::memory_order_acquire);
149+
150+
// fast path
151+
if (capi_ptr) {
152+
return *capi_ptr;
153+
}
154+
155+
// double-checked lock
156+
// can't use std::call_once here as it still may deadlock
157+
static std::mutex init_mtx;
158+
159+
py::gil_scoped_release release;
160+
std::lock_guard<std::mutex> lock(init_mtx);
161+
162+
capi_ptr = global_capi.load(std::memory_order_relaxed);
163+
164+
if (!capi_ptr) {
165+
py::gil_scoped_acquire acquire;
166+
167+
capi_ptr = new dpctl_capi();
168+
169+
global_capi.store(capi_ptr, std::memory_order_release);
170+
}
171+
172+
return *capi_ptr;
147173
}
148174

149175
py::object default_sycl_queue_pyobj() { return *default_sycl_queue_; }

0 commit comments

Comments
 (0)