Skip to content

Commit 732f37d

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

1 file changed

Lines changed: 29 additions & 2 deletions

File tree

dpctl/apis/include/dpctl4pybind11.hpp

Lines changed: 29 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,33 @@ 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+
static std::mutex init_mtx;
156+
157+
// release gil while holding lock
158+
py::gil_scoped_release release;
159+
std::lock_guard<std::mutex> lock(init_mtx);
160+
161+
// double check after acquiring lock
162+
capi_ptr = global_capi.load(std::memory_order_relaxed);
163+
164+
if (!capi_ptr) {
165+
// acquire gil to safely call into Python C API
166+
py::gil_scoped_acquire acquire;
167+
168+
capi_ptr = new dpctl_capi();
169+
170+
global_capi.store(capi_ptr, std::memory_order_release);
171+
}
172+
173+
return *capi_ptr;
147174
}
148175

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

0 commit comments

Comments
 (0)