Skip to content

Commit df6f452

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

1 file changed

Lines changed: 30 additions & 2 deletions

File tree

dpctl/apis/include/dpctl4pybind11.hpp

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

2828
#include "dpctl_capi.h"
29+
30+
#include <atomic>
2931
#include <complex>
3032
#include <cstddef> // for std::size_t for C++ linkage
3133
#include <memory>
34+
#include <mutex>
3235
#include <pybind11/pybind11.h>
3336
#include <stddef.h> // for size_t for C linkage
3437
#include <stdexcept>
@@ -142,8 +145,33 @@ class dpctl_capi
142145

143146
static auto &get()
144147
{
145-
static dpctl_capi api{};
146-
return api;
148+
static std::atomic<dpctl_capi *> global_capi{nullptr};
149+
dpctl_capi *capi_ptr = global_capi.load(std::memory_order_acquire);
150+
151+
// fast path
152+
if (capi_ptr) {
153+
return *capi_ptr;
154+
}
155+
156+
static std::mutex init_mtx;
157+
158+
// release gil while holding lock
159+
py::gil_scoped_release release;
160+
std::lock_guard<std::mutex> lock(init_mtx);
161+
162+
// double check after acquiring lock
163+
capi_ptr = global_capi.load(std::memory_order_relaxed);
164+
165+
if (!capi_ptr) {
166+
// acquire gil to safely call into Python C API
167+
py::gil_scoped_acquire acquire;
168+
169+
capi_ptr = new dpctl_capi();
170+
171+
global_capi.store(capi_ptr, std::memory_order_release);
172+
}
173+
174+
return *capi_ptr;
147175
}
148176

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

0 commit comments

Comments
 (0)